[MEDIUM] improve behaviour with large number of servers per proxy

When a very large number of servers is configured (thousands),
shutting down many of them at once could lead to large number
of calls to recalc_server_map() which already takes some time.
This would result in an O(N^3) computation time, leading to
noticeable pauses on slow embedded CPUs on test platforms.

Instead, mark the map as dirty and recalc it only when needed.
This commit is contained in:
Willy Tarreau 2007-07-24 23:32:33 +02:00
parent 632f5a7b6f
commit 5af3a694f5
6 changed files with 27 additions and 4 deletions

View File

@ -52,6 +52,9 @@ static inline struct server *get_server_rr_with_conns(struct proxy *px)
int newidx; int newidx;
struct server *srv; struct server *srv;
if (px->map_state & PR_MAP_RECALC)
recalc_server_map(px);
if (px->srv_map_sz == 0) if (px->srv_map_sz == 0)
return NULL; return NULL;
@ -81,6 +84,9 @@ static inline struct server *get_server_rr_with_conns(struct proxy *px)
*/ */
static inline struct server *get_server_rr(struct proxy *px) 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->srv_map_sz == 0)
return NULL; return NULL;
@ -97,11 +103,14 @@ static inline struct server *get_server_rr(struct proxy *px)
* If any server is found, it will be returned. If no valid server is found, * If any server is found, it will be returned. If no valid server is found,
* NULL is returned. * NULL is returned.
*/ */
static inline struct server *get_server_sh(const struct proxy *px, static inline struct server *get_server_sh(struct proxy *px,
const char *addr, int len) const char *addr, int len)
{ {
unsigned int h, l; unsigned int h, l;
if (px->map_state & PR_MAP_RECALC)
recalc_server_map(px);
if (px->srv_map_sz == 0) if (px->srv_map_sz == 0)
return NULL; return NULL;
@ -133,6 +142,9 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_
unsigned long hash = 0; unsigned long hash = 0;
int c; int c;
if (px->map_state & PR_MAP_RECALC)
recalc_server_map(px);
if (px->srv_map_sz == 0) if (px->srv_map_sz == 0)
return NULL; return NULL;

View File

@ -53,6 +53,9 @@
#define PR_MODE_HTTP 1 #define PR_MODE_HTTP 1
#define PR_MODE_HEALTH 2 #define PR_MODE_HEALTH 2
/* values for proxy->map_state */
#define PR_MAP_RECALC (1 << 0)
/* flag values for proxy->cap. This is a bitmask of capabilities supported by the proxy */ /* flag values for proxy->cap. This is a bitmask of capabilities supported by the proxy */
#define PR_CAP_NONE 0x0000 #define PR_CAP_NONE 0x0000
#define PR_CAP_FE 0x0001 #define PR_CAP_FE 0x0001
@ -86,6 +89,7 @@ struct proxy {
struct list acl; /* ACL declared on this proxy */ struct list acl; /* ACL declared on this proxy */
struct list block_cond; /* early blocking conditions (chained) */ struct list block_cond; /* early blocking conditions (chained) */
struct list switching_rules; /* content switching rules (chained) */ struct list switching_rules; /* content switching rules (chained) */
int map_state; /* PR_MAP_RECALC */
struct server *srv; /* known servers */ struct server *srv; /* known servers */
int srv_act, srv_bck; /* # of running servers */ int srv_act, srv_bck; /* # of running servers */
int tot_wact, tot_wbck; /* total weights of active and backup servers */ int tot_wact, tot_wbck; /* total weights of active and backup servers */

View File

@ -90,6 +90,7 @@ void recalc_server_map(struct proxy *px)
tot = 1; /* the first server is enough */ tot = 1; /* the first server is enough */
} else { } else {
px->srv_map_sz = 0; px->srv_map_sz = 0;
px->map_state &= ~PR_MAP_RECALC;
return; return;
} }
@ -130,6 +131,7 @@ void recalc_server_map(struct proxy *px)
best->wscore -= tot; best->wscore -= tot;
} }
px->srv_map_sz = tot; px->srv_map_sz = tot;
px->map_state &= ~PR_MAP_RECALC;
} }

View File

@ -2637,6 +2637,7 @@ int readcfgfile(const char *file)
curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *)); curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *));
/* recounts servers and their weights */ /* recounts servers and their weights */
curproxy->map_state = PR_MAP_RECALC;
recount_servers(curproxy); recount_servers(curproxy);
recalc_server_map(curproxy); recalc_server_map(curproxy);
} }

View File

@ -46,7 +46,8 @@
/* Sets server <s> down, notifies by all available means, recounts the /* Sets server <s> down, notifies by all available means, recounts the
* remaining servers on the proxy and transfers queued sessions whenever * remaining servers on the proxy and transfers queued sessions whenever
* possible to other servers. * possible to other servers. It automatically recomputes the number of
* servers, but not the map.
*/ */
static void set_server_down(struct server *s) static void set_server_down(struct server *s)
{ {
@ -58,7 +59,7 @@ static void set_server_down(struct server *s)
if (s->health == s->rise) { if (s->health == s->rise) {
recount_servers(s->proxy); recount_servers(s->proxy);
recalc_server_map(s->proxy); s->proxy->map_state |= PR_MAP_RECALC;
/* we might have sessions queued on this server and waiting for /* we might have sessions queued on this server and waiting for
* a connection. Those which are redispatchable will be queued * a connection. Those which are redispatchable will be queued
@ -454,7 +455,7 @@ void process_chk(struct task *t, struct timeval *next)
int xferred; int xferred;
recount_servers(s->proxy); recount_servers(s->proxy);
recalc_server_map(s->proxy); s->proxy->map_state |= PR_MAP_RECALC;
/* check if we can handle some connections queued at the proxy. We /* check if we can handle some connections queued at the proxy. We
* will take as many as we can handle. * will take as many as we can handle.

View File

@ -3848,6 +3848,9 @@ int produce_content_stats_proxy(struct session *s, struct proxy *px)
case DATA_ST_PX_BE: case DATA_ST_PX_BE:
/* print the backend */ /* print the backend */
if (px->cap & PR_CAP_BE) { if (px->cap & PR_CAP_BE) {
if (px->map_state & PR_MAP_RECALC)
recalc_server_map(px);
chunk_printf(&msg, sizeof(trash), chunk_printf(&msg, sizeof(trash),
/* name */ /* name */
"<tr align=center class=\"backend\"><td>Backend</td>" "<tr align=center class=\"backend\"><td>Backend</td>"