]> git.ipfire.org Git - thirdparty/haproxy.git/commit
MEDIUM: backend: make "balance random" consider req rate when loads are equal
authorWilly Tarreau <w@1wt.eu>
Fri, 30 Jan 2026 12:41:08 +0000 (13:41 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 4 Feb 2026 13:54:16 +0000 (14:54 +0100)
commitb6bdb2553bd1031acfeadea3dfee5366dabed462
tree2cad507728de78cb2206cf3a6d1abeb859685ebe
parent3edf6008591515db8f7d7bdc4a4906e09345e622
MEDIUM: backend: make "balance random" consider req rate when loads are equal

As reported by Damien Claisse and Cédric Paillet, the "random" LB
algorithm can become particularly unfair with large numbers of servers
having few connections. It's indeed fairly common to see many servers
with zero connection in a thousand-server large farm, and in this case
the P2C algo consisting in checking the servers' loads doesn't help at
all and is basically similar to random(1). In this case, we only rely
on the distribution of server IDs in the random space to pick the best
server, but it's possible to observe huge discrepancies.

An attempt to model the problem clearly shows that with 1600 servers
with weight 10, for 1 million requests, the lowest loaded ones will
take 300 req while the most loaded ones will get 780, with most of
the values between 520 and 700.

In addition, only the first 28 lower bits of server IDs are used for
the key calculation, which means that node keys are more determinist.
Setting random keys in the lowest 28 bits only better packs values
with min around 530 and max around 710, with values mostly between
550 and 680.

This can only be compensated by increasing weights and draws without
being a perfect fix either. At 4 draws, the min is around 560 and the
max around 670, with most values bteween 590 and 650.

This patch takes another approach to this problem: when servers are on
tie regarding their loads, instead of arbitrarily taking the second one,
we now compare their current request rates, which is updated all the
time and smoothed over one second, and we pick the server with the
lowest request rate. Now with 2 draws, the curve is mostly flat, with
the min at 580 and the max at 628, and almost all values between 611
and 625. And 4 draws exclusively gives values from 614 to 624.

Other points will need to be addressed separately (bits of server ID,
maybe refine the hash algorithm), but these ones would affect how
caches are selected, and cannot be changed without an extra option.
For random however we can perform a change without impacting anyone.

This should be backported, probably only to 3.3 since it's where the
"random" algo became the default.
doc/configuration.txt
src/backend.c