mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-12 08:49:29 +00:00
[MEDIUM] differentiate between generic LB params and map-specific ones
Since the introduction of server weights, all load balancing algorithms relied on a pre-computed map. Incidently, quite a bunch of map-specific parameters were used at random places in order to get the number of servers or their total weight. It was not architecturally acceptable that optimizations for the map computation had impact on external parts. For instance, during this cleanup it was found that a backend weight was seen as 1 when only the first backup server is used, whatever its weight. This cleanup consists in differentiating between LB-generic parameters, such as total weights, number of servers, etc... and map-specific ones. The struct proxy has been enhanced in order to make it easier to later support other algorithms. The recount_servers() function now also updates generic values such as total weights so that it's not needed anymore to call recalc_server_map() when weights are needed. This permitted to simplify some code which does not need to know about map internals anymore.
This commit is contained in:
parent
be68e6a437
commit
2069704492
@ -46,7 +46,7 @@ int be_downtime(struct proxy *px);
|
||||
/*
|
||||
* This function tries to find a running server with free connection slots for
|
||||
* the proxy <px> following the round-robin method.
|
||||
* If any server is found, it will be returned and px->srv_rr_idx will be updated
|
||||
* If any server is found, it will be returned and px->lbprm.map.rr_idx will be updated
|
||||
* to point to the next server. If no valid server is found, NULL is returned.
|
||||
*/
|
||||
static inline struct server *get_server_rr_with_conns(struct proxy *px)
|
||||
@ -54,25 +54,25 @@ static inline struct server *get_server_rr_with_conns(struct proxy *px)
|
||||
int newidx;
|
||||
struct server *srv;
|
||||
|
||||
if (px->map_state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
if (px->srv_map_sz == 0)
|
||||
if (px->lbprm.tot_weight == 0)
|
||||
return NULL;
|
||||
|
||||
if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
|
||||
px->srv_rr_idx = 0;
|
||||
newidx = px->srv_rr_idx;
|
||||
if (px->lbprm.map.state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
if (px->lbprm.map.rr_idx < 0 || px->lbprm.map.rr_idx >= px->lbprm.tot_weight)
|
||||
px->lbprm.map.rr_idx = 0;
|
||||
newidx = px->lbprm.map.rr_idx;
|
||||
|
||||
do {
|
||||
srv = px->srv_map[newidx++];
|
||||
srv = px->lbprm.map.srv[newidx++];
|
||||
if (!srv->maxconn || srv->cur_sess < srv_dynamic_maxconn(srv)) {
|
||||
px->srv_rr_idx = newidx;
|
||||
px->lbprm.map.rr_idx = newidx;
|
||||
return srv;
|
||||
}
|
||||
if (newidx == px->srv_map_sz)
|
||||
if (newidx == px->lbprm.tot_weight)
|
||||
newidx = 0;
|
||||
} while (newidx != px->srv_rr_idx);
|
||||
} while (newidx != px->lbprm.map.rr_idx);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -81,20 +81,20 @@ static inline struct server *get_server_rr_with_conns(struct proxy *px)
|
||||
/*
|
||||
* This function tries to find a running server for the proxy <px> following
|
||||
* the round-robin method.
|
||||
* If any server is found, it will be returned and px->srv_rr_idx will be updated
|
||||
* If any server is found, it will be returned and px->lbprm.map.rr_idx will be updated
|
||||
* to point to the next server. If no valid server is found, NULL is returned.
|
||||
*/
|
||||
static inline struct server *get_server_rr(struct proxy *px)
|
||||
{
|
||||
if (px->map_state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
if (px->srv_map_sz == 0)
|
||||
if (px->lbprm.tot_weight == 0)
|
||||
return NULL;
|
||||
|
||||
if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz)
|
||||
px->srv_rr_idx = 0;
|
||||
return px->srv_map[px->srv_rr_idx++];
|
||||
if (px->lbprm.map.state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
if (px->lbprm.map.rr_idx < 0 || px->lbprm.map.rr_idx >= px->lbprm.tot_weight)
|
||||
px->lbprm.map.rr_idx = 0;
|
||||
return px->lbprm.map.srv[px->lbprm.map.rr_idx++];
|
||||
}
|
||||
|
||||
|
||||
@ -110,21 +110,21 @@ static inline struct server *get_server_sh(struct proxy *px,
|
||||
{
|
||||
unsigned int h, l;
|
||||
|
||||
if (px->map_state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
if (px->srv_map_sz == 0)
|
||||
if (px->lbprm.tot_weight == 0)
|
||||
return NULL;
|
||||
|
||||
if (px->lbprm.map.state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
l = h = 0;
|
||||
if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) {
|
||||
while ((l + sizeof (int)) <= len) {
|
||||
h ^= ntohl(*(unsigned int *)(&addr[l]));
|
||||
l += sizeof (int);
|
||||
}
|
||||
h %= px->srv_map_sz;
|
||||
h %= px->lbprm.tot_weight;
|
||||
}
|
||||
return px->srv_map[h];
|
||||
return px->lbprm.map.srv[h];
|
||||
}
|
||||
|
||||
/*
|
||||
@ -144,12 +144,12 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_
|
||||
unsigned long hash = 0;
|
||||
int c;
|
||||
|
||||
if (px->map_state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
if (px->srv_map_sz == 0)
|
||||
if (px->lbprm.tot_weight == 0)
|
||||
return NULL;
|
||||
|
||||
if (px->lbprm.map.state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
while (uri_len--) {
|
||||
c = *uri++;
|
||||
if (c == '?')
|
||||
@ -157,7 +157,7 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
}
|
||||
|
||||
return px->srv_map[hash % px->srv_map_sz];
|
||||
return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
||||
#define PR_MODE_HTTP 1
|
||||
#define PR_MODE_HEALTH 2
|
||||
|
||||
/* values for proxy->map_state */
|
||||
/* values for proxy->lbprm.map.state */
|
||||
#define PR_MAP_RECALC (1 << 0)
|
||||
|
||||
/* flag values for proxy->cap. This is a bitmask of capabilities supported by the proxy */
|
||||
@ -78,13 +78,21 @@ struct proxy {
|
||||
struct list acl; /* ACL declared on this proxy */
|
||||
struct list block_cond; /* early blocking conditions (chained) */
|
||||
struct list switching_rules; /* content switching rules (chained) */
|
||||
int map_state; /* PR_MAP_RECALC */
|
||||
struct server *srv; /* known servers */
|
||||
int srv_act, srv_bck; /* # of running servers */
|
||||
int tot_wact, tot_wbck; /* total weights of active and backup servers */
|
||||
struct server **srv_map; /* the server map used to apply weights */
|
||||
int srv_map_sz; /* the size of the effective server map */
|
||||
int srv_rr_idx; /* next server to be elected in round robin mode */
|
||||
|
||||
struct {
|
||||
int tot_wact, tot_wbck; /* total effective weights of active and backup servers */
|
||||
int tot_weight; /* total effective weight of servers participating to LB */
|
||||
int tot_used; /* total number of servers used for LB */
|
||||
int wmult; /* ratio between user weight and effective weight */
|
||||
struct {
|
||||
struct server **srv; /* the server map used to apply weights */
|
||||
int rr_idx; /* next server to be elected in round robin mode */
|
||||
int state; /* PR_MAP_RECALC */
|
||||
} map; /* LB parameters for map-based algorithms */
|
||||
} lbprm; /* LB parameters for all algorithms */
|
||||
|
||||
char *cookie_name; /* name of the cookie to look for */
|
||||
int cookie_len; /* strlen(cookie_name), computed only once */
|
||||
char *url_param_name; /* name of the URL parameter used for hashing */
|
||||
|
@ -54,50 +54,77 @@
|
||||
void recount_servers(struct proxy *px)
|
||||
{
|
||||
struct server *srv;
|
||||
int first_bkw = 0;
|
||||
|
||||
px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0;
|
||||
px->srv_act = px->srv_bck = 0;
|
||||
px->lbprm.tot_wact = px->lbprm.tot_wbck = 0;
|
||||
for (srv = px->srv; srv != NULL; srv = srv->next) {
|
||||
if (srv->state & SRV_RUNNING) {
|
||||
if (srv->state & SRV_BACKUP) {
|
||||
px->srv_bck++;
|
||||
px->tot_wbck += srv->eweight;
|
||||
px->lbprm.tot_wbck += srv->eweight;
|
||||
if (px->srv_bck == 1)
|
||||
first_bkw = srv->eweight;
|
||||
} else {
|
||||
px->srv_act++;
|
||||
px->tot_wact += srv->eweight;
|
||||
px->lbprm.tot_wact += srv->eweight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (px->srv_act) {
|
||||
px->lbprm.tot_weight = px->lbprm.tot_wact;
|
||||
px->lbprm.tot_used = px->srv_act;
|
||||
}
|
||||
else if (px->srv_bck) {
|
||||
if (px->options & PR_O_USE_ALL_BK) {
|
||||
px->lbprm.tot_weight = px->lbprm.tot_wbck;
|
||||
px->lbprm.tot_used = px->srv_bck;
|
||||
}
|
||||
else { /* the first backup server is enough */
|
||||
px->lbprm.tot_weight = first_bkw;
|
||||
px->lbprm.tot_used = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
px->lbprm.tot_weight = 0;
|
||||
px->lbprm.tot_used = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This function recomputes the server map for proxy px. It
|
||||
* relies on px->tot_wact and px->tot_wbck, so it must be
|
||||
* called after recount_servers(). It also expects px->srv_map
|
||||
* to be initialized to the largest value needed.
|
||||
/* This function recomputes the server map for proxy px. It relies on
|
||||
* px->lbprm.tot_wact, tot_wbck, tot_used, tot_weight, so it must be
|
||||
* called after recount_servers(). It also expects px->lbprm.map.srv
|
||||
* to be allocated with the largest size needed. It updates tot_weight.
|
||||
*/
|
||||
void recalc_server_map(struct proxy *px)
|
||||
{
|
||||
int o, tot, flag;
|
||||
struct server *cur, *best;
|
||||
|
||||
if (px->srv_act) {
|
||||
flag = SRV_RUNNING;
|
||||
tot = px->tot_wact;
|
||||
} else if (px->srv_bck) {
|
||||
flag = SRV_RUNNING | SRV_BACKUP;
|
||||
if (px->options & PR_O_USE_ALL_BK)
|
||||
tot = px->tot_wbck;
|
||||
else
|
||||
tot = 1; /* the first server is enough */
|
||||
} else {
|
||||
px->srv_map_sz = 0;
|
||||
px->map_state &= ~PR_MAP_RECALC;
|
||||
switch (px->lbprm.tot_used) {
|
||||
case 0: /* no server */
|
||||
px->lbprm.map.state &= ~PR_MAP_RECALC;
|
||||
return;
|
||||
case 1: /* only one server, just fill first entry */
|
||||
tot = 1;
|
||||
break;
|
||||
default:
|
||||
tot = px->lbprm.tot_weight;
|
||||
break;
|
||||
}
|
||||
|
||||
/* here we *know* that we have some servers */
|
||||
if (px->srv_act)
|
||||
flag = SRV_RUNNING;
|
||||
else
|
||||
flag = SRV_RUNNING | SRV_BACKUP;
|
||||
|
||||
/* this algorithm gives priority to the first server, which means that
|
||||
* it will respect the declaration order for equivalent weights, and
|
||||
* that whatever the weights, the first server called will always be
|
||||
* the first declard. This is an important asumption for the backup
|
||||
* the first declared. This is an important asumption for the backup
|
||||
* case, where we want the first server only.
|
||||
*/
|
||||
for (cur = px->srv; cur; cur = cur->next)
|
||||
@ -116,6 +143,7 @@ void recalc_server_map(struct proxy *px)
|
||||
*/
|
||||
if (tot == 1) {
|
||||
best = cur;
|
||||
/* note that best->wscore will be wrong but we don't care */
|
||||
break;
|
||||
}
|
||||
|
||||
@ -127,11 +155,10 @@ void recalc_server_map(struct proxy *px)
|
||||
}
|
||||
}
|
||||
}
|
||||
px->srv_map[o] = best;
|
||||
px->lbprm.map.srv[o] = best;
|
||||
best->wscore -= tot;
|
||||
}
|
||||
px->srv_map_sz = tot;
|
||||
px->map_state &= ~PR_MAP_RECALC;
|
||||
px->lbprm.map.state &= ~PR_MAP_RECALC;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -150,12 +177,12 @@ struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
|
||||
char *p;
|
||||
int plen;
|
||||
|
||||
if (px->map_state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
if (px->srv_map_sz == 0)
|
||||
if (px->lbprm.tot_weight == 0)
|
||||
return NULL;
|
||||
|
||||
if (px->lbprm.map.state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
p = memchr(uri, '?', uri_len);
|
||||
if (!p)
|
||||
return NULL;
|
||||
@ -183,7 +210,7 @@ struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
|
||||
uri_len--;
|
||||
p++;
|
||||
}
|
||||
return px->srv_map[hash % px->srv_map_sz];
|
||||
return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2652,6 +2652,8 @@ int readcfgfile(const char *file)
|
||||
curproxy->srv = next;
|
||||
}
|
||||
|
||||
curproxy->lbprm.wmult = 1; /* default weight multiplier */
|
||||
|
||||
/* now, newsrv == curproxy->srv */
|
||||
if (newsrv) {
|
||||
struct server *srv;
|
||||
@ -2673,6 +2675,12 @@ int readcfgfile(const char *file)
|
||||
}
|
||||
}
|
||||
|
||||
/* It is sometimes useful to know what factor to apply
|
||||
* to the backend's effective weight to know its real
|
||||
* weight.
|
||||
*/
|
||||
curproxy->lbprm.wmult = pgcd;
|
||||
|
||||
act = bck = 0;
|
||||
for (srv = newsrv; srv; srv = srv->next) {
|
||||
srv->eweight = srv->uweight / pgcd;
|
||||
@ -2686,9 +2694,9 @@ int readcfgfile(const char *file)
|
||||
if (act < bck)
|
||||
act = bck;
|
||||
|
||||
curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
|
||||
curproxy->lbprm.map.srv = (struct server **)calloc(act, sizeof(struct server *));
|
||||
/* recounts servers and their weights */
|
||||
curproxy->map_state = PR_MAP_RECALC;
|
||||
curproxy->lbprm.map.state = PR_MAP_RECALC;
|
||||
recount_servers(curproxy);
|
||||
recalc_server_map(curproxy);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ static void set_server_down(struct server *s)
|
||||
s->state &= ~SRV_RUNNING;
|
||||
|
||||
recount_servers(s->proxy);
|
||||
s->proxy->map_state |= PR_MAP_RECALC;
|
||||
s->proxy->lbprm.map.state |= PR_MAP_RECALC;
|
||||
|
||||
/* we might have sessions queued on this server and waiting for
|
||||
* a connection. Those which are redispatchable will be queued
|
||||
@ -479,7 +479,7 @@ void process_chk(struct task *t, struct timeval *next)
|
||||
}
|
||||
|
||||
recount_servers(s->proxy);
|
||||
s->proxy->map_state |= PR_MAP_RECALC;
|
||||
s->proxy->lbprm.map.state |= PR_MAP_RECALC;
|
||||
|
||||
/* check if we can handle some connections queued at the proxy. We
|
||||
* will take as many as we can handle.
|
||||
|
@ -842,18 +842,6 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
case DATA_ST_PX_BE:
|
||||
/* print the backend */
|
||||
if (px->cap & PR_CAP_BE) {
|
||||
int gcd = 1;
|
||||
|
||||
if (px->map_state & PR_MAP_RECALC)
|
||||
recalc_server_map(px);
|
||||
|
||||
/* The GCD which was computed causes the total effective
|
||||
* weight to appear lower than all weights. Let's
|
||||
* recompute it.
|
||||
*/
|
||||
if (px->srv && px->srv->eweight)
|
||||
gcd = px->srv->uweight / px->srv->eweight;
|
||||
|
||||
if (flags & STAT_FMT_HTML) {
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
/* name */
|
||||
@ -883,8 +871,9 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
px->failed_conns, px->failed_resp,
|
||||
px->retries, px->redispatches,
|
||||
human_time(now.tv_sec - px->last_change, 1),
|
||||
(px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
|
||||
px->srv_map_sz * gcd, px->srv_act, px->srv_bck);
|
||||
(px->lbprm.tot_weight > 0 || !px->srv) ? "UP" : "DOWN",
|
||||
px->lbprm.tot_weight * px->lbprm.wmult,
|
||||
px->srv_act, px->srv_bck);
|
||||
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
/* rest of backend: nothing, down transformations, total downtime */
|
||||
@ -928,10 +917,11 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
px->denied_req, px->denied_resp,
|
||||
px->failed_conns, px->failed_resp,
|
||||
px->retries, px->redispatches,
|
||||
(px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
|
||||
px->srv_map_sz * gcd, px->srv_act, px->srv_bck,
|
||||
(px->lbprm.tot_weight > 0 || !px->srv) ? "UP" : "DOWN",
|
||||
px->lbprm.tot_weight * px->lbprm.wmult,
|
||||
px->srv_act, px->srv_bck,
|
||||
px->down_trans, now.tv_sec - px->last_change,
|
||||
px->srv?be_downtime(px):0,
|
||||
px->srv?be_downtime(px):0,
|
||||
relative_pid, px->uuid);
|
||||
}
|
||||
if (buffer_write_chunk(rep, &msg) != 0)
|
||||
|
Loading…
Reference in New Issue
Block a user