]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: server: support hash-key id32 for a cleaner distribution
authorWilly Tarreau <w@1wt.eu>
Tue, 19 May 2026 16:35:06 +0000 (18:35 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 19 May 2026 17:11:25 +0000 (19:11 +0200)
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.

doc/configuration.txt
include/haproxy/server-t.h
src/lb_chash.c
src/server.c

index c430a47961295d99d17edac7cf7e4c940bc266dd..ed05731658015243ace0c01e42ab1cdfa73712b9 100644 (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".
 
index 69265cb068eee7c09c130698117422575a0c934f..bbc5480818ce97be1fabe39dc889acbe9d2b2510 100644 (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 */
 };
index 362299d254bc29f3216aeb64b4e391bf373e83a1..cf34370bfaa3b4669d650d92cc68b1e4e432277b 100644 (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;
index 819e1c05a9982f3fe0f24d5c13fdf27fffd165b2..4594e1a11d80fb89ebd78788d9e8ab8a3e9685d9 100644 (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;
        }