]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: backend: support hash-key guid for a stabler distribution
authorWilly Tarreau <w@1wt.eu>
Tue, 19 May 2026 17:06:32 +0000 (19:06 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 19 May 2026 17:11:25 +0000 (19:11 +0200)
When server fleets are constantly updated, using a stable distribution
across a bunch of load balancers can be convenient. The addr and port
already provide a bit of this but for situations were addresses might
differ between sites or change dynamically this does not work. The guid
is perfect for this because by definition it's supposed to designate a
single server and be unique. So when two servers anywhere have the same,
the tool that provisionned them promises that they are the same server.

So here we introduce "hash-key guid" which performs a 32-bit hash on
the GUID value. When no guid is provided, a fallback is performed on
ID, as is done for other keys.

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

index ed05731658015243ace0c01e42ab1cdfa73712b9..bfed9369834af0fe1493d1b0055914a6ba9e56ea 100644 (file)
@@ -18859,6 +18859,12 @@ hash-key <key>
                  assigned ID values that are evenly distributed over the 32-bit
                  space.
 
+      guid       The node keys will be derived from the server's guid, when
+                 available, otherwise they will fall back on "id". The benefit
+                 is that it does not depend on ordering at all, only on an
+                 internal stable identifier that can be replicated across many
+                 load balancers.
+
       addr       The node keys will be derived from the server's address, when
                  available, or else fall back on "id".
 
index bbc5480818ce97be1fabe39dc889acbe9d2b2510..a3dbc606a3812bf44583bfbc2d366f08cbccd98a 100644 (file)
@@ -251,6 +251,7 @@ struct pid_list {
 enum srv_hash_key {
        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_GUID,           /* derived from server guid */
        SRV_HASH_KEY_ADDR,           /* derived from server address */
        SRV_HASH_KEY_ADDR_PORT       /* derived from server address and port */
 };
index cf34370bfaa3b4669d650d92cc68b1e4e432277b..ce60bee8ba5af9cb09ca09cd1fc638713934a7ab 100644 (file)
@@ -20,6 +20,7 @@
 #include <haproxy/api.h>
 #include <haproxy/backend.h>
 #include <haproxy/errors.h>
+#include <haproxy/guid.h>
 #include <haproxy/queue.h>
 #include <haproxy/server.h>
 #include <haproxy/tools.h>
@@ -82,6 +83,7 @@ static inline u32 chash_compute_server_key(struct server *s)
 {
        enum srv_hash_key hash_key = s->hash_key;
        struct server_inetaddr srv_addr;
+       const char *guid_key = NULL;
        u32 key;
 
        /* If hash-key is addr or addr-port then we need the address, but if we
@@ -96,6 +98,11 @@ static inline u32 chash_compute_server_key(struct server *s)
                }
                break;
 
+       case SRV_HASH_KEY_GUID:
+               guid_key = guid_get(&s->guid);
+               if (!guid_key)
+                       hash_key = SRV_HASH_KEY_ID;
+               break;
        default:
                break;
        }
@@ -121,6 +128,10 @@ static inline u32 chash_compute_server_key(struct server *s)
                }
                break;
 
+       case SRV_HASH_KEY_GUID:
+               key = XXH32(guid_key, strlen(guid_key), 0);
+               break;
+
        case SRV_HASH_KEY_ID32:
                key = full_hash(htonl(s->puid));
                break;
index 4594e1a11d80fb89ebd78788d9e8ab8a3e9685d9..9ebce0c8c2f8704f43d0f40fb2b2c1983d5ef869 100644 (file)
@@ -1015,7 +1015,7 @@ 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', 'id32', 'addr', or 'addr-port' value", args[*cur_arg]);
+               memprintf(err, "'%s expects 'id', 'id32', 'guid', 'addr', or 'addr-port' value", args[*cur_arg]);
                return ERR_ALERT | ERR_FATAL;
        }
 
@@ -1025,6 +1025,9 @@ static int srv_parse_hash_key(char **args, int *cur_arg,
        else if (strcmp(args[*cur_arg + 1], "id32") == 0) {
                newsrv->hash_key = SRV_HASH_KEY_ID32;
        }
+       else if (strcmp(args[*cur_arg + 1], "guid") == 0) {
+               newsrv->hash_key = SRV_HASH_KEY_GUID;
+       }
        else if (strcmp(args[*cur_arg + 1], "addr") == 0) {
                newsrv->hash_key = SRV_HASH_KEY_ADDR;
        }
@@ -1032,7 +1035,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', 'id32', 'addr', or 'addr-port'", args[*cur_arg]);
+               memprintf(err, "'%s' has to be 'id', 'id32', 'guid', 'addr', or 'addr-port'", args[*cur_arg]);
                return ERR_ALERT | ERR_FATAL;
        }