From: Willy Tarreau Date: Fri, 30 Nov 2007 16:42:05 +0000 (+0100) Subject: [MEDIUM] implement the slowstart parameter for servers X-Git-Tag: v1.3.14~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9909fc13f1e1c7c443068070b48dc703c6aa61ff;p=thirdparty%2Fhaproxy.git [MEDIUM] implement the slowstart parameter for servers The new 'slowstart' parameter for a server accepts a value in milliseconds which indicates after how long a server which has just come back up will run at full speed. The speed grows linearly from 0 to 100% during this time. The limitation applies to two parameters : - maxconn: the number of connections accepted by the server will grow from 1 to 100% of the usual dynamic limit defined by (minconn,maxconn,fullconn). - weight: when the backend uses a dynamic weighted algorithm, the weight grows linearly from 1 to 100%. In this case, the weight is updated at every health-check. For this reason, it is important that the 'inter' parameter is smaller than the 'slowstart', in order to maximize the number of steps. The slowstart never applies when haproxy starts, otherwise it would cause trouble to running servers. It only applies when a server has been previously seen as failed. --- diff --git a/include/types/server.h b/include/types/server.h index b50e1936d8..36ae7cb404 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -42,6 +42,7 @@ #define SRV_BIND_SRC 0x0008 /* this server uses a specific source address */ #define SRV_CHECKED 0x0010 /* this server needs to be checked */ #define SRV_GOINGDOWN 0x0020 /* this server says that it's going down (404) */ +#define SRV_WARMINGUP 0x0040 /* this server is warming up after a failure */ #define SRV_TPROXY_ADDR 0x0020 /* bind to this non-local address to reach this server */ #define SRV_TPROXY_CIP 0x0040 /* bind to the client's IP address to reach this server */ @@ -87,6 +88,7 @@ struct server { int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */ int rise, fall; /* time in iterations */ int inter; /* time in milliseconds */ + int slowstart; /* slowstart time in seconds (ms in the conf) */ int result; /* health-check result : SRV_CHK_* */ int curfd; /* file desc used for current test, or -1 if not in test */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 07caa72170..869567ffad 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1428,6 +1428,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) newsrv->health = newsrv->rise; /* up, but will fall down at first failure */ newsrv->uweight = 1; newsrv->maxqueue = 0; + newsrv->slowstart = 0; cur_arg = 3; while (*args[cur_arg]) { @@ -1484,6 +1485,11 @@ int cfg_parse_listen(const char *file, int linenum, char **args) newsrv->maxqueue = atol(args[cur_arg + 1]); cur_arg += 2; } + else if (!strcmp(args[cur_arg], "slowstart")) { + /* slowstart is stored in seconds */ + newsrv->slowstart = (atol(args[cur_arg + 1]) + 999) / 1000; + cur_arg += 2; + } else if (!strcmp(args[cur_arg], "check")) { global.maxsock++; do_check = 1; @@ -1540,7 +1546,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', 'maxqueue', and 'weight'.\n", + Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'addr', 'port', 'source', 'minconn', 'maxconn', 'maxqueue', 'slowstart' and 'weight'.\n", file, linenum, newsrv->id); return -1; } diff --git a/src/checks.c b/src/checks.c index d3aa6c8ce1..c72b55f629 100644 --- a/src/checks.c +++ b/src/checks.c @@ -530,6 +530,25 @@ void process_chk(struct task *t, struct timeval *next) if ((s->result & (SRV_CHK_ERROR|SRV_CHK_RUNNING)) == SRV_CHK_RUNNING) { /* good server detected */ //fprintf(stderr, "process_chk: 9\n"); + if (s->state & SRV_WARMINGUP) { + if (now.tv_sec < s->last_change || now.tv_sec >= s->last_change + s->slowstart) { + s->state &= ~SRV_WARMINGUP; + if (s->proxy->lbprm.algo & BE_LB_PROP_DYN) + s->eweight = s->uweight * BE_WEIGHT_SCALE; + if (s->proxy->lbprm.update_server_eweight) + s->proxy->lbprm.update_server_eweight(s); + } + else if (s->proxy->lbprm.algo & BE_LB_PROP_DYN) { + /* for dynamic algorithms, let's update the weight */ + s->eweight = BE_WEIGHT_SCALE * (now.tv_sec - s->last_change) / s->slowstart; + s->eweight *= s->uweight; + if (s->proxy->lbprm.update_server_eweight) + s->proxy->lbprm.update_server_eweight(s); + } + /* probably that we can refill this server with a bit more connections */ + check_for_pending(s); + } + /* we may have to add/remove this server from the LB group */ if ((s->state & SRV_RUNNING) && (s->proxy->options & PR_O_DISABLE404)) { if ((s->state & SRV_GOINGDOWN) && @@ -598,6 +617,17 @@ void process_chk(struct task *t, struct timeval *next) s->last_change = now.tv_sec; s->state |= SRV_RUNNING; + if (s->slowstart > 0) { + s->state |= SRV_WARMINGUP; + if (s->proxy->lbprm.algo & BE_LB_PROP_DYN) { + /* For dynamic algorithms, start at the first step of the weight, + * without multiplying by BE_WEIGHT_SCALE. + */ + s->eweight = s->uweight; + if (s->proxy->lbprm.update_server_eweight) + s->proxy->lbprm.update_server_eweight(s); + } + } s->proxy->lbprm.set_server_status_up(s); /* check if we can handle some connections queued at the proxy. We diff --git a/src/queue.c b/src/queue.c index a4670a80c3..d282fecb1e 100644 --- a/src/queue.c +++ b/src/queue.c @@ -33,20 +33,32 @@ int init_pendconn() /* returns the effective dynamic maxconn for a server, considering the minconn * and the proxy's usage relative to its dynamic connections limit. It is - * expected that 0 < s->minconn <= s->maxconn when this is called. + * expected that 0 < s->minconn <= s->maxconn when this is called. If the + * server is currently warming up, the slowstart is also applied to the + * resulting value, which can be lower than minconn in this case, but never + * less than 1. */ unsigned int srv_dynamic_maxconn(const struct server *s) { + unsigned int max; + if (s->proxy->beconn >= s->proxy->fullconn) /* no fullconn or proxy is full */ - return s->maxconn; - - if (s->minconn == s->maxconn) + max = s->maxconn; + else if (s->minconn == s->maxconn) /* static limit */ - return s->maxconn; - - return MAX(s->minconn, - s->proxy->beconn * s->maxconn / s->proxy->fullconn); + max = s->maxconn; + else max = MAX(s->minconn, + s->proxy->beconn * s->maxconn / s->proxy->fullconn); + + if ((s->state & SRV_WARMINGUP) && + now.tv_sec < s->last_change + s->slowstart && + now.tv_sec >= s->last_change) { + unsigned int ratio; + ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / s->slowstart); + max = max * ratio / 100; + } + return max; }