Redis学习笔记38——通信开销:限制Redis Cluster规模的关键因素

Posted qq_34132502

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis学习笔记38——通信开销:限制Redis Cluster规模的关键因素相关的知识,希望对你有一定的参考价值。

Redis Cluster 能保存的数据量以及支撑的吞吐量,跟集群的实例规模密切相关。Redis 官方给出了 Redis Cluster 的规模上限,就是一个集群运行 1000 个实例。

为何要限制集群规模呢?

因为,实例间的通信开销会随着实例规模增加而增大,在集群超过一定规模时(比如 800 节点),集群吞吐量反而会下降。所以,集群的实际规模会受到限制。

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

Redis Cluster 在运行时,每个实例上都会保存 Slot 和实例的对应关系(也就是 Slot 映射表),以及自身的状态信息。

为了让集群中的每个实例都知道其它所有实例的状态信息,实例之间会按照一定的规则进行通信。这个规则就是 Gossip 协议。

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

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

在这里插入图片描述
所以,我们可以很直观地看到,实例间使用 Gossip 协议进行通信时,通信开销受到通信消息大小和通信频率这两方面的影响,消息越大、频率越高,相应的通信开销也就越大。如果想要实现高效的通信,可以从这两方面入手去调优。接下来,我们就来具体分析下这两方面的实际情况。

Gossip消息的大小

一个 Gossip 消息的大小是104字节。

每个实例在发送一个 Gossip 消息时,除了会传递自身的状态信息,默认还会传递集群十分之一实例的状态信息。

所以,对于一个包含了 1000 个实例的集群来说,每个实例发送一个 PING 消息时,会包含 100 个实例的状态信息,总的数据量是 10400 字节,再加上发送实例自身的信息,一个 Gossip 消息大约是 10KB。

此外,为了传递slot映射表,PING 消息中还带有一个长度为 16384 bit 的 Bitmap,这个 Bitmap 的每一位对应了一个 Slot,如果某一位为 1,就表示这个 Slot 属于当前实例。这个 Bitmap 大小换算成字节后,是 2KB。我们把实例状态信息和 Slot 分配信息相加,就可以得到一个 PING 消息的大小了,大约是 12KB。

PONG 消息和 PING 消息的内容一样,所以,它的大小大约是 12KB。每个实例发送了 PING 消息后,还会收到返回的 PONG 消息,两个消息加起来有 24KB。

虽然24KB并不算大,但是,如果一个实例传需要处理的请求并不多,那么,这个看起来也是较大的了。而且,随着集群规模的增加,这些心跳消息的的数量也会越多,进而降低集群服务的吞吐量。

实例间通信频率

Redis Cluster 的实例启动后,默认会每秒从本地的实例列表中随机选出 5 个实例,再从这 5 个实例中找出一个最久没有通信的实例,把 PING 消息发送给该实例。这是实例周期性发送 PING 消息的基本做法。

但是,毕竟是从随机选出的 5 个实例中挑选的,这并不能保证这个实例就一定是整个集群中最久没有通信的实例。

所以,这有可能会出现,有些实例一直没有被发送 PING 消息,导致它们维护的集群状态已经过期了

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

当集群规模扩大之后,因为网络拥塞或是不同服务器间的流量竞争,会导致实例间的网络通信延迟增加。如果有部分实例无法收到其它实例发送的 PONG 消息,就会引起实例之间频繁地发送 PING 消息,这又会对集群网络通信带来额外的开销了。

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

降低通信开销有两个方面,一是减少实例间通信信息的大小,二是降低通信频率。

但通信信息需要用来维持集群状态的统一,一旦减小了传递的消息大小,就会导致实例间的通信信息减少,不利于集群维护,所以,我们不能采用这种方式。所以只能考虑降低通信频率

而发送消息的频率有两个:

  • 每个实例每 1 秒发送一条 PING 消息。这个频率不算高,如果再降低该频率的话,集群中各实例的状态可能就没办法及时传播了。
  • 每个实例每 100 毫秒会做一次检测,给 PONG 消息接收超过 cluster-node-timeout/2 的节点发送 PING 消息。实例按照每 100 毫秒进行检测的频率,是 Redis 实例默认的周期性检查任务的统一频率,我们一般不需要修改它。

那么,就只有 cluster-node-timeout 这个配置项可以修改了。

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

所以,为了避免过多的心跳消息挤占集群带宽,我们可以调大 cluster-node-timeout 值,但也不能太大,否则真的发生了故障我们就需要等待更多的时间才可以检测出故障。

所以,我们可以在调整 cluster-node-timeout 值的前后,使用tcpdump命令抓取实例发送心跳信息网络包的情况。

tcpdump host 192.168.10.3 port 16379 -i 网卡名 -w /tmp/r1.cap

通过分析网络包的数量和大小,就可以判断调整 cluster-node-timeout 值前后,心跳消息占用的带宽情况了。

以上是关于Redis学习笔记38——通信开销:限制Redis Cluster规模的关键因素的主要内容,如果未能解决你的问题,请参考以下文章

Redis学习笔记38——通信开销:限制Redis Cluster规模的关键因素

Redis学习笔记38——通信开销:限制Redis Cluster规模的关键因素

redis之通信开销限制redis cluster规模的关键因素

Day764.RedisCluster规模导致的通信开销问题 -Redis 核心技术与实战

Day764.RedisCluster规模导致的通信开销问题 -Redis 核心技术与实战

Redis学习笔记—Redis与Lua