[PATCH] add a least-connection director

Federico G. Schwindt fgsch at lodoss.net
Sat Jan 21 11:14:27 CET 2012


Hi,

The diff below adds a least-connection director based on the random director.
Documentation and tests included.
Comments? OKs?

f.-

 bin/varnishd/cache/cache_backend.h     |    1 +
 bin/varnishd/cache/cache_backend_cfg.c |    2 +
 bin/varnishd/cache/cache_dir_random.c  |   52 ++++++++++++++++++--
 bin/varnishtest/tests/v00037.vtc       |   86 ++++++++++++++++++++++++++++++++
 doc/sphinx/reference/vcl.rst           |   11 ++++
 lib/libvcl/vcc_backend.c               |    1 +
 7 files changed, 150 insertions(+), 5 deletions(-)

diff --git a/bin/varnishd/cache/cache_backend.h b/bin/varnishd/cache/cache_backend.h
index ad71169..6105ed3 100644
--- a/bin/varnishd/cache/cache_backend.h
+++ b/bin/varnishd/cache/cache_backend.h
@@ -190,3 +190,4 @@ dir_init_f VRT_init_dir_random;
 dir_init_f VRT_init_dir_round_robin;
 dir_init_f VRT_init_dir_fallback;
 dir_init_f VRT_init_dir_client;
+dir_init_f VRT_init_dir_least_connection;
diff --git a/bin/varnishd/cache/cache_backend_cfg.c b/bin/varnishd/cache/cache_backend_cfg.c
index c2d022d..9bed6ed 100644
--- a/bin/varnishd/cache/cache_backend_cfg.c
+++ b/bin/varnishd/cache/cache_backend_cfg.c
@@ -263,6 +263,8 @@ VRT_init_dir(struct cli *cli, struct director **dir, const char *name,
 		VRT_init_dir_fallback(cli, dir, idx, priv);
 	else if (!strcmp(name, "client"))
 		VRT_init_dir_client(cli, dir, idx, priv);
+	else if (!strcmp(name, "least-connection"))
+		VRT_init_dir_least_connection(cli, dir, idx, priv);
 	else
 		INCOMPL();
 }
diff --git a/bin/varnishd/cache/cache_dir_random.c b/bin/varnishd/cache/cache_dir_random.c
index b323343..84a1224 100644
--- a/bin/varnishd/cache/cache_dir_random.c
+++ b/bin/varnishd/cache/cache_dir_random.c
@@ -26,8 +26,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * This code is shared between the random, client and hash directors, because
- * they share the same properties and most of the same selection logic.
+ * This code is shared between the random, client, hash and least-connection
+ * directors, because they share the same properties and most of the same
+ * selection logic.
  *
  * The random director picks a backend on random.
  *
@@ -35,6 +36,9 @@
  *
  * The client director picks based on client identity or IP-address
  *
+ * The least-connection director picks a backend with the least number of
+ * established connections.
+ *
  * In all cases, the choice is by weight of the healthy subset of
  * configured backends.
  *
@@ -63,7 +67,7 @@ struct vdi_random_host {
 	double			weight;
 };
 
-enum crit_e {c_random, c_hash, c_client};
+enum crit_e {c_random, c_hash, c_client, c_least_connection};
 
 struct vdi_random {
 	unsigned		magic;
@@ -185,6 +189,36 @@ vdi_random_getfd(const struct director *d, struct sess *sp)
 	return (NULL);
 }
 
+static struct vbc *
+vdi_least_connection_getfd(const struct director *d, struct sess *sp)
+{
+	int i, m;
+	struct vdi_random *vs;
+	struct backend *b1, *b2;
+
+	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+	CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
+	CAST_OBJ_NOTNULL(vs, d->priv, VDI_RANDOM_MAGIC);
+
+	for (m = 0; m < vs->nhosts; m++)  {
+		if (!VDI_Healthy(vs->hosts[m].backend, sp))
+			continue;
+		b1 = vdi_get_backend_if_simple(vs->hosts[m].backend);
+		for (i = m + 1; i < vs->nhosts; i++) {
+			if (!VDI_Healthy(vs->hosts[i].backend, sp))
+				continue;
+			b2 = vdi_get_backend_if_simple(vs->hosts[i].backend);
+			if (b1->refcount * vs->hosts[i].weight >
+			    b2->refcount * vs->hosts[m].weight) {
+				b1 = b2;
+				m = i;
+			}
+		}
+		return (VDI_GetFd(vs->hosts[m].backend, sp));
+	}
+	return (NULL);
+}
+
 /*
  * Healthy if just a single backend is...
  */
