From 3f78357066288c386709fc9439d56b5d36fe3f35 Mon Sep 17 00:00:00 2001 From: Emeric Brun Date: Thu, 12 Jan 2017 11:21:28 +0100 Subject: [PATCH] OPTIM/MINOR: config: Optimize fullconn automatic computation loading configuration The previous version used an O(number of proxies)^2 algo to get the sum of the number of maxconns of frontends which reference a backend at least once. This new version adds the frontend's maxconn number to the backend's struct proxy member 'tot_fe_maxconn' when the backend name is resolved for switching rules or default_backend statment. At the end, the final backend's fullconn is computed looping only one time for all on proxies O(n). The load of a configuration using a large amount of backends (10 thousands) without configured fullconn was reduced from several minutes to few seconds. --- include/types/proxy.h | 1 + src/cfgparse.c | 67 ++++++++++++++++++------------------------- 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/include/types/proxy.h b/include/types/proxy.h index 3bf5a4d46c..3f848a0dc7 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -326,6 +326,7 @@ struct proxy { struct freq_ctr be_sess_per_sec; /* sessions per second on the backend */ unsigned int fe_sps_lim; /* limit on new sessions per second on the frontend */ unsigned int fullconn; /* #conns on backend above which servers are used at full load */ + unsigned int tot_fe_maxconn; /* #maxconn of frontends linked to that backend, it is used to compute fullconn */ struct in_addr except_net, except_mask; /* don't x-forward-for for this address. FIXME: should support IPv6 */ struct in_addr except_to; /* don't x-original-to for this address. */ struct in_addr except_mask_to; /* the netmask for except_to. */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 13f8983f34..bafd05133d 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -7542,7 +7542,8 @@ int check_config_validity() } else { free(curproxy->defbe.name); curproxy->defbe.be = target; - + /* Update tot_fe_maxconn for a further fullconn's computation */ + target->tot_fe_maxconn += curproxy->maxconn; /* Emit a warning if this proxy also has some servers */ if (curproxy->srv) { Warning("In proxy '%s', the 'default_backend' rule always has precedence over the servers, which will never be used.\n", @@ -7552,6 +7553,14 @@ int check_config_validity() } } + if (!curproxy->defbe.be && (curproxy->cap & PR_CAP_LISTEN) == PR_CAP_LISTEN) { + /* Case of listen without default backend + * The curproxy will be its own default backend + * so we update tot_fe_maxconn for a further + * fullconn's computation */ + curproxy->tot_fe_maxconn += curproxy->maxconn; + } + /* find the target proxy for 'use_backend' rules */ list_for_each_entry(rule, &curproxy->switching_rules, list) { struct proxy *target; @@ -7613,6 +7622,23 @@ int check_config_validity() } else { free((void *)rule->be.name); rule->be.backend = target; + /* For each target of switching rules, we update + * their tot_fe_maxconn, except if a previous rule point + * on the same backend or on the default backend */ + if (rule->be.backend != curproxy->defbe.be) { + struct switching_rule *swrule; + + list_for_each_entry(swrule, &curproxy->switching_rules, list) { + if (rule == swrule) { + target->tot_fe_maxconn += curproxy->maxconn; + break; + } + else if (!swrule->dynamic && swrule->be.backend == rule->be.backend) { + /* there is multiple ref of this backend */ + break; + } + } + } } } @@ -8869,48 +8895,11 @@ out_uri_auth_compat: * the possible incoming frontend's maxconns. */ if (!curproxy->fullconn && (curproxy->cap & PR_CAP_BE)) { - struct proxy *fe; - int total = 0; - - /* sum up the number of maxconns of frontends which - * reference this backend at least once or which are - * the same one ('listen'). - */ - for (fe = proxy; fe; fe = fe->next) { - struct switching_rule *rule; - int found = 0; - - if (!(fe->cap & PR_CAP_FE)) - continue; - - if (fe == curproxy) /* we're on a "listen" instance */ - found = 1; - - if (fe->defbe.be == curproxy) /* "default_backend" */ - found = 1; - - /* check if a "use_backend" rule matches */ - if (!found) { - list_for_each_entry(rule, &fe->switching_rules, list) { - if (!rule->dynamic && rule->be.backend == curproxy) { - found = 1; - break; - } - } - } - - /* now we've checked all possible ways to reference a backend - * from a frontend. - */ - if (!found) - continue; - total += fe->maxconn; - } /* we have the sum of the maxconns in . We only * keep 10% of that sum to set the default fullconn, with * a hard minimum of 1 (to avoid a divide by zero). */ - curproxy->fullconn = (total + 9) / 10; + curproxy->fullconn = (curproxy->tot_fe_maxconn + 9) / 10; if (!curproxy->fullconn) curproxy->fullconn = 1; } -- 2.47.3