]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: config: don't enforce a low frontend maxconn value anymore
authorWilly Tarreau <w@1wt.eu>
Wed, 27 Feb 2019 16:25:52 +0000 (17:25 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 28 Feb 2019 16:05:32 +0000 (17:05 +0100)
Historically the default frontend's maxconn used to be quite low (2000),
which was sufficient two decades ago but often proved to be a problem
when users had purposely set the global maxconn value but forgot to set
the frontend's.

There is no point in keeping this arbitrary limit for frontends : when
the global maxconn is lower, it's already too high and when the global
maxconn is much higher, it becomes a limiting factor which causes trouble
in production.

This commit allows the value to be set to zero, which becomes the new
default value, to mean it's not directly limited, or in fact it's set
to the global maxconn. Since this operation used to be performed before
computing a possibly automatic global maxconn based on memory limits,
the calculation of the maxconn value and its propagation to the backends'
fullconn has now moved to a dedicated function, proxy_adjust_all_maxconn(),
which is called once the global maxconn is stabilized.

This comes with two benefits :
  1) a configuration missing "maxconn" in the defaults section will not
     limit itself to a magically hardcoded value but will scale up to the
     global maxconn ;

  2) when the global maxconn is not set and memory limits are used instead,
     the frontends' maxconn automatically adapts, and the backends' fullconn
     as well.

doc/configuration.txt
include/proto/proxy.h
src/cfgparse.c
src/haproxy.c
src/proxy.c

index 85b687eb644651067b789f3550f3b5ae973f37e7..3e49d0e9835671a0ca061c2137890edb272da0ea 100644 (file)
@@ -5481,7 +5481,8 @@ maxconn <conns>
   are not sized to accept such loads, and for this reason it is generally wise
   to assign them some reasonable connection limits.
 
-  By default, this value is set to 2000.
+  When this value is set to zero, which is the default, the global "maxconn"
+  value is used.
 
   See also : "server", global section's "maxconn", "fullconn"
 
index 782372efced02cc5b3ec9480e8ea4fcaebd2dc47..7bd942109650d1da9758ca972a0fb1c2119b73bd 100644 (file)
@@ -68,6 +68,7 @@ void proxy_capture_error(struct proxy *proxy, int is_back,
                         unsigned int buf_out, unsigned int err_pos,
                         const union error_snapshot_ctx *ctx,
                         void (*show)(struct buffer *, const struct error_snapshot *));
+void proxy_adjust_all_maxconn();
 struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
 struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg);
 
index e29ab9764660a4c3a84e2e8a4d1abcc3f6064cd8..1a03d97ec75104423e7587de64e81718219b0535 100644 (file)
@@ -125,7 +125,7 @@ struct list postparsers = LIST_HEAD_INIT(postparsers);
 
 char *cursection = NULL;
 struct proxy defproxy = { };           /* fake proxy used to assign default values on all instances */
-int cfg_maxpconn = DEFAULT_MAXCONN;    /* # of simultaneous connections per proxy (-N) */
+int cfg_maxpconn = 0;                   /* # of simultaneous connections per proxy (-N) */
 int cfg_maxconn = 0;                   /* # of simultaneous connections, (-n) */
 char *cfg_scope = NULL;                 /* the current scope during the configuration parsing */
 
@@ -2524,8 +2524,6 @@ 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) {
                                        ha_warning("In proxy '%s', the 'default_backend' rule always has precedence over the servers, which will never be used.\n",
@@ -2535,14 +2533,6 @@ 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;
@@ -2611,23 +2601,6 @@ 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;
-                                               }
-                                       }
-                               }
                        }
                }
 
@@ -3817,24 +3790,6 @@ out_uri_auth_compat:
                }
        }
 
