前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为何redis cluster偏偏使用16384个槽

为何redis cluster偏偏使用16384个槽

作者头像
用户3904122
发布2022-06-29 14:56:54
3700
发布2022-06-29 14:56:54
举报
文章被收录于专栏:光华路程序猿光华路程序猿

昨天跟同事讨论redis集群,谈到redis cluster时随口吹嘘了一遍工作机制:"redis cluster采用虚拟槽分区,将key根据哈希函数映射到了16384个槽位... ..."云云

随即同事A:“为何redis cluster使用16384个槽位?”

是呀,redis cluster使用slot=CRC16(key) & 16384计算槽位。而hash函数crc16()产生的hash值有16位,自然会产生2^16=65536个值。也就是hash的值分布在0-65535范围内,按道理我们应该使用65536来进行mod操作,为何使用16384呢?

查了下,果然早有人有此疑问(https://github.com/redis/redis/issues/2576),而且作者也给出了解释:

The reason is:

  1. Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to update an old config. This means they contain the slots configuration for a node, in raw form, that uses 2k of space with16k slots, but would use a prohibitive 8k of space using 65k slots.
  2. At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs.

So 16k was in the right range to ensure enough slots per master with a max of 1000 maters, but a small enough number to propagate the slot configuration as a raw bitmap easily. Note that in small clusters the bitmap would be hard to compress because when N is small the bitmap would have slots/N bits set that is a large percentage of bits set.

总结一下,主要两个原因:

  1. 消息大小的考虑,槽位数越大,维护槽位信息占用空间越大,浪费带宽,也容易导致网络拥塞。

redis cluster中将节点加入到集群,需要执行cluster meet ip:port来完成节点的握手操作,之后节点间就可以通过定期ping-pong来交换信息,其消息头结构体如下:

代码语言:javascript
复制
#define CLUSTER_SLOTS 16384
typedef struct {
    char sig[4];        /* Signature "RCmb" (Redis Cluster message bus). */
    uint32_t totlen;    /* Total length of this message */
    uint16_t ver;       /* Protocol version, currently set to 1. */
    uint16_t port;      /* TCP base port number. */
    uint16_t type;      /* Message type */
    uint16_t count;     /* Only used for some kind of messages. */
    uint64_t currentEpoch;  /* The epoch accordingly to the sending node. */
    uint64_t configEpoch;   /* The config epoch if it's a master, or the last
                               epoch advertised by its master if it is a
                               slave. */
    uint64_t offset;    /* Master replication offset if node is a master or
                           processed replication offset if node is a slave. */
    char sender[CLUSTER_NAMELEN]; /* Name of the sender node */
    unsigned char myslots[CLUSTER_SLOTS/8];
    char slaveof[CLUSTER_NAMELEN];
    char myip[NET_IP_STR_LEN];    /* Sender IP, if not all zeroed. */
    char notused1[34];  /* 34 bytes reserved for future usage. */
    uint16_t cport;      /* Sender TCP cluster bus port */
    uint16_t flags;      /* Sender node flags */
    unsigned char state; /* Cluster state from the POV of the sender */
    unsigned char mflags[3]; /* Message flags: CLUSTERMSG_FLAG[012]_... */
    union clusterMsgData data;
} clusterMsg;

其中的unsigned char myslots[CLUSTER_SLOTS/8];维护了当前节点持有槽信息的bitmap。每一位代表一个槽,对应位为1表示此槽属于当前节点。因为#define CLUSTER_SLOTS 16384故而myslots占用空间为:16384/8/1024=2kb,但如果#define CLUSTER_SLOTS65536,则占用了8kb。

而且在消息体中也会携带其他节点的信息用于交换。这个“其他节点的信息”具体约为集群节点数量的1/10,至少携带3个节点的信息。故而集群节点越多,消息内容占用空间就越大。

  1. redis集群的主节点数据一般不可能超过1000个。

节点越多,交换信息报文也越大;另一方面因为节点槽位信息是通过bitmap维护的,传输过程中会对bitmap进行压缩。如果槽位越小,节点也少的情况下,bitmap的填充率slots/N(N表示节点数)就较小,对应压缩率就高。反之节点很少槽位很多则压缩率就很低。

所以综合考虑,作者觉得实际上16384个槽位就够了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光华路程序猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档