From 0b9c02c861c7795f5aa27d25efd2dbeb31a3ac6c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 4 Feb 2009 22:05:05 +0100 Subject: [PATCH] [MEDIUM] implement bind-process to limit service presence by process 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 | 52 +++++++++++++++++++++++++++++++++++++++++++ include/types/proxy.h | 1 + src/cfgparse.c | 49 ++++++++++++++++++++++++++++++++++++++++ src/haproxy.c | 11 +++++++++ 4 files changed, 113 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index fd62ef1e85..b410a23d24 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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 [
]: [, ...] transparent See also : "source". +bind-process [ all | odd | even | ] ... + 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 } Block a layer 7 request if/unless a condition is matched May be used in sections : defaults | frontend | listen | backend diff --git a/include/types/proxy.h b/include/types/proxy.h index cc5069007a..2f67791508 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -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 { diff --git a/src/cfgparse.c b/src/cfgparse.c index 5136e9471e..e427a6ffdf 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -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; } } diff --git a/src/haproxy.c b/src/haproxy.c index dbb074d298..cc6864ea49 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -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 */ -- 2.39.5