Redis集群方案之Codis
codis集群中包含的4个组件
1、codis server:这是进行了二次开发的 Redis 实例,其中增加了额外的数据结构,支持数据迁移操作,主要负责处理具体的数据读写请求。
2、codis proxy:接收客户端请求,并把请求转发给 codis server。
3、Zookeeper 集群:保存集群元数据,例如数据位置信息和 codis proxy 信息。
4、codis dashboard 和 codis fe:共同组成了集群管理工具。其中,codis dashboard 负责执行集群管理工作,包括增删 codis server、codis proxy 和进行数据迁移。而 codis fe 负责提供 dashboard 的 Web 操作界面,便于我们直接在 Web 界面上进行集群管理。
Codis处理请求流程
1、首先使用codis dashboard 设置 codis server 和 codis proxy 的访问地址。
2、客户端与coids proxy建立连接。codis proxy本身支持Redis的RESP交互协议,所以与codis proxy建立连接与原生Redis没有区别。
3、coids proxy接受到请求后,会查询请求数据和coids proxy的映射关系,然后把请求转发给对应的coids server,处理完后会把结果返回给coids proxy,然后由代理(coids proxy)返回给客户端。
Codis关键技术原理
数据如何在集群里分布
在 Codis 集群中,一个数据应该保存在哪个 codis server 上,这是通过逻辑槽(Slot)映射来完成的。
coids集群又1024个Slot,编号0-1023,我们可以手动把这些Slot分给codis server,也可以使用dashboard进行自动分配。
当客户端要读写数据时,会使用 CRC32 算法计算数据 key 的哈希值,并把这个哈希值对 1024 取模。而取模后的值,则对应 Slot 的编号。此时,根据第一步分配的 Slot 和 server 对应关系,我们就可以知道数据保存在哪个 server 上了。
数据 key 和 Slot 的映射关系是客户端在读写数据前直接通过 CRC32 计算得到的,而 Slot 和 codis server 的映射关系是通过分配完成的,所以就需要用一个存储系统保存下来。
Slot 和 codis server 的映射关系称为数据路由表(简称路由表)。我们在 codis dashboard 上分配好路由表后,dashboard 会把路由表发送给 codis proxy,同时,dashboard 也会把路由表保存在 Zookeeper 中。codis-proxy 会把路由表缓存在本地,当它接收到客户端请求后,直接查询本地的路由表,就可以完成正确的请求转发了。
Codis与Redis Cluster映射区别
Codis 中的路由表是我们通过 codis dashboard 分配和修改的,并被保存在 Zookeeper 集群中。一旦路由表被修改,codis dashbaord 就会把修改后的路由表发送给 codis proxy,然后proxy就可以进行转发。
在 Redis Cluster 中,数据路由表是通过每个实例相互间的通信传递的,最后会在每个实例上保存一份。当数据路由信息发生变化时,就需要在所有实例间通过网络消息进行传递。
Codis如何进行扩容和数据迁移
扩容包括增加 codis server 和增加 codis proxy。
增加codis server
1、增加codis server,将他们加入集群。
2、把部分数据迁移到新的 server。
数据迁移过程
1、在源 server 上,Codis 从要迁移的 Slot 中随机选择一个数据,发送给目的 server。
比如原来有server 1,2,3。现在新添加了一个4,这一步就是从1或2或3中随机选一个数据发送给4。
2、目的 server 确认收到数据后,会给源 server 返回确认消息。这时,源 server 会在本地将刚才迁移的数据删除。
3、第一步和第二步就是单个数据的迁移过程。Codis 会不断重复这个迁移过程,直到要迁移的 Slot 中的数据全部迁移完成。
迁移种类:同步迁移和异步迁移
同步迁移:在数据从源 server 发送给目的 server 的过程中,源 server 是阻塞的,无法处理新的请求操作。这种比较简单,但是迁移过程会设计多个操作,包括数据在源 server 序列化、网络传输、在目的 server 反序列化,以及在源 server 删除,如果是一个bigKey,就会导致阻塞时间过长。
异步迁移:当源 server 把数据发送给目的 server 后,就可以处理其他请求操作了,不用等到目的 server 的命令执行完。目的server收到数据并反序列化保存到本地后,给源server发送一个ACK消息,这时源server删除数据。在这个过程中,目标数据被设置为只读,也就不会出现迁移完数据不一致的情况。
异步迁移对于bigKey采用拆分指令的方式。即对于bigKey中的每一个元素采用一条指令进行迁移,而不是把整个bigKey序列化然后迁移。避免了因序列化bigKey而导致的源server阻塞。
此外,当 bigkey 迁移了一部分数据后,如果 Codis 发生故障,就会导致 bigkey 的一部分元素在源 server,而另一部分元素在目的 server,这就破坏了迁移的原子性。
所以,Codis 会在目标 server 上,给 bigkey 的元素设置一个临时过期时间。如果迁移过程中发生故障,那么,目标 server 上的 key 会在过期后被删除,不会影响迁移的原子性。当正常完成迁移后,bigkey 元素的临时过期时间会被删除。
增加codis proxy
启动一个新的proxy,直接使用codis dashboard加入集群即可。
怎么保证集群可靠性
codis server 的可靠性
Codis 就使用主从集群来保证 codis server 的可靠性。简单来说就是,Codis 给每个 server 配置从库,并使用哨兵机制进行监控,当发生故障时,主从库可以进行切换,从而保证了 server 的可靠性。
在这种配置情况下,每个 server 就成为了一个 server group,每个 group 中是一主多从的 server。数据分布使用的 Slot,也是按照 group 的粒度进行分配的。同时,codis proxy 在转发请求时,也是按照数据所在的 Slot 和 group 的对应关系,把写请求发到相应 group 的主库,读请求发到 group 中的主库或从库上。
codis proxy 和 Zookeeper的可靠性
proxy 上的信息源头都是来自 Zookeeper(例如路由表)。而 Zookeeper 集群使用多个实例来保存数据,只要有超过半数的 Zookeeper 实例可以正常工作, Zookeeper 集群就可以提供服务,也可以保证这些数据的可靠性。
Codis 和 Redis Cluster对比
参考
《Redis核心技术实战》