r4419 - in trunk/varnish-cache: bin/varnishd bin/varnishtest/tests lib/libvcl

phk at projects.linpro.no phk at projects.linpro.no
Wed Dec 16 16:46:44 CET 2009


Author: phk
Date: 2009-12-16 16:46:44 +0100 (Wed, 16 Dec 2009)
New Revision: 4419

Added:
   trunk/varnish-cache/bin/varnishtest/tests/v00026.vtc
Modified:
   trunk/varnish-cache/bin/varnishd/cache_backend.h
   trunk/varnish-cache/bin/varnishd/cache_backend_cfg.c
   trunk/varnish-cache/bin/varnishd/cache_dir_random.c
   trunk/varnish-cache/lib/libvcl/vcc_backend.c
Log:
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.





Modified: trunk/varnish-cache/bin/varnishd/cache_backend.h
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_backend.h	2009-12-16 14:31:27 UTC (rev 4418)
+++ trunk/varnish-cache/bin/varnishd/cache_backend.h	2009-12-16 15:46:44 UTC (rev 4419)
@@ -155,6 +155,8 @@
 
 
 /* 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;

Modified: trunk/varnish-cache/bin/varnishd/cache_backend_cfg.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_backend_cfg.c	2009-12-16 14:31:27 UTC (rev 4418)
+++ trunk/varnish-cache/bin/varnishd/cache_backend_cfg.c	2009-12-16 15:46:44 UTC (rev 4419)
@@ -269,6 +269,8 @@
 	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"))

Modified: trunk/varnish-cache/bin/varnishd/cache_dir_random.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_dir_random.c	2009-12-16 14:31:27 UTC (rev 4418)
+++ trunk/varnish-cache/bin/varnishd/cache_dir_random.c	2009-12-16 15:46:44 UTC (rev 4419)
@@ -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 @@
 #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 @@
 	int i, k;
 	struct vdi_random *vs;
 	double r, s1;
+	unsigned u;
 	struct vbe_conn *vbe;
 	struct director *d2;
 
@@ -77,6 +91,30 @@
 	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 @@
 		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 @@
 {
 	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 @@
 	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 @@
 	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);
+}

Added: trunk/varnish-cache/bin/varnishtest/tests/v00026.vtc
===================================================================
--- trunk/varnish-cache/bin/varnishtest/tests/v00026.vtc	                        (rev 0)
+++ trunk/varnish-cache/bin/varnishtest/tests/v00026.vtc	2009-12-16 15:46:44 UTC (rev 4419)
@@ -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

Modified: trunk/varnish-cache/lib/libvcl/vcc_backend.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcc_backend.c	2009-12-16 14:31:27 UTC (rev 4418)
+++ trunk/varnish-cache/lib/libvcl/vcc_backend.c	2009-12-16 15:46:44 UTC (rev 4419)
@@ -776,6 +776,7 @@
 	const char	*name;
 	parsedirector_f	*func;
 } dirlist[] = {
+	{ "hash",		vcc_ParseRandomDirector },
 	{ "random",		vcc_ParseRandomDirector },
 	{ "round-robin",	vcc_ParseRoundRobinDirector },
 	{ NULL,		NULL }



More information about the varnish-commit mailing list