From 9420b1271d3c800033e8af20c8fcad4258ac27ee Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 15 Dec 2013 18:58:25 +0100 Subject: [PATCH] MINOR: http: add option prefer-last-server When the load balancing algorithm in use is not deterministic, and a previous request was sent to a server to which haproxy still holds a connection, it is sometimes desirable that subsequent requests on a same session go to the same server as much as possible. Note that this is different from persistence, as we only indicate a preference which haproxy tries to apply without any form of warranty. The real use is for keep-alive connections sent to servers. When this option is used, haproxy will try to reuse the same connection that is attached to the server instead of rebalancing to another server, causing a close of the connection. This can make sense for static file servers. It does not make much sense to use this in combination with hashing algorithms. --- doc/configuration.txt | 32 +++++++++++++++++++++++++++++--- include/types/proxy.h | 3 ++- src/backend.c | 13 ++++++++++++- src/cfgparse.c | 1 + 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index d0417c047..b521bf35a 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -3794,7 +3794,9 @@ no option http-keep-alive If the client request has to go to another backend or another server due to content switching or the load balancing algorithm, the idle connection will - immediately be closed and a new one re-opened. + immediately be closed and a new one re-opened. Option "prefer-last-server" is + available to try optimize server selection so that if the server currently + attached to an idle connection is usable, it will be used. In general it is preferred to use "option http-server-close" with application servers, and some static servers might benefit from "option http-keep-alive". @@ -3815,8 +3817,8 @@ no option http-keep-alive in a specific instance by prepending the "no" keyword before it. See also : "option forceclose", "option http-server-close", - "option httpclose", "option http-pretend-keepalive" and - "1.1. The HTTP transaction model". + "option prefer-last-server", "option http-pretend-keepalive", + "option httpclose", and "1.1. The HTTP transaction model". option http-no-delay @@ -4428,6 +4430,30 @@ option pgsql-check [ user ] See also: "option httpchk" +option prefer-last-server +no option prefer-last-server + Allow multiple load balanced requests to remain on the same server + May be used in sections: defaults | frontend | listen | backend + yes | no | yes | yes + Arguments : none + + When the load balancing algorithm in use is not deterministic, and a previous + request was sent to a server to which haproxy still holds a connection, it is + sometimes desirable that subsequent requests on a same session go to the same + server as much as possible. Note that this is different from persistence, as + we only indicate a preference which haproxy tries to apply without any form + of warranty. The real use is for keep-alive connections sent to servers. When + this option is used, haproxy will try to reuse the same connection that is + attached to the server instead of rebalancing to another server, causing a + close of the connection. This can make sense for static file servers. It does + not make much sense to use this in combination with hashing algorithms. + + If this option has been enabled in a "defaults" section, it can be disabled + in a specific instance by prepending the "no" keyword before it. + + See also: "option http-keep-alive" + + option redispatch no option redispatch Enable or disable session redistribution in case of connection failure diff --git a/include/types/proxy.h b/include/types/proxy.h index de5c33744..6c6cc0b9d 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -76,7 +76,8 @@ enum pr_mode { /* bits for proxy->options */ #define PR_O_REDISP 0x00000001 /* allow reconnection to dispatch in case of errors */ #define PR_O_TRANSP 0x00000002 /* transparent mode : use original DEST as dispatch */ -/* unused: 0x04, 0x08, 0x10, 0x20 */ +/* unused: 0x04, 0x08, 0x10 */ +#define PR_O_PREF_LAST 0x00000020 /* prefer last server */ #define PR_O_DISPATCH 0x00000040 /* use dispatch mode */ #define PR_O_KEEPALIVE 0x00000080 /* follow keep-alive sessions */ #define PR_O_FWDFOR 0x00000100 /* conditionally insert x-forwarded-for with client address */ diff --git a/src/backend.c b/src/backend.c index 7eeed8dc0..c9f0718ec 100644 --- a/src/backend.c +++ b/src/backend.c @@ -532,8 +532,19 @@ int assign_server(struct session *s) srv = NULL; s->target = NULL; + conn = objt_conn(s->req->cons->end); - if (s->be->lbprm.algo & BE_LB_KIND) { + if (conn && (s->be->options & PR_O_PREF_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)) { + /* 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. + */ + srv = __objt_server(conn->target); + s->target = &srv->obj_type; + } + else if (s->be->lbprm.algo & BE_LB_KIND) { /* we must check if we have at least one server available */ if (!s->be->lbprm.tot_weight) { err = SRV_STATUS_NOSRV; diff --git a/src/cfgparse.c b/src/cfgparse.c index 8d08d0159..864a9fb9b 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -134,6 +134,7 @@ static const struct cfg_opt cfg_opts[] = { "httpclose", PR_O_HTTP_CLOSE, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP }, { "http-keep-alive", PR_O_KEEPALIVE, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP }, { "http-server-close", PR_O_SERVER_CLO, PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP }, + { "prefer-last-server", PR_O_PREF_LAST, PR_CAP_BE, 0, PR_MODE_HTTP }, { "logasap", PR_O_LOGASAP, PR_CAP_FE, 0, 0 }, { "nolinger", PR_O_TCP_NOLING, PR_CAP_FE | PR_CAP_BE, 0, 0 }, { "persist", PR_O_PERSIST, PR_CAP_BE, 0, 0 },