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

The getaddrinfo(3) API does not tell us the TTL value learned from DNS

so we have to add our own stuff for that.

Without some kind of TTL, we would hit the DNS server once per failed
attempt to connect to the backend.

If the backend were down, we could hit it a LOT.

In the VCL code:

	backend foobar {
		[...]
		set backend.dnsttl = 20s;
	}

will assign a TTL for DNS lookups of this backends hostname+port
combination, we will not hit the DNS server more often that this.

The default is set at 30 seconds, short enough to make things are
workable in a load-balancing-via-DNS setups, yet long enough to not
pound the DNS server flat in case of backend failures.

NOTE that as long as we succeed in connecting to the backend we
do not perform new DNS lookups.  That will have to be revisited
along with possible load-balancing schemes for the backend(s).



git-svn-id: http://www.varnish-cache.org/svn/trunk@1237 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 5a5dffc5
...@@ -302,6 +302,9 @@ struct backend { ...@@ -302,6 +302,9 @@ struct backend {
struct addrinfo *last_addr; struct addrinfo *last_addr;
TAILQ_HEAD(,vbe_conn) connlist; TAILQ_HEAD(,vbe_conn) connlist;
double dnsttl;
double dnstime;
#if 0 #if 0
double responsetime; double responsetime;
double timeout; double timeout;
......
...@@ -58,13 +58,26 @@ static TAILQ_HEAD(,vbe_conn) vbe_head = TAILQ_HEAD_INITIALIZER(vbe_head); ...@@ -58,13 +58,26 @@ static TAILQ_HEAD(,vbe_conn) vbe_head = TAILQ_HEAD_INITIALIZER(vbe_head);
static MTX vbemtx; static MTX vbemtx;
/*--------------------------------------------------------------------*/
/* XXX: belongs a more general place */
static double
Uptime(void)
{
struct timespec ts;
assert(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
return (ts.tv_sec + ts.tv_nsec * 1e-9);
}
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
static struct vbe_conn * static struct vbe_conn *
vbe_new_conn(void) vbe_new_conn(void)
{ {
struct vbe_conn *vbc; struct vbe_conn *vbc;
unsigned char *p, space; unsigned char *p;
unsigned space;
space = params->mem_workspace; space = params->mem_workspace;
vbc = calloc(sizeof *vbc + space * 2, 1); vbc = calloc(sizeof *vbc + space * 2, 1);
...@@ -93,6 +106,7 @@ vbe_lookup(struct backend *bp) ...@@ -93,6 +106,7 @@ vbe_lookup(struct backend *bp)
if (bp->addr != NULL) { if (bp->addr != NULL) {
freeaddrinfo(bp->addr); freeaddrinfo(bp->addr);
bp->addr = NULL; bp->addr = NULL;
bp->last_addr = NULL;
} }
memset(&hint, 0, sizeof hint); memset(&hint, 0, sizeof hint);
...@@ -102,13 +116,14 @@ vbe_lookup(struct backend *bp) ...@@ -102,13 +116,14 @@ vbe_lookup(struct backend *bp)
error = getaddrinfo(bp->hostname, error = getaddrinfo(bp->hostname,
bp->portname == NULL ? "http" : bp->portname, bp->portname == NULL ? "http" : bp->portname,
&hint, &res); &hint, &res);
bp->dnstime = Uptime();
if (error) { if (error) {
if (res != NULL) if (res != NULL)
freeaddrinfo(res); freeaddrinfo(res);
printf("getaddrinfo: %s\n", gai_strerror(error)); /* XXX */ printf("getaddrinfo: %s\n", gai_strerror(error)); /* XXX */
bp->addr = NULL;
return; return;
} }
bp->last_addr = res;
bp->addr = res; bp->addr = res;
} }
...@@ -120,9 +135,7 @@ vbe_sock_conn(const struct addrinfo *ai) ...@@ -120,9 +135,7 @@ vbe_sock_conn(const struct addrinfo *ai)
int s; int s;
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (s < 0) if (s >= 0 && connect(s, ai->ai_addr, ai->ai_addrlen)) {
return (s);
else if (connect(s, ai->ai_addr, ai->ai_addrlen)) {
AZ(close(s)); AZ(close(s));
s = -1; s = -1;
} }
...@@ -157,6 +170,9 @@ vbe_conn_try(struct backend *bp, struct addrinfo **pai) ...@@ -157,6 +170,9 @@ vbe_conn_try(struct backend *bp, struct addrinfo **pai)
} }
} }
if (bp->dnstime + bp->dnsttl >= Uptime())
return (-1);
/* Then do another lookup to catch DNS changes */ /* Then do another lookup to catch DNS changes */
vbe_lookup(bp); vbe_lookup(bp);
......
...@@ -124,6 +124,7 @@ VRT_alloc_backends(struct VCL_conf *cp) ...@@ -124,6 +124,7 @@ VRT_alloc_backends(struct VCL_conf *cp)
cp->backend[i] = calloc(sizeof *cp->backend[i], 1); cp->backend[i] = calloc(sizeof *cp->backend[i], 1);
XXXAN(cp->backend[i]); XXXAN(cp->backend[i]);
cp->backend[i]->magic = BACKEND_MAGIC; cp->backend[i]->magic = BACKEND_MAGIC;
cp->backend[i]->dnsttl = 30;
TAILQ_INIT(&cp->backend[i]->connlist); TAILQ_INIT(&cp->backend[i]->connlist);
} }
} }
...@@ -160,6 +161,7 @@ VRT_r_backend_##onm(struct backend *be) \ ...@@ -160,6 +161,7 @@ VRT_r_backend_##onm(struct backend *be) \
VBACKEND(const char *, host, hostname) VBACKEND(const char *, host, hostname)
VBACKEND(const char *, port, portname) VBACKEND(const char *, port, portname)
VBACKEND(double, dnsttl, dnsttl)
/*-------------------------------------------------------------------- /*--------------------------------------------------------------------
* XXX: Working relative to t_req is maybe not the right thing, we could * XXX: Working relative to t_req is maybe not the right thing, we could
......
...@@ -10,6 +10,8 @@ const char * VRT_r_backend_host(struct backend *); ...@@ -10,6 +10,8 @@ const char * VRT_r_backend_host(struct backend *);
void VRT_l_backend_host(struct backend *, const char *); void VRT_l_backend_host(struct backend *, const char *);
const char * VRT_r_backend_port(struct backend *); const char * VRT_r_backend_port(struct backend *);
void VRT_l_backend_port(struct backend *, const char *); void VRT_l_backend_port(struct backend *, const char *);
double VRT_r_backend_dnsttl(struct backend *);
void VRT_l_backend_dnsttl(struct backend *, double);
const unsigned char * VRT_r_client_ip(struct sess *); const unsigned char * VRT_r_client_ip(struct sess *);
void VRT_l_client_ip(struct sess *, const unsigned char *); void VRT_l_client_ip(struct sess *, const unsigned char *);
const char * VRT_r_req_request(struct sess *); const char * VRT_r_req_request(struct sess *);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
-printf_code( ju, long long unsigned) -printf_code( ju, long long unsigned)
-printf_code( jx, long long unsigned) -printf_code( jx, long long unsigned)
+libh ../../config.h
-header(../../config.h) -header(../../config.h)
-sem(lbv_assert, r_no) -sem(lbv_assert, r_no)
-sem(strchr, 1p, type(1), 2n == 0 ? (@p < 1p) : (@p < 1p || @p == 0 )) -sem(strchr, 1p, type(1), 2n == 0 ? (@p < 1p) : (@p < 1p || @p == 0 ))
......
...@@ -258,6 +258,7 @@ AddRefStr(struct tokenlist *tl, const char *s, enum ref_type type) ...@@ -258,6 +258,7 @@ AddRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
t->e = strchr(s, '\0'); t->e = strchr(s, '\0');
t->tok = METHOD; t->tok = METHOD;
AddRef(tl, t, type); AddRef(tl, t, type);
/* XXX: possibly leaking t */
} }
void void
...@@ -931,6 +932,7 @@ CheckHostPort(const char *host, const char *port) ...@@ -931,6 +932,7 @@ CheckHostPort(const char *host, const char *port)
static void static void
Backend(struct tokenlist *tl) Backend(struct tokenlist *tl)
{ {
unsigned a;
struct var *vp; struct var *vp;
struct token *t_be = NULL; struct token *t_be = NULL;
struct token *t_host = NULL; struct token *t_host = NULL;
...@@ -984,6 +986,27 @@ Backend(struct tokenlist *tl) ...@@ -984,6 +986,27 @@ Backend(struct tokenlist *tl)
Fc(tl, 0, ");\n"); Fc(tl, 0, ");\n");
vcc_NextToken(tl); vcc_NextToken(tl);
break; break;
#if 0
case INT:
case SIZE:
case RATE:
case FLOAT:
#endif
case TIME:
Fc(tl, 1, "\t%s ", vp->lname);
a = tl->t->tok;
if (a == T_MUL || a == T_DIV)
Fc(tl, 0, "%g", DoubleVal(tl));
else if (vp->fmt == TIME)
TimeVal(tl);
else if (vp->fmt == SIZE)
SizeVal(tl);
else if (vp->fmt == RATE)
RateVal(tl);
else
Fc(tl, 0, "%g", DoubleVal(tl));
Fc(tl, 0, ");\n");
break;
default: default:
vsb_printf(tl->sb, vsb_printf(tl->sb,
"Assignments not possible for '%s'\n", vp->name); "Assignments not possible for '%s'\n", vp->name);
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
set beobj { set beobj {
{ backend.host HOSTNAME } { backend.host HOSTNAME }
{ backend.port PORTNAME } { backend.port PORTNAME }
{ backend.dnsttl TIME }
} }
# Objects which operate on sessions # Objects which operate on sessions
......
...@@ -18,6 +18,10 @@ struct var vcc_be_vars[] = { ...@@ -18,6 +18,10 @@ struct var vcc_be_vars[] = {
"VRT_r_backend_port(backend)", "VRT_r_backend_port(backend)",
"VRT_l_backend_port(backend, ", "VRT_l_backend_port(backend, ",
}, },
{ "backend.dnsttl", TIME, 14,
"VRT_r_backend_dnsttl(backend)",
"VRT_l_backend_dnsttl(backend, ",
},
{ NULL } { NULL }
}; };
...@@ -82,6 +86,8 @@ const char *vrt_obj_h = ...@@ -82,6 +86,8 @@ const char *vrt_obj_h =
"void VRT_l_backend_host(struct backend *, const char *);\n" "void VRT_l_backend_host(struct backend *, const char *);\n"
"const char * VRT_r_backend_port(struct backend *);\n" "const char * VRT_r_backend_port(struct backend *);\n"
"void VRT_l_backend_port(struct backend *, const char *);\n" "void VRT_l_backend_port(struct backend *, const char *);\n"
"double VRT_r_backend_dnsttl(struct backend *);\n"
"void VRT_l_backend_dnsttl(struct backend *, double);\n"
"const unsigned char * VRT_r_client_ip(struct sess *);\n" "const unsigned char * VRT_r_client_ip(struct sess *);\n"
"void VRT_l_client_ip(struct sess *, const unsigned char *);\n" "void VRT_l_client_ip(struct sess *, const unsigned char *);\n"
"const char * VRT_r_req_request(struct sess *);\n" "const char * VRT_r_req_request(struct sess *);\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