转自: https://www.v2ex.com/t/535843
Redis Cluster 是一个分布式系统。由多个 Redis 实例组成的整体,数据按照 Slot 存储分布在多个 Redis 实例上,通过 Gossip 协议来进行节点之间通信。
整理理解
- redis cluster 整体上还是一个哈希分布的方案,与 twemproxy,codis 没有本质区别, 不同的地方在于,客户请求不在通过代理节点转发,而是直接与对应槽位的节点处理
- 通过 gossip 来使得集群中的节点互相了解其他节点的状况,(节点的存活情况,所持有的槽位情况等)
哈希方案:slot(槽位)
Redis Cluster 中有一个 16384 长度的槽的概念,每个 key 都会通过公式 CRC16(key) % 16384 来计算键 key 属于哪个槽,槽位是虚拟的,可以在不同节点之前迁移
-
客户端对 key 做哈希,得到槽位,并到本地路由缓存查找槽位对应的服务器节点,其中会有一些特殊情况要处理
- 访问到了错误的节点,该节点会返回正确的节点地址,让客户端重新访问
- 访问到正在迁移的节点,分好几种情况
- 访问的 key 还存储在旧的节点,直接操作
- 访问的 key 已经迁移到新的节点了,但是整个槽位还没有完成迁移,返回一个一次性的 ask 指令,让客户端尝试去新的节点查找这个 key,但是不更新这个槽位在本地的路由缓存
- 访问的 key 已经迁移,且整个槽位已经完成迁移,返回 move 指令,告诉客户端以后这个槽位都访问指定的新节点,客户端收到指令后会更新本地的路由缓存
集群通信
cluster 服务端节点直接使用 gossip 协议进行节点间通信(redis cluster 这种单纯的哈希分布的方案下,好像除了交换节点存活情况和槽位信息,服务端节点之间的数据交互需求并不高,感觉不如谷歌大数据老三篇论文里面的弱 master 节点的设计,能节省很多不必要的节点通信)
- 主要使用 cluster meet ,ping ,pong 三个命令来完成
- 通信由 meet 或 ping 命令发起
- meet 命令主要用于节点间的初次通信(?待确认)
- 节点间的握手,类似于 tcp 的三次握手,都会确保对方知道自己已经收到消息
- 定时任务 clusterCron 会向随机节点发其 ping 通信(标记下线,疑似下线,即获知其他节点的存活情况)
- 在定时心跳通信时,会附带上随机两个节点的信息,包括 ip,端口,以及节点所包含的槽位信息
- 收到心跳信息的节点,会判断附加的节点信息是否在本地记录中,
- 本地无记录,会发其 meet 通信(握手)
- 本地有记录,会进行更新(判断 epoch)
- 收到心跳信息的节点,会判断附加的节点信息是否在本地记录中,
- 数据结构
- 使用 bitmap 来表示一个节点持有的槽位信息
- 集群消息处理函数 clusterProcessPacket
slot 槽位的迁移
- A 节点的一个 slot 需要迁移到 B 节点,节点 A 设置 migrating flag, B 设置 importing flag
- 将该 slot 的 key 逐步迁移到节点 B 中
- 迁移完毕使用 cluster setslot node 来消除 importing 和 migrating flag
- 这个时候节点 B 会 bump epoch,更新专辑的 epoch 编号,来提高优先级,使得节点的槽位信息传播出去后能覆盖旧的版本
- 节点槽位信息的更新:slot 从 A 节点迁移到 B 节点后,信息同步到其他节点 C,C 节点会比较本地缓存的 A 节点的 epoch 与同步过来的 B 节点的 epoch,B 的 epoch 大,才对这个 slot 的信息进行更新
几种方案的对比
-
twemproxy 应该是最早开源的集群方案了,不过功能太过简单了,尽管使用了一致性哈希,但是集群中节点有增加时,还是会产生部分数据的丢失,而且不值钱数据分片迁移,另外是单线程了,不过单线程的问题有唯品会 twemproxies 分支解决了
-
codis 的功能相对比较完整,支持新增节点,支持数据迁移,使用 go 语言开发,而 go 的协程非常适合这种并发请求的场景,也能轻松实现对多核 CPU 的利用,不过 codis 感觉最大的问题还是所有请求都需要结果代理转发,另外就是这个项目现在官方团队已经不再维护了(搞 TiDB 去了~)
-
redis cluster 这个 redis 官方的集群方案,优势和缺点也都很明显,与 codis 的预哈希方案类似,key 哈希到某个 slot(槽位)而不再是具体的节点,使得集群可以比较平滑的伸缩,另外一个优势就是客户端与 node 节点直连,省去了代理的开销,不过 cluster 的问题也同样明显,使用 gossip 这种无中心 p2p 的协议,导致所有节点都要频繁的与其他节点交换信息,另外一个问题就是使用 redis cluster 需要升级客户端,这对很多存量业务是很大的成本
-
corvus 是饿了么开发的,加载 redis cluster 前面的一个客户端代理,主要作用是在不侵入代码的情况下使用 redis cluster,业务代理里面对 redis 的使用与原来单点的实例没有区别
-
另外还有 SSDB/ledisdb/redisdb/tidis 等实现 redis 协议的第三方实现
总结
- 在对 redis 的各种集群化方案比较思考之后,感觉加入一个弱的中心节点可能会是一个可以考虑的优化方向,redis cluster 的 p2p 方式确实增加了通信成本,而且难以获知集群的当前状态,运维上也是一个问题,后续找时间需要研究下能否在 codis 方案下做一些调整(避免使用代理转发,保证主节点高可用,主节点失效时,通过选举产生新的主节点等)
参考:
322

被折叠的 条评论
为什么被折叠?



