[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.
This commit is contained in:
Willy Tarreau 2009-02-04 22:05:05 +01:00
parent c76721da57
commit 0b9c02c861
4 changed files with 113 additions and 0 deletions

View 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

View 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 {

View 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;
}
}

View 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 */