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 },