[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