]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
OPTIM/MINOR: config: Optimize fullconn automatic computation loading configuration
authorEmeric Brun <ebrun@haproxy.com>
Thu, 12 Jan 2017 10:21:28 +0000 (11:21 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 12 Jan 2017 16:36:09 +0000 (17:36 +0100)
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
src/cfgparse.c

index 3bf5a4d46ce85c8460d1a2705a03b5bd4a13fd2d..3f848a0dc7bce53aa78147e27a8f31f337c28c7c 100644 (file)
@@ -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. */
index 13f8983f343d46d53f80059c1016a221facd4dd1..bafd05133d4c21f9c1c0566ea6aa38fc6f69568d 100644 (file)
@@ -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 <total>. 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;
                }