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 || /* Below we pick connections from the safe or idle lists based
((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_SAFE && s->txn && (s->txn->flags & TX_NOT_FIRST))) * on the strategy, the fact that this is a first or second
&& !LIST_ISEMPTY(&srv->idle_conns)) { * (retryable) request, with the indicated priority (1 or 2) :
/* We're going to have to pick the first connection *
* from this pool and use it for our purposes. We may * SAFE AGGR ALWS
* 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. * req| 1st | 2nd | req| 1st | 2nd | req| 1st | 2nd |
*/ * ----+-----+-----+ ----+-----+-----+ ----+-----+-----+
srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list); * 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_DEL(&srv_conn->list);
LIST_INIT(&srv_conn->list); LIST_INIT(&srv_conn->list);
@ -1069,8 +1095,8 @@ int connect_server(struct stream *s)
reuse = 1; reuse = 1;
} }
/* we may have to release our connection if we couldn't swap it */
if (old_conn && !old_conn->owner) { if (old_conn && !old_conn->owner) {
/* we couldn't swap our connection, let's release it */
LIST_DEL(&old_conn->list); LIST_DEL(&old_conn->list);
conn_force_close(old_conn); conn_force_close(old_conn);
conn_free(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)) if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
goto out; 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) { else if (strcmp(args[1], "always") == 0) {
/* enable a graceful server shutdown on an HTTP 404 response */ /* enable a graceful server shutdown on an HTTP 404 response */
curproxy->options &= ~PR_O_REUSE_MASK; curproxy->options &= ~PR_O_REUSE_MASK;
@ -5050,7 +5056,7 @@ stats_error_parsing:
goto out; goto out;
} }
else { 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; err_code |= ERR_ALERT | ERR_FATAL;
goto out; goto out;
} }

View File

@ -5032,6 +5032,7 @@ void http_end_txn_clean_session(struct stream *s)
struct proxy *fe = strm_fe(s); struct proxy *fe = strm_fe(s);
struct connection *srv_conn; struct connection *srv_conn;
struct server *srv; struct server *srv;
unsigned int prev_flags = s->txn->flags;
/* FIXME: We need a more portable way of releasing a backend's and a /* 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 * 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) || else if ((srv_conn->flags & CO_FL_PRIVATE) ||
((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_NEVR)) ((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_NEVR))
si_idle_conn(&s->si[1], &srv->priv_conns); 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 else
si_idle_conn(&s->si[1], &srv->idle_conns); si_idle_conn(&s->si[1], &srv->idle_conns);
} }