]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] implement bind-process to limit service presence by process
authorWilly Tarreau <w@1wt.eu>
Wed, 4 Feb 2009 21:05:05 +0000 (22:05 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Feb 2009 21:05:05 +0000 (22:05 +0100)
The "bind-process" keyword lets the admin select which instances may
run on which process (in multi-process mode). It makes it easier to
more evenly distribute the load across multiple processes by avoiding
having too many listen to the same IP:ports.

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

index fd62ef1e85116b6b49ebf9d5cc70954e2ee868b9..b410a23d24994cacc5fc5dcf18a5860299678517 100644 (file)
@@ -523,6 +523,7 @@ appsession                  -          -         X         X
 backlog                     X          X         X         -
 balance                     X          -         X         X   
 bind                        -          X         X         -   
+bind-process                X          X         X         X   
 block                       -          X         X         X
 capture cookie              -          X         X         -
 capture request header      -          X         X         -
@@ -903,6 +904,57 @@ bind [<address>]:<port> [, ...] transparent
   See also : "source".
 
 
+bind-process [ all | odd | even | <number 1-32> ] ...
+  Limit visibility of an instance to a certain set of processes numbers.
+  May be used in sections :   defaults | frontend | listen | backend
+                                 yes   |    yes   |   yes  |   yes
+  Arguments :
+    all           All process will see this instance. This is the default. It
+                  may be used to override a default value.
+
+    odd           This instance will be enabled on processes 1,3,5,...31. This
+                  option may be combined with other numbers.
+
+    even          This instance will be enabled on processes 2,4,6,...32. This
+                  option may be combined with other numbers. Do not use it
+                  with less than 2 processes otherwise some instances might be
+                  missing from all processes.
+
+    number        The instance will be enabled on this process number, between
+                  1 and 32. You must be careful not to reference a process
+                  number greater than the configured global.nbproc, otherwise
+                  some instances might be missing from all processes.
+
+  This keyword limits binding of certain instances to certain processes. This
+  is useful in order not to have too many processes listening to the same
+  ports. For instance, on a dual-core machine, it might make sense to set
+  'nbproc 2' in the global section, then distributes the listeners among 'odd'
+  and 'even' instances.
+
+  At the moment, it is not possible to reference more than 32 processes using
+  this keyword, but this should be more than enough for most setups. Please
+  note that 'all' really means all processes and is not limited to the first
+  32.
+
+  If some backends are referenced by frontends bound to other processes, the
+  backend automatically inherits the frontend's processes.
+
+  Example :
+        listen app_ip1
+            bind 10.0.0.1:80
+            bind_process odd
+
+        listen app_ip2
+            bind 10.0.0.2:80
+            bind_process even
+
+        listen management
+            bind 10.0.0.3:80
+            bind_process 1 2 3 4
+
+  See also : "nbproc" in global section.
+
+
 block { if | unless } <condition>
   Block a layer 7 request if/unless a condition is matched
   May be used in sections :   defaults | frontend | listen | backend
index cc5069007afc8a9c6259be8cc621133e5969766e..2f6779150887f056f94034c50a1b2e5b26c6219e 100644 (file)
@@ -258,6 +258,7 @@ struct proxy {
        int uuid;                               /* universally unique proxy ID, used for SNMP */
        int next_svid;                          /* next server-id, used for SNMP */
        unsigned int backlog;                   /* force the frontend's listen backlog */
+       unsigned int bind_proc;                 /* bitmask of processes using this proxy. 0 = all. */
 };
 
 struct switching_rule {
index 5136e9471e1d9c5c587bc63e74a9e60849107ae1..e427a6ffdfb965f312132a4b6caf2b12683ea65b 100644 (file)
@@ -668,6 +668,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
                curproxy->state = defproxy.state;
                curproxy->options = defproxy.options;
                curproxy->options2 = defproxy.options2;
+               curproxy->bind_proc = defproxy.bind_proc;
                curproxy->lbprm.algo = defproxy.lbprm.algo;
                curproxy->except_net = defproxy.except_net;
                curproxy->except_mask = defproxy.except_mask;
@@ -930,6 +931,39 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
        else if (!strcmp(args[0], "enabled")) {  /* enables this proxy (used to revert a disabled default) */
                curproxy->state = PR_STNEW;
        }
+       else if (!strcmp(args[0], "bind-process")) {  /* enable this proxy only on some processes */
+               int cur_arg = 1;
+               unsigned int set = 0;
+
+               while (*args[cur_arg]) {
+                       int u;
+                       if (strcmp(args[cur_arg], "all") == 0) {
+                               set = 0;
+                               break;
+                       }
+                       else if (strcmp(args[cur_arg], "odd") == 0) {
+                               set |= 0x55555555;
+                       }
+                       else if (strcmp(args[cur_arg], "even") == 0) {
+                               set |= 0xAAAAAAAA;
+                       }
+                       else {
+                               u = str2uic(args[cur_arg]);
+                               if (u < 1 || u > 32) {
+                                       Alert("parsing [%s:%d]: %s expects 'all', 'odd', 'even', or process numbers from 1 to 32.\n",
+                                             file, linenum, args[0]);
+                                       return -1;
+                               }
+                               if (u > global.nbproc) {
+                                       Warning("parsing [%s:%d]: %s references process number higher than global.nbproc.\n",
+                                               file, linenum, args[0]);
+                               }
+                               set |= 1 << (u - 1);
+                       }
+                       cur_arg++;
+               }
+               curproxy->bind_proc = set;
+       }
        else if (!strcmp(args[0], "acl")) {  /* add an ACL */
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
@@ -3168,6 +3202,11 @@ int readcfgfile(const char *file)
                        } else {
                                free(curproxy->defbe.name);
                                curproxy->defbe.be = target;
+                               /* we force the backend to be present on at least all of
+                                * the frontend's processes.
+                                */
+                               target->bind_proc = curproxy->bind_proc ?
+                                       (target->bind_proc | curproxy->bind_proc) : 0;
                        }
                }
 
@@ -3193,6 +3232,11 @@ int readcfgfile(const char *file)
                                } else {
                                        free((void *)exp->replace);
                                        exp->replace = (const char *)target;
+                                       /* we force the backend to be present on at least all of
+                                        * the frontend's processes.
+                                        */
+                                       target->bind_proc = curproxy->bind_proc ?
+                                               (target->bind_proc | curproxy->bind_proc) : 0;
                                }
                        }
                }
