MINOR: backend: support hash-key guid for a stabler distribution
Some checks are pending
Contrib / admin/halog/ (push) Waiting to run
Contrib / dev/flags/ (push) Waiting to run
Contrib / dev/haring/ (push) Waiting to run
Contrib / dev/hpack/ (push) Waiting to run
Contrib / dev/poll/ (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run

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.
This commit is contained in:
Willy Tarreau 2026-05-19 19:06:32 +02:00
parent a59e6e5efd
commit 7004bb3b8c
4 changed files with 23 additions and 2 deletions

View 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".

View 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 */
};

View 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;

View 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;
}