diff --git a/doc/configuration.txt b/doc/configuration.txt index 9fca4bd18..5b24fcf82 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -11972,6 +11972,14 @@ on-marked-up Actions are disabled by default +pool-max-conn + Set the maximum number of idling connections for a server. -1 means unlimited + connections, 0 means no idle connections. The default is -1. When idle + connections are enabled, orphaned idle connections which do not belong to any + client session anymore are moved to a dedicated pool so that they remain + usable by future clients. This only applies to connections that can be shared + according to the same principles as those applying to "http-reuse". + port Using the "port" parameter, it becomes possible to use a different port to send health-checks. On some servers, it may be desirable to dedicate a port diff --git a/include/proto/connection.h b/include/proto/connection.h index f84b75a3f..2cf37ab97 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -558,6 +558,7 @@ static inline void conn_init(struct connection *conn) LIST_INIT(&conn->session_list); conn->send_wait = NULL; conn->recv_wait = NULL; + conn->idle_time = 0; } /* sets as the connection's owner */ @@ -673,6 +674,13 @@ static inline void conn_free(struct connection *conn) if (objt_conn(s->si[1].end) == conn) s->si[1].end = NULL; } + /* The connection is currently in the server's idle list, so tell it + * there's one less connection available in that list. + */ + if (conn->idle_time > 0) { + struct server *srv = __objt_server(conn->target); + srv->curr_idle_conns--; + } conn_force_unsubscribe(conn); LIST_DEL(&conn->list); diff --git a/include/types/connection.h b/include/types/connection.h index bcc29650a..eff100154 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -446,7 +446,7 @@ struct connection { struct sockaddr_storage from; /* client address, or address to spoof when connecting to the server */ struct sockaddr_storage to; /* address reached by the client, or address to connect to */ } addr; /* addresses of the remote side, client for producer and server for consumer */ - unsigned int idle_time; /* Time the connection was added to the idle list */ + unsigned int idle_time; /* Time the connection was added to the idle list, or 0 if not in the idle list */ }; /* PROTO token registration */ diff --git a/include/types/server.h b/include/types/server.h index bb53523cd..2eef2c3c4 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -223,7 +223,9 @@ struct server { struct list *safe_conns; /* safe idle connections attached to stream interfaces, shared */ struct list *idle_orphan_conns; /* Orphan connections idling */ unsigned int idle_timeout; /* Time to keep an idling orphan connection alive */ - struct task **idle_task; /* task responsible for cleaning idle orphan connections */ + 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 */ + 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 conn_src conn_src; /* connection source settings */ diff --git a/src/backend.c b/src/backend.c index e11675756..83ae51dd6 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1231,6 +1231,8 @@ int connect_server(struct stream *s) */ if (reuse && reuse_orphan) { LIST_DEL(&srv_conn->list); + srv_conn->idle_time = 0; + srv->curr_idle_conns--; LIST_ADDQ(&srv->idle_conns[tid], &srv_conn->list); if (LIST_ISEMPTY(&srv->idle_orphan_conns[tid])) task_unlink_wq(srv->idle_task[tid]); diff --git a/src/cfgparse.c b/src/cfgparse.c index ed09a4e64..c3318a47f 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -471,6 +471,7 @@ void init_default_instance() defproxy.defsrv.maxqueue = 0; defproxy.defsrv.minconn = 0; defproxy.defsrv.maxconn = 0; + defproxy.defsrv.max_idle_conns = -1; defproxy.defsrv.slowstart = 0; defproxy.defsrv.onerror = DEF_HANA_ONERR; defproxy.defsrv.consecutive_errors_limit = DEF_HANA_ERRLIMIT; diff --git a/src/server.c b/src/server.c index bae9a3b66..dc429d1fb 100644 --- a/src/server.c +++ b/src/server.c @@ -380,6 +380,20 @@ static int srv_parse_idle_timeout(char **args, int *cur_arg, struct proxy *curpr return 0; } +static int srv_parse_pool_max_conn(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 as argument.\n", args[*cur_arg]); + return ERR_ALERT | ERR_FATAL; + } + newsrv->max_idle_conns = atoi(arg); + + return 0; +} + /* parse the "id" server keyword */ static int srv_parse_id(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err) { @@ -1230,6 +1244,7 @@ static struct srv_kw_list srv_kws = { "ALL", { }, { { "no-send-proxy-v2", srv_parse_no_send_proxy_v2, 0, 1 }, /* Disable use of PROXY V2 protocol */ { "non-stick", srv_parse_non_stick, 0, 1 }, /* Disable stick-table persistence */ { "observe", srv_parse_observe, 1, 1 }, /* Enables health adjusting based on observing communication with the server */ + { "pool-max-conn", srv_parse_pool_max_conn, 1, 1 }, /* Set the max number of orphan idle connections, 0 means unlimited */ { "proto", srv_parse_proto, 1, 1 }, /* Set the proto to use for all outgoing connections */ { "proxy-v2-options", srv_parse_proxy_v2_options, 1, 1 }, /* options for send-proxy-v2 */ { "redir", srv_parse_redir, 1, 1 }, /* Enable redirection mode */ @@ -1665,6 +1680,7 @@ static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmp #endif srv->mux_proto = src->mux_proto; srv->idle_timeout = src->idle_timeout; + srv->max_idle_conns = src->max_idle_conns; if (srv_tmpl) srv->srvrq = src->srvrq; @@ -1708,6 +1724,9 @@ struct server *new_server(struct proxy *proxy) srv->agent.server = srv; srv->xprt = srv->check.xprt = srv->agent.xprt = xprt_get(XPRT_RAW); + srv->idle_timeout = 1000; + srv->max_idle_conns = -1; + return srv; free_idle_conns: @@ -1914,7 +1933,7 @@ static int server_finalize_init(const char *file, int linenum, char **args, int px->srv_act++; srv_lb_commit_status(srv); - if (!srv->tmpl_info.prefix && srv->idle_timeout != 0) { + if (!srv->tmpl_info.prefix && srv->max_idle_conns != 0) { int i; srv->idle_orphan_conns = calloc(global.nbthread, sizeof(*srv->idle_orphan_conns)); @@ -2019,7 +2038,7 @@ static int server_template_init(struct server *srv, struct proxy *px) /* Linked backwards first. This will be restablished after parsing. */ newsrv->next = px->srv; px->srv = newsrv; - if (newsrv->idle_timeout != 0) { + if (newsrv->max_idle_conns != 0) { int i; newsrv->idle_orphan_conns = calloc(global.nbthread, sizeof(*newsrv->idle_orphan_conns)); diff --git a/src/session.c b/src/session.c index 2dfd1dea6..e5e550812 100644 --- a/src/session.c +++ b/src/session.c @@ -93,6 +93,8 @@ void session_free(struct session *sess) srv = objt_server(conn->target); conn->owner = NULL; if (srv && srv->idle_timeout > 0 && + (srv->max_idle_conns == -1 || + srv->max_idle_conns > srv->curr_idle_conns) && !(conn->flags & CO_FL_PRIVATE) && conn->mux->avail_streams(conn) == conn->mux->max_streams(conn)) { @@ -100,6 +102,7 @@ void session_free(struct session *sess) LIST_ADDQ(&srv->idle_orphan_conns[tid], &conn->list); + srv->curr_idle_conns++; conn->idle_time = now_ms; if (!(task_in_wq(srv->idle_task[tid])) &&