From: Elijah Epifanov Date: Thu, 25 Oct 2007 18:15:38 +0000 (+0200) Subject: [MEDIUM] add support for "maxqueue" to limit server queue overload X-Git-Tag: v1.3.14~72 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=acafc5f88c3eaf98c3edfd6f3af1993cd2fb4604;p=thirdparty%2Fhaproxy.git [MEDIUM] add support for "maxqueue" to limit server queue overload This patch adds the "maxqueue" parameter to the server. This allows new sessions to be immediately rebalanced when the server's queue is filled. It's useful when session stickiness is just a performance boost (even a huge one) but not a requirement. This should only be used if session affinity isn't a hard functional requirement but provides performance boost by keeping server-local caches hot and compact). Absence of 'maxqueue' option means unlimited queue. When queue gets filled up to 'maxqueue' client session is moved from server-local queue to a global one. --- diff --git a/doc/haproxy-en.txt b/doc/haproxy-en.txt index 09d311e52e..3e8ce107b5 100644 --- a/doc/haproxy-en.txt +++ b/doc/haproxy-en.txt @@ -1364,6 +1364,21 @@ simultaneous sessions when the proxy instance will reach 10000 sessions, and will receive only 10 simultaneous sessions when the proxy will be under 1000 sessions. +It is possible to limit server queue length in order to rebalance excess +sessions between less busy application servers IF session affinity isn't +hard functional requirement (for example it just gives huge performance boost +by keeping server-local caches hot and compact). 'maxqueue' option sets a +queue limit on a server, as in example below: + +... (just the same as in example above) + server pentium3-800 192.168.1.1:80 cookie s1 weight 8 minconn 10 maxconn 100 check maxqueue 50 + server opteron-2.0G 192.168.1.2:80 cookie s2 weight 20 minconn 30 maxconn 300 check maxqueue 200 + server opteron-2.4G 192.168.1.3:80 cookie s3 weight 24 minconn 30 maxconn 300 check + +Absence of 'maxqueue' option means unlimited queue. When queue gets filled +up to 'maxqueue' client session is moved from server-local queue to a global +one. + Notes : ------- - The requests will not stay indefinitely in the queue, they follow the diff --git a/doc/haproxy-fr.txt b/doc/haproxy-fr.txt index d29259fc7c..7974546bf4 100644 --- a/doc/haproxy-fr.txt +++ b/doc/haproxy-fr.txt @@ -1391,6 +1391,23 @@ connexions simultan recevra seulement 10 connexions simultanées tant que le proxy sera sous les 1000 sessions. +Il est possible de limiter la taille de la file d'attente dans le but de +redistribuer les connexions destinées à un serveur en particulier qui sont trop +loin pour avoir une chance d'être servies en un temps raisonnable. Ceci n'est +acceptable que dans le cas où l'affinité entre le client et le serveur n'est +pas obligatoire, mais motivée uniquement par des raisons de performances, par +exemple, par l'utilisation d'un cache local au serveur. L'option 'maxqueue' +permet de préciser la limite par serveur, tel que dans l'exemple ci-dessous : + +... (même exemple que précédemment) + server pentium3-800 192.168.1.1:80 cookie s1 weight 8 minconn 10 maxconn 100 check maxqueue 50 + server opteron-2.0G 192.168.1.2:80 cookie s2 weight 20 minconn 30 maxconn 300 check maxqueue 200 + server opteron-2.4G 192.168.1.3:80 cookie s3 weight 24 minconn 30 maxconn 300 check + +En l'absence du paramètre 'maxqueue', la file d'un serveur n'a pas de limite +définie. Dans le cas contraire, lorsque la file atteint la limite fixée par +'maxqueue', les clients sont déplacés vers la file globale. + Notes : ------- - la requête ne restera pas indéfiniment en file d'attente, elle est diff --git a/include/types/server.h b/include/types/server.h index 62179f33d8..6e3a9138b4 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -64,6 +64,7 @@ struct server { int cur_sess, cur_sess_max; /* number of currently active sessions (including syn_sent) */ unsigned maxconn, minconn; /* max # of active sessions (0 = unlimited), min# for dynamic limit. */ int nbpend, nbpend_max; /* number of pending connections */ + int maxqueue; /* maximum number of pending connections allowed */ struct list pendconns; /* pending connections */ struct task *queue_mgt; /* the task associated to the queue processing */ diff --git a/src/backend.c b/src/backend.c index 596d5676ca..faf5db89a9 100644 --- a/src/backend.c +++ b/src/backend.c @@ -294,19 +294,25 @@ int assign_server_and_queue(struct session *s) return SRV_STATUS_INTERNAL; if (s->flags & SN_ASSIGNED) { - /* a server does not need to be assigned, perhaps because we're in - * direct mode, or in dispatch or transparent modes where the server - * is not needed. - */ - if (s->srv && - s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) { - p = pendconn_add(s); - if (p) - return SRV_STATUS_QUEUED; - else - return SRV_STATUS_FULL; + if (s->srv && s->srv->maxqueue > 0 && s->srv->nbpend >= s->srv->maxqueue) { + s->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET); + s->srv = NULL; + http_flush_cookie_flags(&s->txn); + } else { + /* a server does not need to be assigned, perhaps because we're in + * direct mode, or in dispatch or transparent modes where the server + * is not needed. + */ + if (s->srv && + s->srv->maxconn && s->srv->cur_sess >= srv_dynamic_maxconn(s->srv)) { + p = pendconn_add(s); + if (p) + return SRV_STATUS_QUEUED; + else + return SRV_STATUS_FULL; + } + return SRV_STATUS_OK; } - return SRV_STATUS_OK; } /* a server needs to be assigned */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 7b73e0bee1..89c8c1997f 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1413,6 +1413,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) newsrv->fall = DEF_FALLTIME; newsrv->health = newsrv->rise; /* up, but will fall down at first failure */ newsrv->uweight = 1; + newsrv->maxqueue = 0; cur_arg = 3; while (*args[cur_arg]) { @@ -1465,6 +1466,10 @@ int cfg_parse_listen(const char *file, int linenum, char **args) newsrv->maxconn = atol(args[cur_arg + 1]); cur_arg += 2; } + else if (!strcmp(args[cur_arg], "maxqueue")) { + newsrv->maxqueue = atol(args[cur_arg + 1]); + cur_arg += 2; + } else if (!strcmp(args[cur_arg], "check")) { global.maxsock++; do_check = 1; @@ -1521,7 +1526,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) } #endif else { - Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'addr', 'port', 'source', 'minconn', 'maxconn' and 'weight'.\n", + Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'addr', 'port', 'source', 'minconn', 'maxconn', 'maxqueue', and 'weight'.\n", file, linenum, newsrv->id); return -1; } diff --git a/src/dumpstats.c b/src/dumpstats.c index 7ec4b565be..4d34c474a1 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -372,7 +372,7 @@ int stats_dump_http(struct session *s, struct uri_auth *uri, int flags) "ereq,econ,eresp," "wretr,wredis," "status,weight,act,bck," - "chkfail,chkdown,lastchg,downtime," + "chkfail,chkdown,lastchg,downtime,qlimit," "\n"); } if (buffer_write_chunk(rep, &msg) != 0) @@ -582,20 +582,20 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, if (flags & STAT_FMT_HTML) { /* print a new table */ chunk_printf(&msg, sizeof(trash), - "\n" + "
\n" "" "" "" "\n" "" "" - "" + "" "" "" "" "\n" "" - "" + "" "" "" "" @@ -617,7 +617,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, if (flags & STAT_FMT_HTML) { chunk_printf(&msg, sizeof(trash), /* name, queue */ - "" + "" /* sessions : current, max, limit, cumul */ "" "" @@ -657,7 +657,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, /* server status : reflect frontend status */ "%s," /* rest of server: nothing */ - ",,,,,,," + ",,,,,,,," "\n", px->id, px->feconn, px->feconn_max, px->maxconn, px->cum_feconn, @@ -709,8 +709,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, chunk_printf(&msg, sizeof(trash), /* name */ "" - /* queue : current, max */ - "" + /* queue : current, max, limit */ + "" /* sessions : current, max, limit, cumul */ "" "" @@ -725,8 +725,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, "", (sv->state & SRV_BACKUP) ? "backup" : "active", sv_state, sv->id, - sv->nbpend, sv->nbpend_max, - sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess, + sv->nbpend, sv->nbpend_max, LIM2A0(sv->maxqueue, "-"), + sv->cur_sess, sv->cur_sess_max, LIM2A1(sv->maxconn, "-"), sv->cum_sess, sv->bytes_in, sv->bytes_out, sv->failed_secu, sv->failed_conns, sv->failed_resp, @@ -809,12 +809,17 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, /* check failures: unique, fatal; last change, total downtime */ if (sv->state & SRV_CHECKED) chunk_printf(&msg, sizeof(trash), - "%d,%d,%d,%d,\n", + "%d,%d,%d,%d,", sv->failed_checks, sv->down_trans, now.tv_sec - sv->last_change, srv_downtime(sv)); else chunk_printf(&msg, sizeof(trash), - ",,,,\n"); + ",,,,"); + + /* queue limit and EOL */ + chunk_printf(&msg, sizeof(trash), + "%s,\n", + LIM2A0(sv->maxqueue, "")); } if (buffer_write_chunk(rep, &msg) != 0) return 0; @@ -845,7 +850,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, /* name */ "" /* queue : current, max */ - "" + "" /* sessions : current, max, limit, cumul. */ "" /* bytes : in, out */ @@ -903,7 +908,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, "%d,%d,%d," /* rest of backend: nothing, down transformations, * last change, total downtime. */ - ",%d,%d,%d," + ",%d,%d,%d,," "\n", px->id, px->nbpend /* or px->totpend ? */, px->nbpend_max,
%s
QueueSessionsQueueSessionsBytesDeniedErrorsWarningsServer
CurMaxCurMaxCurMaxLimitCurMaxLimitCumulInOutReqRespReqConnRespRetrRedis
Frontend
Frontend%d%d%d%d
%s%d%d%d%d%s%d%d%s%d
Backend%d%d%d%d%d%d%d%d