From: Willy Tarreau Date: Wed, 5 Aug 2015 15:16:33 +0000 (+0200) Subject: MEDIUM: backend: add the "http-reuse aggressive" strategy X-Git-Tag: v1.6-dev4~106 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=449d74a9063797c57d39fe95ddee87697e0a2c35;p=thirdparty%2Fhaproxy.git MEDIUM: backend: add the "http-reuse aggressive" strategy This strategy is less extreme than "always", it only dispatches first requests to validated reused connections, and moves a connection from the idle list to the safe list once it has seen a second request, thus proving that it could be reused. --- diff --git a/src/backend.c b/src/backend.c index 18f688d1eb..9e8e9b6968 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1046,17 +1046,43 @@ int connect_server(struct stream *s) */ } - if (((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_ALWS || - ((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_SAFE && s->txn && (s->txn->flags & TX_NOT_FIRST))) - && !LIST_ISEMPTY(&srv->idle_conns)) { - /* We're going to have to pick the first connection - * from this pool and use it for our purposes. We may - * have to get rid of the current idle connection, so - * for this we try to swap it with the other owner's. - * That way it may remain alive for others to pick. - */ + /* Below we pick connections from the safe or idle lists based + * on the strategy, the fact that this is a first or second + * (retryable) request, with the indicated priority (1 or 2) : + * + * SAFE AGGR ALWS + * + * +-----+-----+ +-----+-----+ +-----+-----+ + * req| 1st | 2nd | req| 1st | 2nd | req| 1st | 2nd | + * ----+-----+-----+ ----+-----+-----+ ----+-----+-----+ + * safe| - | 2 | safe| 1 | 2 | safe| 1 | 2 | + * ----+-----+-----+ ----+-----+-----+ ----+-----+-----+ + * idle| - | 1 | idle| - | 1 | idle| 2 | 1 | + * ----+-----+-----+ ----+-----+-----+ ----+-----+-----+ + */ + + if (!LIST_ISEMPTY(&srv->idle_conns) && + ((s->be->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR && + s->txn && (s->txn->flags & TX_NOT_FIRST))) { + srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list); + } + else if (!LIST_ISEMPTY(&srv->safe_conns) && + ((s->txn && (s->txn->flags & TX_NOT_FIRST)) || + (s->be->options & PR_O_REUSE_MASK) >= PR_O_REUSE_AGGR)) { + srv_conn = LIST_ELEM(srv->safe_conns.n, struct connection *, list); + } + else if (!LIST_ISEMPTY(&srv->idle_conns) && + (s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_ALWS) { srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list); + } + /* If we've picked a connection from the pool, we now have to + * detach it. We may have to get rid of the previous idle + * connection we had, so for this we try to swap it with the + * other owner's. That way it may remain alive for others to + * pick. + */ + if (srv_conn) { LIST_DEL(&srv_conn->list); LIST_INIT(&srv_conn->list); @@ -1069,8 +1095,8 @@ int connect_server(struct stream *s) reuse = 1; } + /* we may have to release our connection if we couldn't swap it */ if (old_conn && !old_conn->owner) { - /* we couldn't swap our connection, let's release it */ LIST_DEL(&old_conn->list); conn_force_close(old_conn); conn_free(old_conn); diff --git a/src/cfgparse.c b/src/cfgparse.c index 9f7a6b53b3..08adccdc12 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -5042,6 +5042,12 @@ stats_error_parsing: if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) goto out; } + else if (strcmp(args[1], "aggressive") == 0) { + curproxy->options &= ~PR_O_REUSE_MASK; + curproxy->options |= PR_O_REUSE_AGGR; + if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code)) + goto out; + } else if (strcmp(args[1], "always") == 0) { /* enable a graceful server shutdown on an HTTP 404 response */ curproxy->options &= ~PR_O_REUSE_MASK; @@ -5050,7 +5056,7 @@ stats_error_parsing: goto out; } else { - Alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'always'.\n", file, linenum, args[0]); + Alert("parsing [%s:%d] : '%s' only supports 'never', 'safe', 'aggressive', 'always'.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; goto out; } diff --git a/src/proto_http.c b/src/proto_http.c index 02ff485d44..c7ed011596 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -5032,6 +5032,7 @@ void http_end_txn_clean_session(struct stream *s) struct proxy *fe = strm_fe(s); struct connection *srv_conn; struct server *srv; + unsigned int prev_flags = s->txn->flags; /* FIXME: We need a more portable way of releasing a backend's and a * server's connections. We need a safer way to reinitialize buffer @@ -5194,6 +5195,12 @@ void http_end_txn_clean_session(struct stream *s) else if ((srv_conn->flags & CO_FL_PRIVATE) || ((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_NEVR)) si_idle_conn(&s->si[1], &srv->priv_conns); + else if (prev_flags & TX_NOT_FIRST) + /* note: we check the request, not the connection, but + * this is valid for strategies SAFE and AGGR, and in + * case of ALWS, we don't care anyway. + */ + si_idle_conn(&s->si[1], &srv->safe_conns); else si_idle_conn(&s->si[1], &srv->idle_conns); }