Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Exploit the new and cleaner director interface and add a "hash" director

by sharing most of the code with the "random" director.

The Hash director will use the hash output from vcl_hash{} to pick a
backend from the configured set.

If this backend is unhealthy, it pick another backend, using only the
healthy subset of backends, but as soon as the "canonical" backend becomes
healthy it will revert to using that.

This means that one backend going unhealthy on "rehashes" the requests for
that backend, hashing for healthy backends are not affected.





git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@4419 d4fa192b-c00b-0410-8231-f00ffab90ce4
  • Loading branch information...
commit 59caf963dce03e4c93da850b497775af68f99302 1 parent ed03c78
Poul-Henning Kamp authored
View
8 bin/varnishd/cache_backend.h
@@ -155,6 +155,8 @@ void VBP_Stop(struct backend *b);
/* Init functions for directors */
-void VRT_init_dir_simple(struct cli *, struct director **, int , const void*);
-void VRT_init_dir_random(struct cli *, struct director **, int , const void*);
-void VRT_init_dir_round_robin(struct cli *, struct director **, int , const void*);
+typedef void dir_init_f(struct cli *, struct director **, int , const void*);
+dir_init_f VRT_init_dir_simple;
+dir_init_f VRT_init_dir_hash;
+dir_init_f VRT_init_dir_random;
+dir_init_f VRT_init_dir_round_robin;
View
2  bin/varnishd/cache_backend_cfg.c
@@ -269,6 +269,8 @@ VRT_init_dir(struct cli *cli, struct director **dir, const char *name,
ASSERT_CLI();
if (!strcmp(name, "simple"))
VRT_init_dir_simple(cli, dir, idx, priv);
+ else if (!strcmp(name, "hash"))
+ VRT_init_dir_hash(cli, dir, idx, priv);
else if (!strcmp(name, "random"))
VRT_init_dir_random(cli, dir, idx, priv);
else if (!strcmp(name, "round-robin"))
View
74 bin/varnishd/cache_dir_random.c
@@ -26,6 +26,17 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
+ * This code is shared between the random and hash directors, because they
+ * share the same properties and most of the same selection logic.
+ *
+ * The random director picks a backend on random, according to weight,
+ * from the healty subset of backends.
+ *
+ * The hash director first tries to locate the "canonical" backend from
+ * the full set, according to weight, and if it is healthy selects it.
+ * If the canonical backend is not healthy, we pick a backend according
+ * to weight from the healthy subset. That way only traffic to unhealthy
+ * backends gets redistributed.
*/
#include "config.h"
@@ -59,7 +70,9 @@ struct vdi_random {
#define VDI_RANDOM_MAGIC 0x3771ae23
struct director dir;
+ unsigned use_hash;
unsigned retries;
+ double tot_weight;
struct vdi_random_host *hosts;
unsigned nhosts;
};
@@ -70,6 +83,7 @@ vdi_random_getfd(struct director *d, struct sess *sp)
int i, k;
struct vdi_random *vs;
double r, s1;
+ unsigned u;
struct vbe_conn *vbe;
struct director *d2;
@@ -77,6 +91,30 @@ vdi_random_getfd(struct director *d, struct sess *sp)
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
CAST_OBJ_NOTNULL(vs, d->priv, VDI_RANDOM_MAGIC);
+ /*
+ * If we are hashing, first try to hit our "canonical backend"
+ * If that fails, we fall through, and select a weighted backend
+ * amongst the good set.
+ */
+ if (vs->use_hash) {
+ memcpy(&u, sp->digest, sizeof u);
+ r = u / 4294967296.0;
+ r *= vs->tot_weight;
+ s1 = 0.0;
+ for (i = 0; i < vs->nhosts; i++) {
+ s1 += vs->hosts[i].weight;
+ if (r >= s1)
+ continue;
+ d2 = vs->hosts[i].backend;
+ if (!VBE_Healthy(d2, sp))
+ break;
+ vbe = VBE_GetFd(d2, sp);
+ if (vbe != NULL)
+ return (vbe);
+ break;
+ }
+ }
+
for (k = 0; k < vs->retries; ) {
/* Sum up the weights of healty backends */
@@ -91,8 +129,13 @@ vdi_random_getfd(struct director *d, struct sess *sp)
if (s1 == 0.0)
return (NULL);
- /* Pick a random threshold in that interval */
- r = random() / 2147483648.0; /* 2^31 */
+ if (vs->use_hash) {
+ memcpy(&u, sp->digest, sizeof u);
+ r = u / 4294967296.0;
+ } else {
+ /* Pick a random threshold in that interval */
+ r = random() / 2147483648.0; /* 2^31 */
+ }
assert(r >= 0.0 && r < 1.0);
r *= s1;
@@ -119,15 +162,13 @@ vdi_random_healthy(struct director *d, const struct sess *sp)
{
struct vdi_random *vs;
int i;
- struct director *d2;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
CAST_OBJ_NOTNULL(vs, d->priv, VDI_RANDOM_MAGIC);
for (i = 0; i < vs->nhosts; i++) {
- d2 = vs->hosts[i].backend;
- if (VBE_Healthy(d2, sp))
+ if (VBE_Healthy(vs->hosts[i].backend, sp))
return 1;
}
return 0;
@@ -148,9 +189,9 @@ vdi_random_fini(struct director *d)
FREE_OBJ(vs);
}
-void
-VRT_init_dir_random(struct cli *cli, struct director **bp, int idx,
- const void *priv)
+static void
+vrt_init(struct cli *cli, struct director **bp, int idx,
+ const void *priv, int use_hash)
{
const struct vrt_dir_random *t;
struct vdi_random *vs;
@@ -175,17 +216,34 @@ VRT_init_dir_random(struct cli *cli, struct director **bp, int idx,
vs->dir.fini = vdi_random_fini;
vs->dir.healthy = vdi_random_healthy;
+ vs->use_hash = use_hash;
vs->retries = t->retries;
if (vs->retries == 0)
vs->retries = t->nmember;
vh = vs->hosts;
te = t->members;
+ vs->tot_weight = 0.;
for (i = 0; i < t->nmember; i++, vh++, te++) {
assert(te->weight > 0.0);
vh->weight = te->weight;
+ vs->tot_weight += vh->weight;
vh->backend = bp[te->host];
AN(vh->backend);
}
vs->nhosts = t->nmember;
bp[idx] = &vs->dir;
}
+
+void
+VRT_init_dir_random(struct cli *cli, struct director **bp, int idx,
+ const void *priv)
+{
+ vrt_init(cli, bp, idx, priv, 0);
+}
+
+void
+VRT_init_dir_hash(struct cli *cli, struct director **bp, int idx,
+ const void *priv)
+{
+ vrt_init(cli, bp, idx, priv, 1);
+}
View
52 bin/varnishtest/tests/v00026.vtc
@@ -0,0 +1,52 @@
+# $Id$
+
+test "Hash director"
+
+server s1 {
+ rxreq
+ txresp -hdr "Foo: 1" -body "1"
+ rxreq
+ txresp -hdr "Foo: 3" -body "3"
+} -start
+
+server s2 {
+ rxreq
+ txresp -hdr "Foo: 2" -body "2"
+ rxreq
+ txresp -hdr "Foo: 4" -body "4"
+} -start
+
+
+varnish v1 -vcl+backend {
+ director h1 hash {
+ { .backend = s1; .weight = 1; }
+ { .backend = s2; .weight = 1; }
+ }
+
+ sub vcl_recv {
+ set req.backend = h1;
+ pass;
+ }
+
+} -start
+
+
+client c1 {
+ txreq -url /12
+ rxresp
+ expect resp.http.foo == "1"
+
+ txreq -url /1
+ rxresp
+ expect resp.http.foo == "2"
+
+ txreq -url /13
+ rxresp
+ expect resp.http.foo == "3"
+
+ txreq -url /15
+ rxresp
+ expect resp.http.foo == "4"
+
+
+} -run
View
1  lib/libvcl/vcc_backend.c
@@ -776,6 +776,7 @@ static const struct dirlist {
const char *name;
parsedirector_f *func;
} dirlist[] = {
+ { "hash", vcc_ParseRandomDirector },
{ "random", vcc_ParseRandomDirector },
{ "round-robin", vcc_ParseRoundRobinDirector },
{ NULL, NULL }
Please sign in to comment.
Something went wrong with that request. Please try again.