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.
This commit is contained in:
Willy Tarreau 2015-08-05 17:16:33 +02:00
parent 7017cb040c
commit 449d74a906
3 changed files with 51 additions and 12 deletions

View File

@ -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.
*/
srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list);
/* 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);

View File

@ -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;
}

View File

@ -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);
}