实例通信方法和对集群规模的影响

redis官方给出了Redis Cluster的规模上限为1000个实例,其中一个限制实例规模的因素就是实例间的通信会随着实例规模的增加而增大,因此在实例超过一定规模后,实例增加吞吐量反而会下降。

Redis Cluster 运行时,每个实例都会保存slot和实例的对应关系,以及自身的状态信息。为了让集群中每个实例都知道其他实例的状态,所以实例之间需要进行通信,采用的是Gossip 协议。

Gossip 协议原理

1、每个实例之间会按照一定的频率,从集群中随机挑选一些实例,把 PING 消息发送给挑选出来的实例,用来检测这些实例是否在线,并交换彼此的状态信息。PING 消息中封装了发送消息的实例自身的状态信息、部分其它实例的状态信息,以及 Slot 映射表。

2、一个实例在接收到 PING 消息后,会给发送 PING 消息的实例,发送一个 PONG 消息。PONG 消息包含的内容和 PING 消息一样。

Gossip 协议可以保证在一段时间后,集群中的每一个实例都能获得其它所有实例的状态信息。

不难看出,实例间使用 Gossip 协议进行通信时,通信开销受到通信消息大小通信频率这两方面的影响。信息越大,频率越高,影响越大。

Redis Cluster 的实例启动后,默认会每秒从本地的实例列表中随机选出 5 个实例,再从这 5 个实例中找出一个最久没有通信的实例,把 PING 消息发送给该实例。但是这样会导致有些实例一直没有被发送 PING 消息,导致它们维护的集群状态已经过期了

为了避免这种情况,Redis Cluster 的实例会按照每 100ms 一次的频率,扫描本地的实例列表,如果发现有实例最近一次接收 PONG 消息的时间,已经大于配置项 cluster-node-timeout 的一半了(cluster-node-timeout/2),就会立刻给该实例发送 PING 消息,更新这个实例上的集群状态信息。

以上频率加上每一次ping,pong所包含信息的大小,多实例的通信占用带宽可能会很多。

如何降低实例间的通信开销

针对以上分析,降低开销的办法一方面可以降低实例传输的大小,另一方面可以降低通信频率。

降低大小不可取,因为降低大小只能减少传输的字段,无法保证实例之间传输足够的信息来维持集群运行。

所以只能通过降低通信频率。可以修改cluster-node-timeout 这个配置项。

配置项 cluster-node-timeout 定义了集群实例被判断为故障的心跳超时时间,默认是 15 秒。如果 cluster-node-timeout 值比较小,那么,在大规模集群中,就会比较频繁地出现 PONG 消息接收超时的情况,从而导致实例每秒要执行 10 次“给 PONG 消息超时的实例发送 PING 消息”这个操作。

所以,为了避免过多的心跳消息挤占集群带宽,我们可以调大 cluster-node-timeout 值,比如说调大到 20 秒或 25 秒。这样一来, PONG 消息接收超时的情况就会有所缓解,单实例也不用频繁地每秒执行 10 次心跳发送操作了。

参考

《Redis核心技术实战》