之前学习过 Redis Cluster,但是在 Redis Cluster 官方正式发布前,业界已经广泛使用 Codis,这篇文章主要学习一下 Codis 的整体架构和流程,对比一下 Redis Cluster。
1.笔记图
2.Codis 集群的 4 类关键组件
- codis server:这是进行了二次开发的
Redis
实例,其中增加了额外的数据结构,支持数据迁移操作,主要负责处理具体的数据读写请求 - codis proxy:接收客户端请求,并把请求转发给
codis server
- Zookeeper 集群:保存集群元数据,例如数据位置信息和
codis proxy
信息 - codis dashboard 和 codis fe:
- codis dashboard:负责执行集群管理工作,包括增删
codis server
、codis proxy
和数据迁移 - codis fe:提供
dashboard
的Web
操作界面,便于直接在Web
界面上集群管理
3.Codis 是如何处理请求的?
- 使用
codis dashboard
设置codis server
和codis proxy
的访问地址,完成设置后,codis server
和codis proxy
才会开始接收连接 - 当客户端要读写数据时,客户端直接和
codis proxy
建立连接 codis proxy
本身支持Redis
的RESP
交互协议,客户端访问codis proxy
时,和访问原生的Redis
实例没有什么区别codis proxy
接收到请求,就会查询请求数据和codis server
的映射关系,并把请求转发给相应的codis server
进行处理
4.Codis 的关键技术原理
4.1 数据如何在集群里分布?
Codis
集群一共有1024
个Slot
,编号依次是0
到1023
,可以手动分配,也可以自动均匀分配- 当客户端读写数据时,使用
CRC32
算法计算数据key
的哈希值,把这个哈希值对1024
取模,对应Slot
的编号
4.2 数据、Slot 、 codis server 的映射关系
- 数据
key
和Slot
的映射关系是客户端在读写数据前直接通过CRC32
计算得到的 Slot
和codis server
的映射关系是通过分配完成的,需要用存储系统保存,否则,集群有故障,映射关系就会丢失Slot
和codis server
的映射关系称为数据路由表(简称路由表)codis dashboard
上分配好路由表,dashboard
会把路由表发给codis proxy
,dashboard
也会把路由表保存在Zookeeper
中
5.Codis集群扩容和数据迁移
5.1 Codis 集群扩容
- 增加 codis server 时扩容步骤
- 启动新的
codis server
,将它加入集群 - 把部分数据迁移到新的
server
- 增加 codis proxy 时扩容步骤
- 直接启动
proxy
,再通过codis dashboard
把proxy
加入集群就行 codis proxy
的访问连接信息都会保存在Zookeeper
上,新增了proxy
后,Zookeeper
上会有最 新的访问列表,客户端也就可以从Zookeeper
上读取proxy
访问列表,把请求发送给新增的proxy
5.2 Codis 集群数据迁移
- 增加 codis server 时迁移数据步骤
- 在源
server
上,Codis
从要迁移的Slot
中随机选择一个数据,发送给目的server
- 目的
server
确认收到数据后,会给源server
返回确认消息。这时,源server
会在本地将刚才迁移的数据删除 - 第一步和第二步就是单个数据的迁移过程。
Codis
会不断重复这个迁移过程,直到要迁移的Slot
中的数据全部迁移完成
- Codis 的两种数据迁移模式
- 同步迁移:
- 在数据从源
server
发送给目的server
的过程中,源server
是阻塞的,无法处理新的请求操作 - 迁移过程涉及多个操作(数据在源
server
序列化、网络传输、在目的server
反序列化、在源server
删除) - 如果迁移的数据是一个
bigkey
,源server
就会阻塞较长时间,无法及时处理用户请求
- 异步迁移
- 当源
server
把数据发送给目的server
后,就可以处理其他请求操作了,不用等到目的server
的命令执行完 - 目的
server
会在收到数据并反序列化保存到本地后,给源server
发送一个ACK
消息,表明迁移完成 - 源
server
在本地把刚才迁移的数据删除 - 在迁移过程中,迁移的数据会被设置为只读,源
server
上的数据不会被修改,不会出现和目的server
上的数据不一致的问题 - 迁移bigkey:
- 对于
bigkey
,异步迁移采用了拆分指令的方式进行迁移,对bigkey
中每个元素,用一条指令进行迁移,而不是把整个bigkey
进行序列化后再整体传输 Codis
在目标server
上,给bigkey
设置过期时间,迁移过程发生故障,目标server
的key
会在过期后被删除,不影响迁移的原子性,正常完成迁移后,过期时间会被删除
可以通过异步迁移命令SLOTSMGRTTAGSLOT-ASYNC
的参数numkeys
设置每次迁移的key
数量
6.如何保证可靠性
codis server
其实就是Redis
实例,只不过增加了和集群操作相关的命令Redis
主从复制和哨兵机制在codis server
上是可以用的,Codis
使用主从集群来保证 codis server 的可靠性Codis
给每个server
配置从库,并使用哨兵机制进行监控,当发生故障时,主从库可以进行切换,从而保证了 server 的可靠性- 每个
server
成了一个server group
,每个group
中是一主多从的server
codis proxy
在转发请求时,也是按照数据所在的Slot
和group
的对应关系proxy
上的信息源头都是来自Zookeeper
(例如路由表)Zookeeper
集群使用多个实例来保存数据,只要有超过半数的Zookeeper
实例可以正常工作,Zookeeper
集群就可以提供服务,也可以保证这些数据的可靠性
7.切片集群方案选择建议
- 从稳定性和成熟度来看,
Codis
应用得比较早,在业界已经有了成熟的生产部署。虽然Codis
引入了proxy
和Zookeeper
,增加了集群复杂度,但是,proxy
的无状态设计和Zookeeper
自身的稳定性,也给Codis
的稳定使用提供了保证。而Redis Cluster
的推出时间晚于Codis
,相对来说,成熟度要弱于Codis
,如果你想选择一个成熟稳定的方案,Codis
更加合适些 - 从业务应用客户端兼容性来看,连接单实例的客户端可以直接连接
codis proxy
,而原本连接单实例的客户端要想连接Redis Cluster
的话,就需要开发新功能。所以,如果你的业务应用中大量使用了单实例的客户端,而现在想应用切片集群的话,建议你选择Codis
,这样可以避免修改业务应用中的客户端 - 从使用
Redis
新命令和新特性来看,Codis server
是基于开源的Redis 3.2.8
开发的,所以,Codis
并不支持Redis
后续的开源版本中的新增命令和数据类型。另外,Codis
并没有实现开源Redis
版本的所有命令,比如BITOP
、BLPOP
、BRPOP
,以及和与事务相关的MUTLI
、EXEC
等命令。Codis
官网上列出了不被支持的命令列表,你在使用时记得去核查一下。所以,如果你想使用开源Redis
版本的新特性,Redis Cluster
是一个合适的选择 - 从数据迁移性能维度来看,
Codis
能支持异步迁移,异步迁移对集群处理正常请求的性能影响要比使用同步迁移的小。所以,如果你在应用集群时,数据迁移比较频繁的话,Codis
是个更合适的选择