@@ -3214,6 +3258,11 @@ int readcfgfile(const char *file)
                        } else {
                                free((void *)rule->be.name);
                                rule->be.backend = target;
+                               /* we force the backend to be present on at least all of
+                                * the frontend's processes.
+                                */
+                               target->bind_proc = curproxy->bind_proc ?
+                                       (target->bind_proc | curproxy->bind_proc) : 0;
                        }
                }
 
index dbb074d29843f35dc9c105fe611b8dff65b599bb..cc6864ea4947e48d62cc6ca1baa79f972a9f11b4 100644 (file)
@@ -1106,6 +1106,7 @@ int main(int argc, char **argv)
        }
 
        if (global.mode & MODE_DAEMON) {
+               struct proxy *px;
                int ret = 0;
                int proc;
 
@@ -1131,6 +1132,16 @@ int main(int argc, char **argv)
                free(global.pidfile);
                global.pidfile = NULL;
 
+               /* we might have to unbind some proxies from some processes */
+               px = proxy;
+               while (px != NULL) {
+                       if (px->bind_proc && px->state != PR_STSTOPPED) {
+                               if (!(px->bind_proc & (1 << proc)))
+                                       stop_proxy(px);
+                       }
+                       px = px->next;
+               }
+
                if (proc == global.nbproc)
                        exit(0); /* parent must leave */