@@ -241,7 +275,10 @@ vrt_init(struct cli *cli, struct director **bp, int idx,
 	vs->dir.priv = vs;
 	vs->dir.name = "random";
 	REPLACE(vs->dir.vcl_name, t->name);
-	vs->dir.getfd = vdi_random_getfd;
+	if (criteria == c_least_connection)
+		vs->dir.getfd = vdi_least_connection_getfd;
+	else
+		vs->dir.getfd = vdi_random_getfd;
 	vs->dir.fini = vdi_random_fini;
 	vs->dir.healthy = vdi_random_healthy;
 
@@ -283,3 +320,10 @@ VRT_init_dir_client(struct cli *cli, struct director **bp, int idx,
 {
 	vrt_init(cli, bp, idx, priv, c_client);
 }
+
+void
+VRT_init_dir_least_connection(struct cli *cli, struct director **bp, int idx,
+    const void *priv)
+{
+	vrt_init(cli, bp, idx, priv, c_least_connection);
+}
diff --git a/bin/varnishtest/tests/v00037.vtc b/bin/varnishtest/tests/v00037.vtc
new file mode 100644
index 0000000..f392f6f
--- /dev/null
+++ b/bin/varnishtest/tests/v00037.vtc
@@ -0,0 +1,86 @@
+varnishtest "Test least-connection director"
+
+server s1 {
+	rxreq
+	sema r1 sync 3
+	sema r1 sync 2
+	txresp -hdr "be: s1"
+	close
+
+	accept
+	rxreq
+	txresp -hdr "be: s1"
+} -start
+
+server s2 {
+	rxreq
+	sema r1 sync 3
+	txresp -hdr "be: s2"
+	close
+
+	accept
+	rxreq
+	txresp -hdr "be: s2"
+} -start
+
+server s3 {
+	rxreq
+	txresp -hdr "be: s3"
+	close
+
+	accept
+	rxreq
+	txresp -hdr "be: s3"
+} -start
+
+varnish v1 -vcl+backend {
+	director lc least-connection {
+		{ .backend = s1; .weight = 1; }
+		{ .backend = s2; .weight = 1; }
+		{ .backend = s3; .weight = 1; }
+	}
+	sub vcl_recv {
+		set req.backend = lc;
+		return (pass);
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -start
+
+client c2 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -start
+
+delay .5
+
+client c3 {
+	txreq
+	rxresp
+	expect resp.status == 200
+
+	txreq
+	rxresp
+	expect resp.http.be == "s3"
+
+	sema r1 sync 3
+
+	txreq
+	rxresp
+	expect resp.http.be == "s2"
+
+	sema r1 sync 2
+
+	txreq
+	rxresp
+	expect resp.http.be == "s1"
+} -start
+
+client c1 -wait
+client c2 -wait
+client c3 -wait
diff --git a/doc/sphinx/reference/vcl.rst b/doc/sphinx/reference/vcl.rst
index 2c185ed..68be210 100644
--- a/doc/sphinx/reference/vcl.rst
+++ b/doc/sphinx/reference/vcl.rst
@@ -275,6 +275,17 @@ An example of a fallback director::
                          // are unhealthy.
   }
 
+The least-connection director
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The least-connection director will pick a backend with the least number of
+established connections.
+
+Each backend requires a .weight option which sets the amount of traffic
+each backend will get compared to the others. Equal weight means equal
+traffic. A backend with lower weight than an other will get proportionally
+less traffic.
+
 Backend probes
 --------------
 
diff --git a/lib/libvcl/vcc_backend.c b/lib/libvcl/vcc_backend.c
index fb160e7..d1a8a31 100644
--- a/lib/libvcl/vcc_backend.c
+++ b/lib/libvcl/vcc_backend.c
@@ -688,6 +688,7 @@ static const struct dirlist {
 	{ "hash",		vcc_ParseRandomDirector },
 	{ "random",		vcc_ParseRandomDirector },
 	{ "client",		vcc_ParseRandomDirector },
+	{ "least-connection",	vcc_ParseRandomDirector },
 	{ "round-robin",	vcc_ParseRoundRobinDirector },
 	{ "fallback",		vcc_ParseRoundRobinDirector },
 	{ "dns",		vcc_ParseDnsDirector },



More information about the varnish-dev mailing list