From: cecilihf Date: Fri, 27 Jul 2007 14:16:39 +0000 (+0000) Subject: Added a health parameter for the backend. This is readable in vcl with backend.health. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e49f28d3186b29d4fbff5178910615d53e5d2db5;p=varnish Added a health parameter for the backend. This is readable in vcl with backend.health. Made it possible to pass a vcl variable to error (error 200 backend.health). Implemented a first attempt at an algorithm for checking the health of a backend. Negative values means the backend has problems, positive values means it is ok. 0 is neutral, and could mean that it has been a while since the backend was asked for anything. See the code for details. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1778 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index e2da5bf2..951d2a04 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -332,6 +332,11 @@ struct backend { double dnsttl; double dnstime; + + int health; + double last_check; + int minute_limit; + #if 0 double responsetime; double timeout; diff --git a/varnish-cache/bin/varnishd/cache_center.c b/varnish-cache/bin/varnishd/cache_center.c index 1bc6b446..46b4cefe 100644 --- a/varnish-cache/bin/varnishd/cache_center.c +++ b/varnish-cache/bin/varnishd/cache_center.c @@ -288,10 +288,35 @@ cnt_fetch(struct sess *sp) AN(sp->bereq); i = Fetch(sp); + + /* Experimental. Set time for last check of backend health. + * If the backend replied with 200, it is obviously up and running, + * increase health parameter. If we got a 504 back, it would imply + * that the backend is not reachable. Decrease health parameter. + */ + sp->backend->last_check = TIM_mono(); + sp->backend->minute_limit = 1; + if (!i){ + if (http_GetStatus(sp->bereq->http) == 200) { + if (sp->backend->health < 10000) + sp->backend->health++; + } else if(http_GetStatus(sp->bereq->http) == 504) { + if (sp->backend->health > -10000) + sp->backend->health--; + } + } + + vbe_free_bereq(sp->bereq); sp->bereq = NULL; if (i) { + /* Experimental. If the fetch failed, it would also seem + * to be a backend problem, so decrease the health parameter. + */ + if (sp->backend->health > -10000) + sp->backend->health--; + SYN_ErrorPage(sp, 503, "Error talking to backend", 30); } else { RFC2616_cache_policy(sp, &sp->obj->http); /* XXX -> VCL */ @@ -372,8 +397,19 @@ DOT hit -> deliver [label="deliver",style=bold,color=green,weight=4] static int cnt_hit(struct sess *sp) { + double time_diff; + double minutes; assert(!sp->obj->pass); + + /* Experimental. Reduce health parameter of backend towards zero + * if it has been more than a minute since it was checked. */ + time_diff = TIM_mono() - sp->backend->last_check; + minutes = time_diff / 60; + if (minutes > sp->backend->minute_limit) { + sp->backend->minute_limit++; + sp->backend->health = (int)((double)sp->backend->health / 2); + } VCL_hit_method(sp); diff --git a/varnish-cache/bin/varnishd/cache_vrt.c b/varnish-cache/bin/varnishd/cache_vrt.c index 04b92f02..d393c7cf 100644 --- a/varnish-cache/bin/varnishd/cache_vrt.c +++ b/varnish-cache/bin/varnishd/cache_vrt.c @@ -289,6 +289,9 @@ VRT_alloc_backends(struct VCL_conf *cp) cp->backend[i]->magic = BACKEND_MAGIC; cp->backend[i]->dnsttl = 30; TAILQ_INIT(&cp->backend[i]->connlist); + cp->backend[i]->health = 0; + cp->backend[i]->last_check = TIM_mono(); + cp->backend[i]->minute_limit = 1; } } @@ -320,6 +323,7 @@ VBACKEND(const char *, host, hostname) VBACKEND(const char *, port, portname) VBACKEND(double, dnsttl, dnsttl) + /*-------------------------------------------------------------------- * XXX: Working relative to t_req is maybe not the right thing, we could * XXX: have spent a long time talking to the backend since then. @@ -487,6 +491,15 @@ VRT_r_obj_lastuse(struct sess *sp) return (TIM_mono() - sp->obj->lru_stamp); } +int +VRT_r_backend_health(struct sess *sp) +{ + + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC); + return sp->backend->health; +} + /*--------------------------------------------------------------------*/ char * @@ -514,6 +527,18 @@ VRT_IP_string(struct sess *sp, struct sockaddr *sa) return (q); } +char * +VRT_int_string(struct sess *sp, int num) +{ + char *p; + int size = 10; + + p = WS_Alloc(sp->http->ws, size); + AN(p); + snprintf(p, size, "%d", num); + return (p); +} + /*--------------------------------------------------------------------*/ void diff --git a/varnish-cache/include/vrt.h b/varnish-cache/include/vrt.h index 2cf5f7ef..7edf14f4 100644 --- a/varnish-cache/include/vrt.h +++ b/varnish-cache/include/vrt.h @@ -89,6 +89,7 @@ void VRT_free_backends(struct VCL_conf *cp); void VRT_fini_backend(struct backend *be); char *VRT_IP_string(struct sess *sp, struct sockaddr *sa); +char *VRT_int_string(struct sess *sp, int); #define VRT_done(sp, hand) \ do { \ diff --git a/varnish-cache/include/vrt_obj.h b/varnish-cache/include/vrt_obj.h index 2d65ca2f..9560ce7a 100644 --- a/varnish-cache/include/vrt_obj.h +++ b/varnish-cache/include/vrt_obj.h @@ -46,3 +46,4 @@ void VRT_l_resp_status(struct sess *, int); const char * VRT_r_resp_response(struct sess *); void VRT_l_resp_response(struct sess *, const char *, ...); double VRT_r_now(struct sess *); +int VRT_r_backend_health(struct sess *); diff --git a/varnish-cache/lib/libvcl/vcc_action.c b/varnish-cache/lib/libvcl/vcc_action.c index 181abe23..9b007e0a 100644 --- a/varnish-cache/lib/libvcl/vcc_action.c +++ b/varnish-cache/lib/libvcl/vcc_action.c @@ -84,6 +84,9 @@ parse_error(struct tokenlist *tl) if (tl->t->tok == CSTR) { Fb(tl, 0, ", %.*s", PF(tl->t)); vcc_NextToken(tl); + } else if (tl->t->tok == VAR) { + Fb(tl, 0, ", "); + vcc_StringVal(tl); } else { Fb(tl, 0, ", (const char *)0"); } diff --git a/varnish-cache/lib/libvcl/vcc_fixed_token.c b/varnish-cache/lib/libvcl/vcc_fixed_token.c index 07e30c56..4cb1f77b 100644 --- a/varnish-cache/lib/libvcl/vcc_fixed_token.c +++ b/varnish-cache/lib/libvcl/vcc_fixed_token.c @@ -445,6 +445,7 @@ vcl_output_lang_h(struct vsb *sb) vsb_cat(sb, "void VRT_fini_backend(struct backend *be);\n"); vsb_cat(sb, "\n"); vsb_cat(sb, "char *VRT_IP_string(struct sess *sp, struct sockaddr *sa);\n"); + vsb_cat(sb, "char *VRT_int_string(struct sess *sp, int);\n"); vsb_cat(sb, "\n"); vsb_cat(sb, "#define VRT_done(sp, hand) \\\n"); vsb_cat(sb, " do { \\\n"); @@ -499,4 +500,5 @@ vcl_output_lang_h(struct vsb *sb) vsb_cat(sb, "const char * VRT_r_resp_response(struct sess *);\n"); vsb_cat(sb, "void VRT_l_resp_response(struct sess *, const char *, ...);\n"); vsb_cat(sb, "double VRT_r_now(struct sess *);\n"); + vsb_cat(sb, "int VRT_r_backend_health(struct sess *);\n"); } diff --git a/varnish-cache/lib/libvcl/vcc_gen_obj.tcl b/varnish-cache/lib/libvcl/vcc_gen_obj.tcl index 8d691ffe..315ab05e 100755 --- a/varnish-cache/lib/libvcl/vcc_gen_obj.tcl +++ b/varnish-cache/lib/libvcl/vcc_gen_obj.tcl @@ -164,6 +164,10 @@ set spobj { RO TIME {recv pipe pass hash miss hit fetch deliver discard timeout} } + { backend.health RO INT + {recv pipe pass hash miss hit fetch deliver discard timeout} + } + } set tt(IP) "struct sockaddr *" diff --git a/varnish-cache/lib/libvcl/vcc_obj.c b/varnish-cache/lib/libvcl/vcc_obj.c index b0930662..e016aad6 100644 --- a/varnish-cache/lib/libvcl/vcc_obj.c +++ b/varnish-cache/lib/libvcl/vcc_obj.c @@ -210,5 +210,12 @@ struct var vcc_vars[] = { 0, VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_DISCARD | VCL_MET_TIMEOUT }, + { "backend.health", INT, 14, + "VRT_r_backend_health(sp)", + NULL, + V_RO, + 0, + VCL_MET_RECV | VCL_MET_PIPE | VCL_MET_PASS | VCL_MET_HASH | VCL_MET_MISS | VCL_MET_HIT | VCL_MET_FETCH | VCL_MET_DELIVER | VCL_MET_DISCARD | VCL_MET_TIMEOUT + }, { NULL } }; diff --git a/varnish-cache/lib/libvcl/vcc_string.c b/varnish-cache/lib/libvcl/vcc_string.c index b50a7361..80eb0972 100644 --- a/varnish-cache/lib/libvcl/vcc_string.c +++ b/varnish-cache/lib/libvcl/vcc_string.c @@ -140,6 +140,9 @@ vcc_StringVal(struct tokenlist *tl) case IP: Fb(tl, 0, "VRT_IP_string(sp, %s)", vp->rname); break; + case INT: + Fb(tl, 0, "VRT_int_string(sp, %s)", vp->rname); + break; default: vsb_printf(tl->sb, "String representation of '%s' not implemented yet.\n",