We have experimented a bit with the latest haproxies and keep-alive. We
rely on haproxy to set good maxconn values for our servers so they can
operate at full speed without becoming overloaded.
When using multiple servers in a backend, "prefer-last-server" is required
to get keep-alive working, but the sessions seem to be a bit too sticky -
haproxy perfers putting the request on a server _queue_ instead of
assigning it to a server that still has some capacity left.
So we found that the average serving time increased with keep-alive.
Suggested patch attached -- NOT TESTED PROPERLY!! -- but shows the spirit
of something...
- Finn Arne
Subject: [PATCH] prefer-last-server only when a server is not busy
If a server has filled up all its session slots, let prefer-last-server
pick a different server instead of queuing the request on a busy server.
Followups to 401 and 407 results are still queued though.
When all clients use keep-alive connections and stick around for a while,
the load could be skewed too much on servers, and we even got into queuing
while servers were idle.
---
include/proto/queue.h | 10 ++++++++--
src/backend.c | 5 +++--
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/include/proto/queue.h b/include/proto/queue.h
index 7bf8137..d2a2f2a 100644
--- a/include/proto/queue.h
+++ b/include/proto/queue.h
@@ -65,13 +65,19 @@ static inline struct pendconn *pendconn_from_px(const struct proxy *px) {
return LIST_ELEM(px->pendconns.n, struct pendconn *, list);
}
+
+/* Returns 0 if all slots are full on a server, or 1 if there are slots available. */
+static inline int server_has_room(const struct server *s) {
+ return !s->maxconn || s->cur_sess < srv_dynamic_maxconn(s);
+}
+
/* returns 0 if nothing has to be done for server <s> regarding queued connections,
* and non-zero otherwise. If the server is down, we only check its own queue. Suited
* for and if/else usage.
*/
static inline int may_dequeue_tasks(const struct server *s, const struct proxy *p) {
- return (s && (s->nbpend || (p->nbpend && srv_is_usable(s->state, s->eweight))) &&
- (!s->maxconn || s->cur_sess < srv_dynamic_maxconn(s)));
+ return s && (s->nbpend || (p->nbpend && srv_is_usable(s->state, s->eweight))) &&
+ server_has_room(s);
}
#endif /* _PROTO_QUEUE_H */
diff --git a/src/backend.c b/src/backend.c
index d878028..f5e76b0 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -544,9 +544,10 @@ int assign_server(struct session *s)
if (conn &&
(conn->flags & CO_FL_CONNECTED) &&
- ((s->be->options & PR_O_PREF_LAST) || (s->txn.flags & TX_PREFER_LAST)) &&
objt_server(conn->target) && __objt_server(conn->target)->proxy == s->be &&
- srv_is_usable(__objt_server(conn->target)->state, __objt_server(conn->target)->eweight)) {
+ srv_is_usable(__objt_server(conn->target)->state, __objt_server(conn->target)->eweight) &&
+ (((s->be->options & PR_O_PREF_LAST) && server_has_room(__objt_server(conn->target))) ||
+ (s->txn.flags & TX_PREFER_LAST))) {
/* This session was relying on a server in a previous request
* and the proxy has "option prefer-current-server" set, so
* let's try to reuse the same server.
--
1.8.4