Skip to content

文档

1.redis

1.1 redis cluster pub/sub业务场景下出现内存不释放和主从内存差异问题

概要

redis cluster集群监控显示redis内存消耗在一段时间内增加且不释放,排查过程中又发现异常实例的主从节点内存不一致且差距较大(问题环境差了近100MB)。 1_1_image_1

关键词

send buffer/link-sndbuf/redis主从内存不一致

分析过程

针对该问题,排查了过期key,主从复制是否异常和redis内存分配情况后,发现额外内存非数据集占用,但是仍然无法确认这个额外占用是什么。直到在redis pr记录中发现了疑似相同问题,该问题阐述了redis cluster集群有个send buffer不释放问题(https://github.com/redis/redis/pull/9255),根据这个线索,继续查阅相关资料和redis源代码,最终发现redis cluster集群有个集群间通信的总线,其中维护着一个link->sndbuf,该buffer不会释放,且不被统计到overhead,其生命周期和link保持一致,在pub/sub业务场景中,会复用这个信道,当消息较小时影响不大,将出现较大消息时,该内存开销会增大且不释放,直观现象是redis内存增大且主从内存不一致。

详细描述

在redis cluster集群各节点通过一种Gossip协议实现节点间通信,以维护集群状态,该信道称之为redis cluster集群总线(The cluster bus),其中拥有link->sndbuf,在设计中用以传输PING/PONG/FAIL/MEET等简短消息,为了通信效率和集群稳定,该buffer不会被释放,其生命周期和link生命周期一致。

(1)redis7.0之前,redis cluster架构中,pub/sub业务复用了cluster集群消息总线(The cluster bus); (2)link->sndbuf不释放,和link生命周期保持一致,直到连接中断,该因素导致内存不释放; (3)每个link拥有单独link->sndbuf缓冲区,节点中link->sndbuf个数=(集群节点数-1),且redis字符串内存预分配策略,字符串小于1mb时,预分配大小为s_size*2,字符串大于1mb时,预分配大小为s_size+1Mb,该因素导致实际占用内存大于预期。 (4)publish客户端可以随机连接至主节点或者从节点,且link->sndbuf占用内存不被overhead统计归类到dataset之中,该因素导致主从节点used_memory内存不一致。 (5)示例 8节点4主4从集群中, publish连接节点会有7个link->sndbuf缓冲区 当pub 发布4MB大小字符串时,每个link->sndbuf的sds预分配约4mb+1mb=5mb,实际大小约5+其他头信息大小 > 5mb,7个link总消耗大于40MB左右。

模拟复现

1_1_image_2

prompt提示词

redis cluster节点间通信原理是什么 详细介绍下redis的Gossip协议

参考资料

https://github.com/redis/redis/pull/9255 https://redis.io/docs/latest/develop/interact/pubsub/ https://github.com/redis/redis/blob/6.2/src/cluster.c