From: Willy Tarreau Date: Tue, 24 Jul 2007 21:32:33 +0000 (+0200) Subject: [MEDIUM] improve behaviour with large number of servers per proxy X-Git-Tag: v1.3.13~48 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5af3a694f5278793685a102fa8e33974bc608443;p=thirdparty%2Fhaproxy.git [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. --- diff --git a/include/proto/backend.h b/include/proto/backend.h index f0295b0f5e..467e756806 100644 --- a/include/proto/backend.h +++ b/include/proto/backend.h @@ -52,6 +52,9 @@ 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) 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) { + if (px->map_state & PR_MAP_RECALC) + recalc_server_map(px); + if (px->srv_map_sz == 0) 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, * 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) { unsigned int h, l; + if (px->map_state & PR_MAP_RECALC) + recalc_server_map(px); + if (px->srv_map_sz == 0) return NULL; @@ -133,6 +142,9 @@ 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) return NULL; diff --git a/include/types/proxy.h b/include/types/proxy.h index 6d87f806da..d205c42d02 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -53,6 +53,9 @@ #define PR_MODE_HTTP 1 #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 */ #define PR_CAP_NONE 0x0000 #define PR_CAP_FE 0x0001 @@ -86,6 +89,7 @@ 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 */ diff --git a/src/backend.c b/src/backend.c index 8abaf1ca5e..da8b8ac36a 100644 --- a/src/backend.c +++ b/src/backend.c @@ -90,6 +90,7 @@ void recalc_server_map(struct proxy *px) tot = 1; /* the first server is enough */ } else { px->srv_map_sz = 0; + px->map_state &= ~PR_MAP_RECALC; return; } @@ -130,6 +131,7 @@ void recalc_server_map(struct proxy *px) best->wscore -= tot; } px->srv_map_sz = tot; + px->map_state &= ~PR_MAP_RECALC; } diff --git a/src/cfgparse.c b/src/cfgparse.c index 39abbc318a..967b9ca74d 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2637,6 +2637,7 @@ int readcfgfile(const char *file) curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *)); /* recounts servers and their weights */ + curproxy->map_state = PR_MAP_RECALC; recount_servers(curproxy); recalc_server_map(curproxy); } diff --git a/src/checks.c b/src/checks.c index 4c8a009718..2c581ef1c8 100644 --- a/src/checks.c +++ b/src/checks.c @@ -46,7 +46,8 @@ /* Sets server down, notifies by all available means, recounts the * 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) { @@ -58,7 +59,7 @@ static void set_server_down(struct server *s) if (s->health == s->rise) { 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 * a connection. Those which are redispatchable will be queued @@ -454,7 +455,7 @@ void process_chk(struct task *t, struct timeval *next) int xferred; 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 * will take as many as we can handle. diff --git a/src/proto_http.c b/src/proto_http.c index 9044d5d0a2..f717bdf326 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3848,6 +3848,9 @@ int produce_content_stats_proxy(struct session *s, struct proxy *px) case DATA_ST_PX_BE: /* print the backend */ if (px->cap & PR_CAP_BE) { + if (px->map_state & PR_MAP_RECALC) + recalc_server_map(px); + chunk_printf(&msg, sizeof(trash), /* name */ "Backend"