Commit 6e875421 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

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: http://www.varnish-cache.org/svn/trunk@3135 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 25471613
......@@ -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 */
......
......@@ -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;
......
......@@ -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 */
......
......@@ -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);
}
}
......
# $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
......@@ -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")
......
......@@ -69,6 +69,7 @@ struct vrt_backend {
const unsigned char *ipv6_sockaddr;
double connect_timeout;
unsigned max_connections;
struct vrt_backend_probe probe;
};
......
......@@ -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);
......
......@@ -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");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment