]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: connections: Revamp the way idle connections are killed
authorOlivier Houchard <cognet@ci0.org>
Sun, 29 Mar 2020 22:23:57 +0000 (00:23 +0200)
committerOlivier Houchard <cognet@ci0.org>
Sun, 29 Mar 2020 22:30:07 +0000 (00:30 +0200)
The original algorithm always killed half the idle connections. This doesn't
take into account the way the load can change. Instead, we now kill half
of the exceeding connections (exceeding connection being the number of
used + idle connections past the last maximum used connections reached).
That way if we reach a peak, we will kill much less, and it'll slowly go back
down when there's less usage.

src/server.c

index 8d4ad89893faa9cfe0871fb30383db41621e761f..725a7c63e297dd23779d10e85c4dacdc2c0a0cd0 100644 (file)
@@ -5590,6 +5590,9 @@ struct task *srv_cleanup_idle_connections(struct task *task, void *context, unsi
        HA_SPIN_LOCK(OTHER_LOCK, &idle_conn_srv_lock);
        while (1) {
                int srv_is_empty = 1;
+               int exceed_conns;
+               int to_kill;
+               int curr_idle;
 
                eb = eb32_lookup_ge(&idle_conn_srv, now_ms - TIMER_LOOK_BACK);
                if (!eb) {
@@ -5609,12 +5612,27 @@ struct task *srv_cleanup_idle_connections(struct task *task, void *context, unsi
                        break;
                }
                srv = eb32_entry(eb, struct server, idle_node);
-               for (i = 0; i < global.nbthread; i++) {
-                       int max_conn = (srv->curr_idle_thr[i] / 2) +
-                           (srv->curr_idle_thr[i] & 1);
+
+               /* Calculate how many idle connections we want to kill :
+                * we want to remove half the difference between the total
+                * of established connections (used or idle) and the max
+                * number of used connections.
+                */
+               curr_idle = srv->curr_idle_conns;
+               if (curr_idle == 0)
+                       goto remove;
+               exceed_conns = srv->curr_used_conns + curr_idle -
+                              srv->max_used_conns;
+               exceed_conns = to_kill = exceed_conns / 2 + (exceed_conns & 1);
+               srv->max_used_conns = srv->curr_used_conns;
+
+               for (i = 0; i < global.nbthread && to_kill > 0; i++) {
+                       int max_conn;
                        int j;
                        int did_remove = 0;
 
+                       max_conn = (exceed_conns * srv->curr_idle_thr[i]) /
+                                  curr_idle + 1;
                        HA_SPIN_LOCK(OTHER_LOCK, &toremove_lock[i]);
                        for (j = 0; j < max_conn; j++) {
                                struct connection *conn = MT_LIST_POP(&srv->idle_conns[i], struct connection *, list);
@@ -5632,6 +5650,7 @@ struct task *srv_cleanup_idle_connections(struct task *task, void *context, unsi
                        if (did_remove)
                                task_wakeup(idle_conn_cleanup[i], TASK_WOKEN_OTHER);
                }
+remove:
                eb32_delete(&srv->idle_node);
                if (!srv_is_empty) {
                        /* There are still more idle connections, add the