MINOR: lb: allow redispatch when using consistent hash

Redispatch traditionally only worked for cookie based persistence.

Adding redispatch support for consistent hash based persistence - also
update docs.

Reported by Oskar Stenman on discourse:
https://discourse.haproxy.org/t/balance-uri-consistent-hashing-redispatch-3-not-redispatching/3344

Should be backported to 1.8.

Cc: Lukas Tribus <lukas@ltri.eu>
This commit is contained in:
Willy Tarreau 2019-01-02 14:48:31 +01:00
parent 200f895cca
commit 59884a646c
4 changed files with 28 additions and 27 deletions

View File

@ -6764,8 +6764,8 @@ no option redispatch
definitely stick to it because they cannot flush the cookie, so they will not
be able to access the service anymore.
Specifying "option redispatch" will allow the proxy to break their
persistence and redistribute them to a working server.
Specifying "option redispatch" will allow the proxy to break cookie or
consistent hash based persistence and redistribute them to a working server.
It also allows to retry connections to another server in case of multiple
connection failures. Of course, it requires having "retries" set to a nonzero

View File

@ -28,7 +28,7 @@
void chash_init_server_tree(struct proxy *p);
struct server *chash_get_next_server(struct proxy *p, struct server *srvtoavoid);
struct server *chash_get_server_hash(struct proxy *p, unsigned int hash);
struct server *chash_get_server_hash(struct proxy *p, unsigned int hash, const struct server *avoid);
#endif /* _PROTO_LB_CHASH_H */

View File

