MINOR: server: add a max-reuse parameter

Some servers may wish to limit the total number of requests they execute
over a connection because some of their components might leak resources.
In HTTP/1 it was easy, they just had to emit a "connection: close" header
field with the last response. In HTTP/2, it's less easy because the info
is not always shared with the component dealing with the H2 protocol and
it could be harder to advertise a GOAWAY with a stream limit.

This patch provides a solution to this by adding a new "max-reuse" parameter
to the server keyword. This parameter indicates how many times an idle
connection may be reused for new requests. The information is made available
and the underlying muxes will be able to use it at will.

This patch should be backported to 1.9.
This commit is contained in:
Willy Tarreau 2019-01-23 10:21:49 +01:00
parent 2c7deddc06
commit 9c538e01c2
4 changed files with 29 additions and 0 deletions

View File

@ -11826,6 +11826,16 @@ maxqueue <maxqueue>
default value is "0" which means the queue is unlimited. See also the default value is "0" which means the queue is unlimited. See also the
"maxconn" and "minconn" parameters. "maxconn" and "minconn" parameters.
max-reuse <count>
The "max-reuse" argument indicates the HTTP connection processors that they
should not reuse a server connection more than this number of times to send
new requests. Permitted values are -1 (the default), which disables this
limit, or any positive value. Value zero will effectively disable keep-alive.
This is only used to work around certain server bugs which cause them to leak
resources over time. The argument is not necessarily respected by the lower
layers as there might be technical limitations making it impossible to
enforce. At least HTTP/2 connections to servers will respect it.
minconn <minconn> minconn <minconn>
When the "minconn" parameter is set, the maxconn limit becomes a dynamic When the "minconn" parameter is set, the maxconn limit becomes a dynamic
limit following the backend's load. The server will always accept at least limit following the backend's load. The server will always accept at least

View File

@ -225,6 +225,7 @@ struct server {
unsigned int pool_purge_delay; /* Delay before starting to purge the idle conns pool */ unsigned int pool_purge_delay; /* Delay before starting to purge the idle conns pool */
unsigned int max_idle_conns; /* Max number of connection allowed in the orphan connections list */ unsigned int max_idle_conns; /* Max number of connection allowed in the orphan connections list */
unsigned int curr_idle_conns; /* Current number of orphan idling connections */ unsigned int curr_idle_conns; /* Current number of orphan idling connections */
int max_reuse; /* Max number of requests on a same connection */
struct task **idle_task; /* task responsible for cleaning idle orphan connections */ struct task **idle_task; /* task responsible for cleaning idle orphan connections */
struct task *warmup; /* the task dedicated to the warmup when slowstart is set */ struct task *warmup; /* the task dedicated to the warmup when slowstart is set */

View File

@ -471,6 +471,7 @@ void init_default_instance()
defproxy.defsrv.maxqueue = 0; defproxy.defsrv.maxqueue = 0;
defproxy.defsrv.minconn = 0; defproxy.defsrv.minconn = 0;
defproxy.defsrv.maxconn = 0; defproxy.defsrv.maxconn = 0;
defproxy.defsrv.max_reuse = -1;
defproxy.defsrv.max_idle_conns = -1; defproxy.defsrv.max_idle_conns = -1;
defproxy.defsrv.pool_purge_delay = 1000; defproxy.defsrv.pool_purge_delay = 1000;
defproxy.defsrv.slowstart = 0; defproxy.defsrv.slowstart = 0;

View File

@ -358,6 +358,20 @@ static int srv_parse_enabled(char **args, int *cur_arg,
return 0; return 0;
} }
static int srv_parse_max_reuse(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
{
char *arg;
arg = args[*cur_arg + 1];
if (!*arg) {
memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
return ERR_ALERT | ERR_FATAL;
}
newsrv->max_reuse = atoi(arg);
return 0;
}
static int srv_parse_pool_purge_delay(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err) static int srv_parse_pool_purge_delay(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
{ {
const char *res; const char *res;
@ -1239,6 +1253,7 @@ static struct srv_kw_list srv_kws = { "ALL", { }, {
{ "disabled", srv_parse_disabled, 0, 1 }, /* Start the server in 'disabled' state */ { "disabled", srv_parse_disabled, 0, 1 }, /* Start the server in 'disabled' state */
{ "enabled", srv_parse_enabled, 0, 1 }, /* Start the server in 'enabled' state */ { "enabled", srv_parse_enabled, 0, 1 }, /* Start the server in 'enabled' state */
{ "id", srv_parse_id, 1, 0 }, /* set id# of server */ { "id", srv_parse_id, 1, 0 }, /* set id# of server */
{ "max-reuse", srv_parse_max_reuse, 1, 1 }, /* Set the max number of requests on a connection, -1 means unlimited */
{ "namespace", srv_parse_namespace, 1, 1 }, /* Namespace the server socket belongs to (if supported) */ { "namespace", srv_parse_namespace, 1, 1 }, /* Namespace the server socket belongs to (if supported) */
{ "no-agent-check", srv_parse_no_agent_check, 0, 1 }, /* Do not enable any auxiliary agent check */ { "no-agent-check", srv_parse_no_agent_check, 0, 1 }, /* Do not enable any auxiliary agent check */
{ "no-backup", srv_parse_no_backup, 0, 1 }, /* Flag as non-backup server */ { "no-backup", srv_parse_no_backup, 0, 1 }, /* Flag as non-backup server */
@ -1689,6 +1704,7 @@ static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmp
srv->mux_proto = src->mux_proto; srv->mux_proto = src->mux_proto;
srv->pool_purge_delay = src->pool_purge_delay; srv->pool_purge_delay = src->pool_purge_delay;
srv->max_idle_conns = src->max_idle_conns; srv->max_idle_conns = src->max_idle_conns;
srv->max_reuse = src->max_reuse;
if (srv_tmpl) if (srv_tmpl)
srv->srvrq = src->srvrq; srv->srvrq = src->srvrq;
@ -1736,6 +1752,7 @@ struct server *new_server(struct proxy *proxy)
srv->pool_purge_delay = 1000; srv->pool_purge_delay = 1000;
srv->max_idle_conns = -1; srv->max_idle_conns = -1;
srv->max_reuse = -1;
return srv; return srv;