写了一篇对 redis cluster 实现方式以及其他其他方案的对比文章 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
oncewosiwo
V2EX    程序员

写了一篇对 redis cluster 实现方式以及其他其他方案的对比文章

  •  1
     
  •   oncewosiwo
    wosiwo 2019-02-17 15:26:07 +08:00 2851 次点击
    这是一个创建于 2429 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 方案下做一些调整(避免使用代理转发,保证主节点高可用,主节点失效时,通过选举产生新的主节点等)

    参考:

    Codis 的设计与实现 Part 1

    Tidis - 基于 tikv 实现兼容 redis 协议分布式事务存储

    黄光星:Redis Cluster 原理与管理

    3 条回复    2021-04-25 16:49:14 +08:00
    haiyangcn
        1
    haiyangcn  
       2019-02-18 10:06:18 +08:00
    请教一个问题:有什么方案可以实现:redis 分布式部署,并且可以多写(在任意节点写入后同步到其他节点)
    oncewosiwo
        2
    oncewosiwo  
    OP
       2019-02-18 10:19:22 +08:00
    @haiyangcn 好像目前并没有符合“任意节点写入”这个一条的方案,codis 是一个中心的代理服务器来接收所有请求,redis cluster 里的节点只接收其所管理的槽位下的 key 的请求。如果单纯说多节点写入的话,redis cluster 算是符合要求,客户端会自动将请求发送到对应的节点中,也会将请求同步到这个节点的从节点上
    MarkrMelon
        3
    MarkrMelon  
       2021-04-25 16:49:14 +08:00
    可以转载吗, 家里的网访问不了 v2
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     861 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 22:23 PVG 06:23 LAX 15:23 JFK 18:23
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86