-       /* automatically compute fullconn if not set. We must not do it in the
-        * loop above because cross-references are not yet fully resolved.
-        */
-       for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
-               /* If <fullconn> is not set, let's set it to 10% of the sum of
-                * the possible incoming frontend's maxconns.
-                */
-               if (!curproxy->fullconn && (curproxy->cap & PR_CAP_BE)) {
-                       /* 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 = (curproxy->tot_fe_maxconn + 9) / 10;
-                       if (!curproxy->fullconn)
-                               curproxy->fullconn = 1;
-               }
-       }
-
        /*
         * Recount currently required checks.
         */
index 942c075976b7e3b967e7525ab4b23a43749f50ac..59da1fda6904b533a3fdeb7db19f5df5be49a5e5 100644 (file)
@@ -2069,6 +2069,8 @@ static void init(int argc, char **argv)
                                global.maxsock += p->peers_fe->maxconn;
        }
 
+       proxy_adjust_all_maxconn();
+
        if (global.tune.maxpollevents <= 0)
                global.tune.maxpollevents = MAX_POLL_EVENTS;
 
index 7f442b9da9834c1bddd10a47bbf79366149ac152..e60b34a2181675598d544daf7cf935eab85de035 100644 (file)
@@ -1488,6 +1488,75 @@ void proxy_capture_error(struct proxy *proxy, int is_back,
        HA_SPIN_UNLOCK(PROXY_LOCK, &proxy->lock);
 }
 
+/* Configure all proxies which lack a maxconn setting to use the global one by
+ * default. This avoids the common mistake consisting in setting maxconn only
+ * in the global section and discovering the hard way that it doesn't propagate
+ * through the frontends. These values are also propagated through the various
+ * targetted backends, whose fullconn is finally calculated if not yet set.
+ */
+void proxy_adjust_all_maxconn()
+{
+       struct proxy *curproxy;
+       struct switching_rule *swrule1, *swrule2;
+
+       for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
+               if (curproxy->state == PR_STSTOPPED)
+                       continue;
+
+               if (!(curproxy->cap & PR_CAP_FE))
+                       continue;
+
+               if (!curproxy->maxconn)
+                       curproxy->maxconn = global.maxconn;
+
+               /* update the target backend's fullconn count : default_backend */
+               if (curproxy->defbe.be)
+                       curproxy->defbe.be->tot_fe_maxconn += curproxy->maxconn;
+               else if ((curproxy->cap & PR_CAP_LISTEN) == PR_CAP_LISTEN)
+                       curproxy->tot_fe_maxconn += curproxy->maxconn;
+
+               list_for_each_entry(swrule1, &curproxy->switching_rules, list) {
+                       /* For each target of switching rules, we update their
+                        * tot_fe_maxconn, except if a previous rule points to
+                        * the same backend or to the default backend.
+                        */
+                       if (swrule1->be.backend != curproxy->defbe.be) {
+                               list_for_each_entry(swrule2, &curproxy->switching_rules, list) {
+                                       if (swrule2 == swrule1) {
+                                               swrule1->be.backend->tot_fe_maxconn += curproxy->maxconn;
+                                               break;
+                                       }
+                                       else if (!swrule2->dynamic && swrule2->be.backend == swrule1->be.backend) {
+                                               /* there are multiple refs of this backend */
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* automatically compute fullconn if not set. We must not do it in the
+        * loop above because cross-references are not yet fully resolved.
+        */
+       for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
+               if (curproxy->state == PR_STSTOPPED)
+                       continue;
+
+               /* If <fullconn> is not set, let's set it to 10% of the sum of
+                * the possible incoming frontend's maxconns.
+                */
+               if (!curproxy->fullconn && (curproxy->cap & PR_CAP_BE)) {
+                       /* 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 = (curproxy->tot_fe_maxconn + 9) / 10;
+                       if (!curproxy->fullconn)
+                               curproxy->fullconn = 1;
+               }
+       }
+}
+
 /* Config keywords below */
 
 static struct cfg_kw_list cfg_kws = {ILH, {