]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: servers: Add a command to limit the number of idling connections.
authorOlivier Houchard <ohouchard@haproxy.com>
Mon, 10 Dec 2018 17:30:32 +0000 (18:30 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 15 Dec 2018 22:50:08 +0000 (23:50 +0100)
Add a new command, "pool-max-conn" that sets the maximum number of connections
waiting in the orphan idling connections list (as activated with idle-timeout).
Using "-1" means unlimited. Using pools is now dependant on this.

doc/configuration.txt
include/proto/connection.h
include/types/connection.h
include/types/server.h
src/backend.c
src/cfgparse.c
src/server.c
src/session.c

index 9fca4bd18edd3d207d82a406b69fe98d2de34d53..5b24fcf824115f603a6791958be8440f977c70ee 100644 (file)
@@ -11972,6 +11972,14 @@ on-marked-up <action>
 
   Actions are disabled by default
 
+pool-max-conn <max>
+  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 <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
index f84b75a3f2e1bc7916fe6a0d9fe5f6f6365e22a5..2cf37ab97161d4a4c1d7ffd4e9cc8aeb78f526bd 100644 (file)
@@ -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 <owner> 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);
index bcc29650a75e8dc4a947752511fe361ee43073e7..eff1001544ca5e5d3fc0b7522cb3135eb7b08ca6 100644 (file)
@@ -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 */
index bb53523cd848261763cf09059346bf7234027ccf..2eef2c3c44778919e13b514273fc5aa0ddeaa284 100644 (file)
@@ -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 */
index e11675756d390114dbdf9c00b8a4721ffeaab985..83ae51dd6f77d27d2560be5416cc0a464bf89e00 100644 (file)
@@ -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]);
index ed09a4e64bb0ebf359c97b3a358ce270f11fa2fe..c3318a47f94d767f127c628c5113583b45330a42 100644 (file)
@@ -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;
index bae9a3b6694f64b3c44d71fece4bb1bc2244fc3b..dc429d1fb9780d4d5ccf3e013877b4a73499df7a 100644 (file)
@@ -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 <value> 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));
index 2dfd1dea657047c4e4f4f0ad530957fb3466663d..e5e550812e3ed82ff46dc369ab81a796c534d8b6 100644 (file)
@@ -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])) &&