@ -165,7 +165,7 @@ void update_backend_weight(struct proxy *px)
* If any server is found, it will be returned. If no valid server is found,
* NULL is returned.
*/
static struct server *get_server_sh(struct proxy *px, const char *addr, int len)
static struct server *get_server_sh(struct proxy *px, const char *addr, int len, const struct server *avoid)
{
unsigned int h, l;
@ -186,7 +186,7 @@ static struct server *get_server_sh(struct proxy *px, const char *addr, int len)
h = full_hash(h);
hash_done:
if (px->lbprm.algo & BE_LB_LKUP_CHTREE)
return chash_get_server_hash(px, h);
return chash_get_server_hash(px, h, avoid);
else
return map_get_server_hash(px, h);
}
@ -203,7 +203,7 @@ static struct server *get_server_sh(struct proxy *px, const char *addr, int len)
* algorithm out of a tens because it gave him the best results.
*
*/
static struct server *get_server_uh(struct proxy *px, char *uri, int uri_len)
static struct server *get_server_uh(struct proxy *px, char *uri, int uri_len, const struct server *avoid)
{
unsigned int hash = 0;
int c;
@ -239,7 +239,7 @@ static struct server *get_server_uh(struct proxy *px, char *uri, int uri_len)
hash = full_hash(hash);
hash_done:
if (px->lbprm.algo & BE_LB_LKUP_CHTREE)
return chash_get_server_hash(px, hash);
return chash_get_server_hash(px, hash, avoid);
else
return map_get_server_hash(px, hash);
}
@ -253,7 +253,7 @@ static struct server *get_server_uh(struct proxy *px, char *uri, int uri_len)
* is returned. If any server is found, it will be returned. If no valid server
* is found, NULL is returned.
*/
static struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len)
static struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len, const struct server *avoid)
{
unsigned int hash = 0;
const char *start, *end;
@ -296,7 +296,7 @@ static struct server *get_server_ph(struct proxy *px, const char *uri, int uri_l
hash = full_hash(hash);
if (px->lbprm.algo & BE_LB_LKUP_CHTREE)
return chash_get_server_hash(px, hash);
return chash_get_server_hash(px, hash, avoid);
else
return map_get_server_hash(px, hash);
}
@ -315,7 +315,7 @@ static struct server *get_server_ph(struct proxy *px, const char *uri, int uri_l
/*
* this does the same as the previous server_ph, but check the body contents
*/
static struct server *get_server_ph_post(struct stream *s)
static struct server *get_server_ph_post(struct stream *s, const struct server *avoid)
{
unsigned int hash = 0;
struct http_txn *txn = s->txn;
@ -370,7 +370,7 @@ static struct server *get_server_ph_post(struct stream *s)
hash = full_hash(hash);
if (px->lbprm.algo & BE_LB_LKUP_CHTREE)
return chash_get_server_hash(px, hash);
return chash_get_server_hash(px, hash, avoid);
else
return map_get_server_hash(px, hash);
}
@ -396,7 +396,7 @@ static struct server *get_server_ph_post(struct stream *s)
* is returned. If any server is found, it will be returned. If no valid server
* is found, NULL is returned.
*/
static struct server *get_server_hh(struct stream *s)
static struct server *get_server_hh(struct stream *s, const struct server *avoid)
{
unsigned int hash = 0;
struct http_txn *txn = s->txn;
@ -466,13 +466,13 @@ static struct server *get_server_hh(struct stream *s)
hash = full_hash(hash);
hash_done:
if (px->lbprm.algo & BE_LB_LKUP_CHTREE)
return chash_get_server_hash(px, hash);
return chash_get_server_hash(px, hash, avoid);
else
return map_get_server_hash(px, hash);
}
/* RDP Cookie HASH. */
static struct server *get_server_rch(struct stream *s)
static struct server *get_server_rch(struct stream *s, const struct server *avoid)
{
unsigned int hash = 0;
struct proxy *px = s->be;
@ -511,13 +511,13 @@ static struct server *get_server_rch(struct stream *s)
hash = full_hash(hash);
hash_done:
if (px->lbprm.algo & BE_LB_LKUP_CHTREE)
return chash_get_server_hash(px, hash);
return chash_get_server_hash(px, hash, avoid);
else
return map_get_server_hash(px, hash);
}
/* random value */
static struct server *get_server_rnd(struct stream *s)
static struct server *get_server_rnd(struct stream *s, const struct server *avoid)
{
unsigned int hash = 0;
struct proxy *px = s->be;
@ -528,7 +528,7 @@ static struct server *get_server_rnd(struct stream *s)
/* ensure all 32 bits are covered as long as RAND_MAX >= 65535 */
hash = ((uint64_t)random() * ((uint64_t)RAND_MAX + 1)) ^ random();
return chash_get_server_hash(px, hash);
return chash_get_server_hash(px, hash, avoid);
}
/*
@ -639,7 +639,7 @@ int assign_server(struct stream *s)
case BE_LB_LKUP_MAP:
if ((s->be->lbprm.algo & BE_LB_KIND) == BE_LB_KIND_RR) {
if ((s->be->lbprm.algo & BE_LB_PARM) == BE_LB_RR_RANDOM)
srv = get_server_rnd(s);
srv = get_server_rnd(s, prev_srv);
else if (s->be->lbprm.algo & BE_LB_LKUP_CHTREE)
srv = chash_get_next_server(s->be, prev_srv);
else
@ -658,12 +658,12 @@ int assign_server(struct stream *s)
if (conn && conn->addr.from.ss_family == AF_INET) {
srv = get_server_sh(s->be,
(void *)&((struct sockaddr_in *)&conn->addr.from)->sin_addr,
4);
4, prev_srv);
}
else if (conn && conn->addr.from.ss_family == AF_INET6) {
srv = get_server_sh(s->be,
(void *)&((struct sockaddr_in6 *)&conn->addr.from)->sin6_addr,
16);
16, prev_srv);
}
else {
/* unknown IP family */
@ -678,7 +678,7 @@ int assign_server(struct stream *s)
break;
srv = get_server_uh(s->be,
c_ptr(&s->req, -http_uri_rewind(&s->txn->req)),
s->txn->req.sl.rq.u_l);
s->txn->req.sl.rq.u_l, prev_srv);
break;
case BE_LB_HASH_PRM:
@ -688,22 +688,22 @@ int assign_server(struct stream *s)
srv = get_server_ph(s->be,
c_ptr(&s->req, -http_uri_rewind(&s->txn->req)),
s->txn->req.sl.rq.u_l);
s->txn->req.sl.rq.u_l, prev_srv);
if (!srv && s->txn->meth == HTTP_METH_POST)
srv = get_server_ph_post(s);
srv = get_server_ph_post(s, prev_srv);
break;
case BE_LB_HASH_HDR:
/* Header Parameter hashing */
if (!s->txn || s->txn->req.msg_state < HTTP_MSG_BODY)
break;
srv = get_server_hh(s);
srv = get_server_hh(s, prev_srv);
break;
case BE_LB_HASH_RDP:
/* RDP Cookie hashing */
srv = get_server_rch(s);
srv = get_server_rch(s, prev_srv);
break;
default:

View File

@ -313,9 +313,10 @@ int chash_server_is_eligible(struct server *s)
* the closest distance from the value of <hash>. Doing so ensures that even
* with a well imbalanced hash, if some servers are close to each other, they
* will still both receive traffic. If any server is found, it will be returned.
* It will also skip server <avoid> if the hash result ends on this one.
* If no valid server is found, NULL is returned.
*/
struct server *chash_get_server_hash(struct proxy *p, unsigned int hash)
struct server *chash_get_server_hash(struct proxy *p, unsigned int hash, const struct server *avoid)
{
struct eb32_node *next, *prev;
struct server *nsrv, *psrv;
@ -367,7 +368,7 @@ struct server *chash_get_server_hash(struct proxy *p, unsigned int hash)
}
loop = 0;
while (p->lbprm.chash.balance_factor && !chash_server_is_eligible(nsrv)) {
while (nsrv == avoid || (p->lbprm.chash.balance_factor && !chash_server_is_eligible(nsrv))) {
next = eb32_next(next);
if (!next) {
next = eb32_first(root);