MINOR: server: support hash-key id32 for a cleaner distribution

The "id" hash-key scales the ID by a factor of 16 that tries to leave
room between the nodes on the 32-bit space to permit smooth weight
variations (e.g. during slowstart). However this does not deal well
with overlaps between server IDs. For example, assigning IDs that are
only multiples of 256 million to 16 servers yields traffic only on
one since in practice they all have the same 28 lower bits.

The new "id32" hash key bridges this gap by using the full 32-bit ID
of the server as the key. On the other hand, the user must be careful
not to switch the hash function to "none" when using incremental IDs
because in this case they might be very poorly distributed. But this
can be convenient for automated provisionning systems which assign
IDs themselves, as the full 32 bits are used now.
This commit is contained in:
Willy Tarreau 2026-05-19 18:35:06 +02:00
parent cb5d98c495
commit a59e6e5efd
4 changed files with 20 additions and 3 deletions

View file

@ -18850,6 +18850,15 @@ hash-key <key>
better only use values comprised between 1 and this value to
avoid overlap.
id32 The node keys will be derived from the server's numeric
identifier as set from "id" or which defaults to its position
in the server list, but the full 32 bits of the ID will be
used so that there is no collision. This one is not scaled
like "id" is, so it is recommended to either always use it
with a hash function (see "hash-key") or with explicitly
assigned ID values that are evenly distributed over the 32-bit
space.
addr The node keys will be derived from the server's address, when
available, or else fall back on "id".

View file

@ -249,7 +249,8 @@ struct pid_list {
/* srv methods of computing chash keys */
enum srv_hash_key {
SRV_HASH_KEY_ID = 0, /* derived from server puid */
SRV_HASH_KEY_ID = 0, /* derived from server puid, 28 LSB used */
SRV_HASH_KEY_ID32, /* derived from server puid, 32 bits used */
SRV_HASH_KEY_ADDR, /* derived from server address */
SRV_HASH_KEY_ADDR_PORT /* derived from server address and port */
};

View file

@ -121,6 +121,10 @@ static inline u32 chash_compute_server_key(struct server *s)
}
break;
case SRV_HASH_KEY_ID32:
key = full_hash(htonl(s->puid));
break;
case SRV_HASH_KEY_ID:
default:
key = s->puid * SRV_EWGHT_RANGE;

View file

@ -1015,13 +1015,16 @@ static int srv_parse_hash_key(char **args, int *cur_arg,
struct proxy *curproxy, struct server *newsrv, char **err)
{
if (!args[*cur_arg + 1]) {
memprintf(err, "'%s expects 'id', 'addr', or 'addr-port' value", args[*cur_arg]);
memprintf(err, "'%s expects 'id', 'id32', 'addr', or 'addr-port' value", args[*cur_arg]);
return ERR_ALERT | ERR_FATAL;
}
if (strcmp(args[*cur_arg + 1], "id") == 0) {
newsrv->hash_key = SRV_HASH_KEY_ID;
}
else if (strcmp(args[*cur_arg + 1], "id32") == 0) {
newsrv->hash_key = SRV_HASH_KEY_ID32;
}
else if (strcmp(args[*cur_arg + 1], "addr") == 0) {
newsrv->hash_key = SRV_HASH_KEY_ADDR;
}
@ -1029,7 +1032,7 @@ static int srv_parse_hash_key(char **args, int *cur_arg,
newsrv->hash_key = SRV_HASH_KEY_ADDR_PORT;
}
else {
memprintf(err, "'%s' has to be 'id', 'addr', or 'addr-port'", args[*cur_arg]);
memprintf(err, "'%s' has to be 'id', 'id32', 'addr', or 'addr-port'", args[*cur_arg]);
return ERR_ALERT | ERR_FATAL;
}