被槽吸引
why redis-cluster use 16384 slots? #2576
【原创】为什么Redis集群有16384个槽
看到这位博主的文章,感觉redis作者的考量很有意思。
打开集群的头文件,看了一下数据结构,不出所料是16384个槽
https://github.com/antirez/redis/blob/6.0.0/src/cluster.h
1 | /*----------------------------------------------------------------------------- |
博主解释的很挺清楚的了,说白了就是不会有这么多节点,不需要太多槽。
issue 里评论区有提到 Compress bitmap to reduce network traffic
,
我觉得评论区最后的回复是对的,传输中的数据没有被压缩 No compression, just 1 bit for 1 slot
。
追查代码:
https://github.com/antirez/redis/blob/6.0.0/src/cluster.c1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24line:2433
void clusterSendPing(clusterLink *link, int type) {
...
clusterBuildMessageHdr(hdr,type);
...
clusterSendMessage(link,buf,totlen);
zfree(buf);
}
line:2329
void clusterBuildMessageHdr(clusterMsg *hdr, int type) {
...
memcpy(hdr->myslots,master->slots,sizeof(hdr->myslots));
...
}
line:2292
void clusterSendMessage(clusterLink *link, unsigned char *msg, size_t msglen) {
if (sdslen(link->sndbuf) == 0 && msglen != 0)
connSetWriteHandlerWithBarrier(link->conn, clusterWriteHandler, 1);
link->sndbuf = sdscatlen(link->sndbuf, msg, msglen);
...
}
并没有发现有压缩的过程,我猜作者想说的是,压缩位图以节省内存空间1
2
3
4
5
6
7void clusterInit(void) {
...
line:518
/* The slots -> keys map is a radix tree. Initialize it here. */
server.cluster->slots_to_keys = raxNew();
...
}
评论区老哥
看完文章,评论区老哥的问题,引起了我的兴趣:
对呀,带宽损耗可不可以算出来?
给定节点数量、实例数量、超时时间,估算带宽损耗?
嗯,这很酷。。。
博主已经介绍了ping发送数量的计算公式:数量=1+10*num(node.pong_received>cluster_node_timeout/2)
可对GOSSIP协议不够了解,计算结果和《Redis运维与实现》的例子对不上
200节点,20台物理机,15s超时,真的是占25Mb带宽吗?
跑一个看看
没那么多物理机,用docker做个测试,创建20个节点,分布在2个桥接的网络上:
10分钟后docker的状态
10分钟后redis-0的集群信息
- 通过容器的网络IO换算一下,带宽损耗1.66Mb,例子的数据是正确的~~~
((121.93MB / 600s) * 1024 / 1000) * 8 = 1.66Mbps
- 通过redis-0的网络Output来看,每个消息大约 2.91KB/msg
6.24MB * 1024 / 2197 = 2.91KB/msg
- 10分钟发送1114个ping,平均 1.86ping/s,可见公式里的 num(x) 大约是 0.086个
ping的发送
如果按本地所有节点都在默默等待超时来算,ping数量、带宽损耗会远高于观察到的结果
看源码可以知道,除了每秒固定的ping外,100ms发送ping的条件有3个
https://github.com/antirez/redis/blob/6.0.0/src/cluster.c1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25line:3389
/* -----------------------------------------------------------------------------
* CLUSTER cron job
* -------------------------------------------------------------------------- */
/* This is executed 10 times every second */
void clusterCron(void) {
...
line:3495
if (!(iteration % 10)) {
...
clusterSendPing(min_pong_node->link, CLUSTERMSG_TYPE_PING);
...
}
...
line:3575
if (node->link &&
node->ping_sent == 0 &&
(now - node->pong_received) > server.cluster_node_timeout/2)
{
clusterSendPing(node->link, CLUSTERMSG_TYPE_PING);
continue;
}
...
}
- 当前节点和目标节点的连接有效
- 没有向目标节点发过ping(没收到过目标节点的pong)
- 目标节点的本地pong接收时间已经超时
可见,我忽略了重要的第二点,即博主提到的:
在消息体中,会携带一定数量的其他节点信息用于交换。
也就是说,我向张三打听他是不是还活着,他会顺带着告诉我李四也还活着 :)
总结
由于有GOSSIP协议的信息传播,集群ping数量大幅降低
集群安装参考
https://www.runoob.com/docker/docker-redis-cluster.html
https://blog.csdn.net/alinyua/article/details/80936940
https://blog.csdn.net/u012882163/article/details/100033442