
前言:
Redis Cluster集群环境下,实例越多真的越好吗,吞吐量就越大吧
redis官方建议是一个集群不超过1000个实例,原因是再多可能吞吐量反而会有降低的风险,那么为什么会这样呢?我们可以继续往下看
1.实例通信方法对集群规模的影响
由于Redis Cluster集群环境下,各个实例之间需要同步slot及实例的映射信息、当前实例的信息等。因此实例之间的通信是不可以避免了,redis会按照一定的规则同步实例的信息及slot映射的信息,这个规则就是Gossip协议
1.1.Gossip协议:
保证一段时间后,集群内的每个实例都能获得其他实例的信息,哪怕新加入的实例、实例故障、Slot变更
工作原理主要包括如下:
通过了解Gossip协议之后,我们可以知道通信对集群可能造成的影响主要包括两个方面:
消息越大、频率越高,开销自然也就越大
1.2.通信频率大小
Redis实例的PING
消息的结构体clusterMsgDataGossip如下:
typedef struct {
char nodename[CLUSTER_NAMELEN]; //40字节
uint32_t ping_sent; //4字节
uint32_t pong_received; //4字节
char ip[NET_IP_STR_LEN]; //46字节
uint16_t port; //2字节
uint16_t cport; //2字节
uint16_t flags; //2字节
uint32_t notused1; //4字节
} clusterMsgDataGossip;
从结构体中我们可以得知,一条PING消息包含自身的状态信息(104字节)、默认十分之一的实例的状态信息(10*104字节)、Slot映射表(一个16384位的bitmap
,如果slot在该实例上,则为1,否则为0),所以一个PING消息的大小如下:
104 + 100 * 104(假设集群中1000个实例)+ 16384/8(slot映射表) ≈ 12 KB
再加上PONG消息,那么就是12 * 2 = 24KB的消息大小了,可能24KB不算大,但是这也是相较于业务而言,如果正常业务的单个请求只要几KB,那么就大于正常请求了,并且随着集群规模增大,心跳消息的数量会越来越多,进而影响网络带宽的占用
1.3.实例通信频率
之前说了Gossip规则是挑选一些实例进行PING
发送,那么具体规则是怎么样的呢?
实例默认会每秒从实例列表中挑选5个实例,再从5个实例中挑出最久没有通信的实例,发送PING
消息。
但是随机挑选5个实例,还是无法保证集群最久没有通信的实例会被挑选入5个实例,这有可能出现这些未被挑选的实例一直没有被发送PING信息,导致维护的集群状态过时了
为了避免,Redis Cluster实例会按照100ms每次遍历本地实例列表,如果发现有实例最近一次接受PONG
命令的时间,已经大于配置项cluster-node-timeout
的一半(cluster-node-timeout/2
),就会立即给该实例发生PING
信息。
集群规模扩大后,可能会由于网络阻塞或不正常的网络竞争导致实例列表大部分的实例都超时,这个时候就会频繁的发送PING
信息,导致额外的网络开销
我们来总结下单实例每秒会发送的PING消息数量,如下所示:
PING消息发送数量 = 1 + 10 * 实例数(最近一次接收PONG消息的时间超出cluster-node-timeout/2)
2.如何降低实例间的通信开销
-
从降低通信数据量角度入手:
由于实例之间需要依靠通信的数据进行集群的状态的数据同步,因此数据量不太好缩减,会影响集群状态的数据同步
-
从降低通信频率角度入手:
前面我们知道了实例每秒的通信次数,并且通信次数是依赖于配置项cluster-node-timeout
(默认15s),
这个参数如果过大:如果实例发生了故障,那么我们就需要等待cluster-node-timeout
时长后,才能检测出故障
参数设置过小:那么通信的频率会越来越频繁
我们可以适当调大该配置项,例如20s或25s,这样可以有效避免过多的集群消息占用网络带宽