From: Willy Tarreau Date: Sat, 10 Oct 2009 10:02:45 +0000 (+0200) Subject: [MINOR] acl: add fe_conn, be_conn, queue, avg_queue X-Git-Tag: v1.4-dev4~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a36af91951539ee7b24afd1dee58216979efeaea;p=thirdparty%2Fhaproxy.git [MINOR] acl: add fe_conn, be_conn, queue, avg_queue These ACLs are used to check the number of active connections on the frontend, backend or in a backend's queue. The avg_queue returns the average number of queued connections per server, and for this, divides the total number of queued connections by the number of alive servers. The dst_conn ACL has been slightly changed to more reflect its name and original usage, which is to return the number of connections on the destination address/port (the socket) and not the whole frontend. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index fecab814fc..7e9659447d 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -5041,10 +5041,30 @@ dst_port to a different backend for some alternative ports. dst_conn - Applies to the number of currently established connections on the frontend, + Applies to the number of currently established connections on the same socket including the one being evaluated. It can be used to either return a sorry page before hard-blocking, or to use a specific backend to drain new requests - when the farm is considered saturated. + when the socket is considered saturated. This offers the ability to assign + different limits to different listening ports or addresses. See also the + "fe_conn" and "be_conn" criteria. + +fe_conn +fe_conn(frontend) + Applies to the number of currently established connections on the frontend, + possibly including the connection being evaluated. If no frontend name is + specified, the current one is used. But it is also possible to check another + frontend. It can be used to either return a sorry page before hard-blocking, + or to use a specific backend to drain new requests when the farm is + considered saturated. See also the "dst_conn", "be_conn" and "fe_sess_rate" + criteria. + +be_conn +be_conn(frontend) + Applies to the number of currently established connections on the backend, + possibly including the connection being evaluated. If no backend name is + specified, the current one is used. But it is also possible to check another + backend. It can be used to use a specific farm when the nominal one is full. + See also the "fe_conn", "queue" and "be_sess_rate" criteria. nbsrv nbsrv(backend) @@ -5063,19 +5083,43 @@ connslots(backend) 'connslots' = number of available server connection slots, + number of available server queue slots. - Note that while "dst_conn" may be used, "connslots" comes in especially + Note that while "fe_conn" may be used, "connslots" comes in especially useful when you have a case of traffic going to one single ip, splitting into multiple backends (perhaps using acls to do name-based load balancing) and you want to be able to differentiate between different backends, and their available "connslots". Also, whereas "nbsrv" only measures servers that are actually *down*, this acl is more fine-grained and looks into the number of - available connection slots as well. + available connection slots as well. See also "queue" and "avg_queue". OTHER CAVEATS AND NOTES: at this point in time, the code does not take care of dynamic connections. Also, if any of the server maxconn, or maxqueue is 0, then this acl clearly does not make sense, in which case the value returned will be -1. +queue +queue(frontend) + Returns the total number of queued connections of the designated backend, + including all the connections in server queues. If no backend name is + specified, the current one is used, but it is also possible to check another + one. This can be used to take actions when queuing goes above a known level, + generally indicating a surge of traffic or a massive slowdown on the servers. + One possible action could be to reject new users but still accept old ones. + See also the "avg_queue", "be_conn", and "be_sess_rate" criteria. + +avg_queue +avg_queue(frontend) + Returns the total number of queued connections of the designated backend + divided by the number of active servers. This is very similar to "queue" + except that the size of the farm is considered, in order to give a more + accurate measurement of the time it may take for a new connection to be + processed. The main usage is to return a sorry page to new users when it + becomes certain they will get a degraded service. Note that in the event + there would not be any active server anymore, we would consider twice the + number of queued connections as the measured value. This is a fair estimate, + as we expect one server to get back soon anyway, but we still prefer to send + new traffic to another backend if in better shape. See also the "queue", + "be_conn", and "be_sess_rate" criteria. + fe_sess_rate fe_sess_rate(frontend) Returns true when the session creation rate on the current or the named diff --git a/src/backend.c b/src/backend.c index 77c5a9207a..f4e6110f97 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1188,7 +1188,7 @@ acl_fetch_connslots(struct proxy *px, struct session *l4, void *l7, int dir, test->i = 0; iterator = px->srv; while (iterator) { - if ((iterator->state & 1) == 0) { + if ((iterator->state & SRV_RUNNING) == 0) { iterator = iterator->next; continue; } @@ -1243,6 +1243,99 @@ acl_fetch_be_sess_rate(struct proxy *px, struct session *l4, void *l7, int dir, return 1; } +/* set test->i to the number of concurrent connections on the frontend */ +static int +acl_fetch_fe_conn(struct proxy *px, struct session *l4, void *l7, int dir, + struct acl_expr *expr, struct acl_test *test) +{ + test->flags = ACL_TEST_F_VOL_TEST; + if (expr->arg_len) { + /* another proxy was designated, we must look for it */ + for (px = proxy; px; px = px->next) + if ((px->cap & PR_CAP_FE) && !strcmp(px->id, expr->arg.str)) + break; + } + if (!px) + return 0; + + test->i = px->feconn; + return 1; +} + +/* set test->i to the number of concurrent connections on the backend */ +static int +acl_fetch_be_conn(struct proxy *px, struct session *l4, void *l7, int dir, + struct acl_expr *expr, struct acl_test *test) +{ + test->flags = ACL_TEST_F_VOL_TEST; + if (expr->arg_len) { + /* another proxy was designated, we must look for it */ + for (px = proxy; px; px = px->next) + if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str)) + break; + } + if (!px) + return 0; + + test->i = px->beconn; + return 1; +} + +/* set test->i to the total number of queued connections on the backend */ +static int +acl_fetch_queue_size(struct proxy *px, struct session *l4, void *l7, int dir, + struct acl_expr *expr, struct acl_test *test) +{ + test->flags = ACL_TEST_F_VOL_TEST; + if (expr->arg_len) { + /* another proxy was designated, we must look for it */ + for (px = proxy; px; px = px->next) + if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str)) + break; + } + if (!px) + return 0; + + test->i = px->totpend; + return 1; +} + +/* set test->i to the total number of queued connections on the backend divided + * by the number of running servers and rounded up. If there is no running + * server, we return twice the total, just as if we had half a running server. + * This is more or less correct anyway, since we expect the last server to come + * back soon. + */ +static int +acl_fetch_avg_queue_size(struct proxy *px, struct session *l4, void *l7, int dir, + struct acl_expr *expr, struct acl_test *test) +{ + int nbsrv; + + test->flags = ACL_TEST_F_VOL_TEST; + if (expr->arg_len) { + /* another proxy was designated, we must look for it */ + for (px = proxy; px; px = px->next) + if ((px->cap & PR_CAP_BE) && !strcmp(px->id, expr->arg.str)) + break; + } + if (!px) + return 0; + + if (px->srv_act) + nbsrv = px->srv_act; + else if (px->lbprm.fbck) + nbsrv = 1; + else + nbsrv = px->srv_bck; + + if (nbsrv > 0) + test->i = (px->totpend + nbsrv - 1) / nbsrv; + else + test->i = px->totpend * 2; + + return 1; +} /* Note: must not be declared as its list will be overwritten */ static struct acl_kw_list acl_kws = {{ },{ @@ -1250,6 +1343,10 @@ static struct acl_kw_list acl_kws = {{ },{ { "connslots", acl_parse_int, acl_fetch_connslots, acl_match_int, ACL_USE_NOTHING }, { "fe_sess_rate", acl_parse_int, acl_fetch_fe_sess_rate, acl_match_int, ACL_USE_NOTHING }, { "be_sess_rate", acl_parse_int, acl_fetch_be_sess_rate, acl_match_int, ACL_USE_NOTHING }, + { "fe_conn", acl_parse_int, acl_fetch_fe_conn, acl_match_int, ACL_USE_NOTHING }, + { "be_conn", acl_parse_int, acl_fetch_be_conn, acl_match_int, ACL_USE_NOTHING }, + { "queue", acl_parse_int, acl_fetch_queue_size, acl_match_int, ACL_USE_NOTHING }, + { "avg_queue", acl_parse_int, acl_fetch_avg_queue_size, acl_match_int, ACL_USE_NOTHING }, { NULL, NULL, NULL, NULL }, }}; diff --git a/src/client.c b/src/client.c index 3bd31cf1f2..b9e304a12c 100644 --- a/src/client.c +++ b/src/client.c @@ -593,12 +593,12 @@ acl_fetch_dport(struct proxy *px, struct session *l4, void *l7, int dir, } -/* set test->i to the number of connexions to the proxy */ +/* set test->i to the number of connexions to the same listening socket */ static int acl_fetch_dconn(struct proxy *px, struct session *l4, void *l7, int dir, struct acl_expr *expr, struct acl_test *test) { - test->i = px->feconn; + test->i = l4->listener->nbconn; return 1; }