From 5fcd02f28b10814318ced8954693c4c155c679ac Mon Sep 17 00:00:00 2001 From: phk Date: Tue, 26 Aug 2008 19:59:23 +0000 Subject: [PATCH] Varnish 2.0 bonus feature #1: backend->max_connections backend default { .host = "127.0.0.1"; .port = "9080"; .max_connections = 100; } will limit the simultaneous TCP connections to this backend to 100. Stats counter backend_busy == "Backend connections too many" tells how often we have hit this limit for a backend. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3135 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/cache.h | 1 - varnish-cache/bin/varnishd/cache_backend.c | 9 +++- varnish-cache/bin/varnishd/cache_backend.h | 4 ++ .../bin/varnishd/cache_backend_cfg.c | 20 +++++++-- .../bin/varnishtest/tests/v00012.vtc | 43 +++++++++++++++++++ varnish-cache/include/stat_field.h | 1 + varnish-cache/include/vrt.h | 1 + varnish-cache/lib/libvcl/vcc_backend.c | 12 +++++- varnish-cache/lib/libvcl/vcc_fixed_token.c | 1 + 9 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 varnish-cache/bin/varnishtest/tests/v00012.vtc diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index 460fdf19..50e335b4 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -407,7 +407,6 @@ void VBE_Poll(void); /* cache_backend_cfg.c */ void VBE_Init(void); -void VBE_DropRef(struct backend *); struct backend *VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb); /* cache_backend_poll.c */ diff --git a/varnish-cache/bin/varnishd/cache_backend.c b/varnish-cache/bin/varnishd/cache_backend.c index 53afab0c..831148ba 100644 --- a/varnish-cache/bin/varnishd/cache_backend.c +++ b/varnish-cache/bin/varnishd/cache_backend.c @@ -240,6 +240,7 @@ bes_conn_try(const struct sess *sp, struct backend *bp) LOCK(&bp->mtx); bp->refcount++; + bp->n_conn++; /* It mostly works */ UNLOCK(&bp->mtx); s = -1; @@ -256,6 +257,7 @@ bes_conn_try(const struct sess *sp, struct backend *bp) if (s < 0) { LOCK(&bp->mtx); + bp->n_conn--; bp->refcount--; /* Only keep ref on success */ UNLOCK(&bp->mtx); } @@ -318,6 +320,11 @@ VBE_GetVbe(struct sess *sp, struct backend *bp) return (NULL); } + if (bp->max_conn > 0 && bp->n_conn >= bp->max_conn) { + VSL_stats->backend_busy++; + return (NULL); + } + vc = VBE_NewConn(); assert(vc->fd == -1); AZ(vc->backend); @@ -347,7 +354,7 @@ VBE_ClosedFd(struct sess *sp) WSL(sp->wrk, SLT_BackendClose, sp->vbe->fd, "%s", bp->vcl_name); TCP_close(&sp->vbe->fd); - VBE_DropRef(bp); + VBE_DropRefConn(bp); sp->vbe->backend = NULL; VBE_ReleaseConn(sp->vbe); sp->vbe = NULL; diff --git a/varnish-cache/bin/varnishd/cache_backend.h b/varnish-cache/bin/varnishd/cache_backend.h index 6afb9155..bbfc1e4b 100644 --- a/varnish-cache/bin/varnishd/cache_backend.h +++ b/varnish-cache/bin/varnishd/cache_backend.h @@ -113,6 +113,8 @@ struct backend { struct sockaddr *ipv6; socklen_t ipv6len; + unsigned max_conn; + unsigned n_conn; VTAILQ_HEAD(, vbe_conn) connlist; struct vbp_target *probe; @@ -125,6 +127,8 @@ struct vbe_conn *VBE_GetVbe(struct sess *sp, struct backend *bp); /* cache_backend_cfg.c */ extern MTX VBE_mtx; +void VBE_DropRefConn(struct backend *); +void VBE_DropRef(struct backend *); void VBE_DropRefLocked(struct backend *b); /* cache_backend_poll.c */ diff --git a/varnish-cache/bin/varnishd/cache_backend_cfg.c b/varnish-cache/bin/varnishd/cache_backend_cfg.c index 27aba581..af7c4eb9 100644 --- a/varnish-cache/bin/varnishd/cache_backend_cfg.c +++ b/varnish-cache/bin/varnishd/cache_backend_cfg.c @@ -132,6 +132,18 @@ VBE_DropRef(struct backend *b) VBE_DropRefLocked(b); } +void +VBE_DropRefConn(struct backend *b) +{ + + CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC); + + LOCK(&b->mtx); + assert(b->n_conn > 0); + b->n_conn--; + VBE_DropRefLocked(b); +} + /*--------------------------------------------------------------------*/ static void @@ -210,6 +222,7 @@ VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb) REPLACE(b->hosthdr, vb->hosthdr); b->connect_timeout = vb->connect_timeout; + b->max_conn = vb->max_connections; /* * Copy over the sockaddrs @@ -252,10 +265,9 @@ cli_debug_backend(struct cli *cli, const char * const *av, void *priv) ASSERT_CLI(); VTAILQ_FOREACH(b, &backends, list) { CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC); - cli_out(cli, "%p %s %d\n", - b, - b->vcl_name, - b->refcount); + cli_out(cli, "%p %s %d %d/%d\n", + b, b->vcl_name, b->refcount, + b->n_conn, b->max_conn); } } diff --git a/varnish-cache/bin/varnishtest/tests/v00012.vtc b/varnish-cache/bin/varnishtest/tests/v00012.vtc new file mode 100644 index 00000000..fa4ba54c --- /dev/null +++ b/varnish-cache/bin/varnishtest/tests/v00012.vtc @@ -0,0 +1,43 @@ +# $Id$ + +test "Check backend connection limit" + +server s1 { + rxreq + sema r1 sync 2 + sema r2 sync 2 + txresp +} -start + +varnish v1 -vcl { + + backend default { + .host = "127.0.0.1"; + .port = "9080"; + .max_connections = 1; + } + sub vcl_recv { + pass; + } +} -start + +client c1 { + txreq + rxresp + expect resp.status == 200 +} -start + + +client c2 { + sema r1 sync 2 + txreq + rxresp + expect resp.status == 503 +} -run + +varnish v1 -cli "debug.backend" + +sema r2 sync 2 +client c1 -wait + +varnish v1 -expect backend_busy == 1 diff --git a/varnish-cache/include/stat_field.h b/varnish-cache/include/stat_field.h index 86f7b678..beec28ff 100644 --- a/varnish-cache/include/stat_field.h +++ b/varnish-cache/include/stat_field.h @@ -38,6 +38,7 @@ MAC_STAT(cache_miss, uint64_t, 'a', "Cache misses") MAC_STAT(backend_conn, uint64_t, 'a', "Backend connections success") MAC_STAT(backend_unhealthy, uint64_t, 'a', "Backend connections not attempted") +MAC_STAT(backend_busy, uint64_t, 'a', "Backend connections too many") MAC_STAT(backend_fail, uint64_t, 'a', "Backend connections failures") MAC_STAT(backend_reuse, uint64_t, 'a', "Backend connections reuses") MAC_STAT(backend_recycle, uint64_t, 'a', "Backend connections recycles") diff --git a/varnish-cache/include/vrt.h b/varnish-cache/include/vrt.h index 35bc1d7f..243c5d65 100644 --- a/varnish-cache/include/vrt.h +++ b/varnish-cache/include/vrt.h @@ -69,6 +69,7 @@ struct vrt_backend { const unsigned char *ipv6_sockaddr; double connect_timeout; + unsigned max_connections; struct vrt_backend_probe probe; }; diff --git a/varnish-cache/lib/libvcl/vcc_backend.c b/varnish-cache/lib/libvcl/vcc_backend.c index 7d93e3f4..284a6e2a 100644 --- a/varnish-cache/lib/libvcl/vcc_backend.c +++ b/varnish-cache/lib/libvcl/vcc_backend.c @@ -476,13 +476,16 @@ vcc_ParseHostDef(struct tokenlist *tl, int *nbh, const struct token *name, const const char *ep; struct fld_spec *fs; struct vsb *vsb; + unsigned u; fs = vcc_FldSpec(tl, "!host", "?port", "?host_header", "?connect_timeout", - "?probe", NULL); + "?probe", + "?max_connections", + NULL); t_first = tl->t; ExpectErr(tl, '{'); @@ -546,6 +549,13 @@ vcc_ParseHostDef(struct tokenlist *tl, int *nbh, const struct token *name, const Fb(tl, 0, ",\n"); ExpectErr(tl, ';'); vcc_NextToken(tl); + } else if (vcc_IdIs(t_field, "max_connections")) { + u = vcc_UintVal(tl); + vcc_NextToken(tl); + ERRCHK(tl); + ExpectErr(tl, ';'); + vcc_NextToken(tl); + Fb(tl, 0, "\t.max_connections = %u,\n", u); } else if (vcc_IdIs(t_field, "probe")) { vcc_ParseProbe(tl); ERRCHK(tl); diff --git a/varnish-cache/lib/libvcl/vcc_fixed_token.c b/varnish-cache/lib/libvcl/vcc_fixed_token.c index ff59e228..3ee45b25 100644 --- a/varnish-cache/lib/libvcl/vcc_fixed_token.c +++ b/varnish-cache/lib/libvcl/vcc_fixed_token.c @@ -349,6 +349,7 @@ vcl_output_lang_h(struct vsb *sb) vsb_cat(sb, " const unsigned char *ipv6_sockaddr;\n"); vsb_cat(sb, "\n"); vsb_cat(sb, " double connect_timeout;\n"); + vsb_cat(sb, " unsigned max_connections;\n"); vsb_cat(sb, " struct vrt_backend_probe probe;\n"); vsb_cat(sb, "};\n"); vsb_cat(sb, "\n"); -- 2.39.5