Skip to content
Permalink
Browse files

MINOR: backend: make the random algorithm support a number of draws

When an argument <draws> is present, it must be an integer value one
or greater, indicating the number of draws before selecting the least
loaded of these servers. It was indeed demonstrated that picking the
least loaded of two servers is enough to significantly improve the
fairness of the algorithm, by always avoiding to pick the most loaded
server within a farm and getting rid of any bias that could be induced
by the unfair distribution of the consistent list. Higher values N will
take away N-1 of the highest loaded servers at the expense of performance.
With very high values, the algorithm will converge towards the leastconn's
result but much slower. The default value is 2, which generally shows very
good distribution and performance. This algorithm is also known as the
Power of Two Random Choices and is described here :

http://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf
  • Loading branch information...
Willy Tarreau
Willy Tarreau committed Jan 14, 2019
1 parent 0cac26c commit 21c741a665f4c7b354e961267824c81ec44f503f
Showing with 66 additions and 9 deletions.
  1. +23 −5 doc/configuration.txt
  2. +43 −4 src/backend.c
@@ -2541,15 +2541,33 @@ balance url_param <param> [check_post]
changing a server's weight on the fly will have no effect,
but this can be changed using "hash-type".

random A random number will be used as the key for the consistent
random
random(<draws>)
A random number will be used as the key for the consistent
hashing function. This means that the servers' weights are
respected, dynamic weight changes immediately take effect, as
well as new server additions. Random load balancing can be
useful with large farms or when servers are frequently added
or removed. The hash-balance-factor directive can be used to
further improve fairness of the load balancing, especially
in situations where servers show highly variable response
times.
or removed as it may avoid the hammering effect that could
result from roundrobin or leastconn in this situation. The
hash-balance-factor directive can be used to further improve
fairness of the load balancing, especially in situations
where servers show highly variable response times. When an
argument <draws> is present, it must be an integer value one
or greater, indicating the number of draws before selecting
the least loaded of these servers. It was indeed demonstrated
that picking the least loaded of two servers is enough to
significantly improve the fairness of the algorithm, by
always avoiding to pick the most loaded server within a farm
and getting rid of any bias that could be induced by the
unfair distribution of the consistent list. Higher values N
will take away N-1 of the highest loaded servers at the
expense of performance. With very high values, the algorithm
will converge towards the leastconn's result but much slower.
The default value is 2, which generally shows very good
distribution and performance. This algorithm is also known as
the Power of Two Random Choices and is described here :
http://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf

rdp-cookie
rdp-cookie(<name>)
@@ -524,14 +524,31 @@ static struct server *get_server_rnd(struct stream *s, const struct server *avoi
{
unsigned int hash = 0;
struct proxy *px = s->be;
struct server *prev, *curr;
int draws = px->lbprm.arg_opt1; // number of draws

/* tot_weight appears to mean srv_count */
if (px->lbprm.tot_weight == 0)
return NULL;

/* 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, avoid);
curr = NULL;
do {
prev = curr;
/* ensure all 32 bits are covered as long as RAND_MAX >= 65535 */
hash = ((uint64_t)random() * ((uint64_t)RAND_MAX + 1)) ^ random();
curr = chash_get_server_hash(px, hash, avoid);
if (!curr)
break;

/* compare the new server to the previous best choice and pick
* the one with the least currently served requests.
*/
if (prev && prev != curr &&
curr->served * prev->cur_eweight > prev->served * curr->cur_eweight)
curr = prev;
} while (--draws > 0);

return curr;
}

/*
@@ -1722,9 +1739,31 @@ int backend_parse_balance(const char **args, char **err, struct proxy *curproxy)
curproxy->lbprm.algo &= ~BE_LB_ALGO;
curproxy->lbprm.algo |= BE_LB_ALGO_LC;
}
else if (!strcmp(args[0], "random")) {
else if (!strncmp(args[0], "random", 6)) {
curproxy->lbprm.algo &= ~BE_LB_ALGO;
curproxy->lbprm.algo |= BE_LB_ALGO_RND;
curproxy->lbprm.arg_opt1 = 2;

if (*(args[0] + 6) == '(' && *(args[0] + 7) != ')') { /* number of draws */
const char *beg;
char *end;

beg = args[0] + 7;
curproxy->lbprm.arg_opt1 = strtol(beg, &end, 0);

if (*end != ')') {
if (!*end)
memprintf(err, "random : missing closing parenthesis.");
else
memprintf(err, "random : unexpected character '%c' after argument.", *end);
return -1;
}

if (curproxy->lbprm.arg_opt1 < 1) {
memprintf(err, "random : number of draws must be at least 1.");
return -1;
}
}
}
else if (!strcmp(args[0], "source")) {
curproxy->lbprm.algo &= ~BE_LB_ALGO;

1 comment on commit 21c741a

@Alexkho0o

This comment has been minimized.

Copy link

Alexkho0o commented on 21c741a Feb 26, 2019

Please sign in to comment.
You can’t perform that action at this time.