写在前面

codis和Redis cluster 都是Redis的集群方案,本文就一起来看下。

1:codis的组件和架构

codis的组件有4个,如下:

codis server:基于redis进行了二次开发的组件,负责数据的读写
codis proxy:面向客户端,代理客户端访问codis server
zookeeper 集群:保存元数据,如数据路由表信息,codis proxy信息
codis dashboard,codis fe:codis dashboard提供维护codis server,codis proxy等功能,codis fe提供web界面,方便管理人员使用。

架构图如下:

cluster codis redis 比较 codis和redis cluster_redis

2:codis工作原理

2.1:客户端如何获取codis proxy信息

客户端通过zookeeper集群获取codis proxy信息,如当前有3个codis proxy实例,则在客户端就可以随机选择一个codis proxy来访问,达到负载均衡的效果如下图:

cluster codis redis 比较 codis和redis cluster_codis server_02

如图中红框部分就是客户端获取codis proxy列表,当codis proxy有增减时客户端都能动态的通过zookeeper感知。

2.2:数据是如何分布的

我们在redis之分片集群 一文中分析了redis cluster的数据分布是通过16384个槽(slot)分配到各个redis实例节点完成的,codis的数据分布方案与之类似,不同之处在于槽slot的个数是1024,编号0~1023,分配的方式有手动分配和基于codis dashboard自动分配两种方式,分配完成后没有差异,都是一个codis server负责一批slot数据的读写,其中映射到codis server的过程是crc32(key)/1023,获取的结果就是槽号,而槽对应codis server,这样就能找到目标codis server了,这个寻找的过程可能如下图:

cluster codis redis 比较 codis和redis cluster_codis server_03

slot和codis server分配后的对应关系我们叫做路由表,路由表维护在zookeeper集群中,并且在codis proxy本地也会缓存一份,提高路由的性能,分配过程如下图:

cluster codis redis 比较 codis和redis cluster_客户端_04

2.3:codis proxy压力过大怎么办

因为客户端直连codis proxy,当客户端请求压力比较大时,可能处理不过来,此时需要增加codis proxy节点,然后在codis dashboard中配置即可,配置后信息会同步到zookeeper集群中,然后客户端就可以从zookeeper集群中获取最新的codis proxy列表了,这个过程如下图:

cluster codis redis 比较 codis和redis cluster_redis_05

2.4:codis server压力过大怎么办

codis server实际就是redis实例,用来实际处理数据的读写请求,当其压力过大时,需要增加codis server节点,当增加节点后,信息会同步写到zookeeper中,然后codis proxy就可以获取最新的codis server列表信息,并缓存到本地了。但是,增加codis server的最大问题是数据迁移,数据迁移具体做法是:

1:随机选择一批slot分配给新codis server
2:针对每个slot循环执行如下操作
    1:选择slot中的一个key同步到新codis server,收到ACK后将该key从源codis server删除
    2:继续同步其他key,直到全部同步完成

以上同步一个slot的过程可能如下图:

cluster codis redis 比较 codis和redis cluster_redis_06

当数据量较大,或存在一些bigkey时,数据迁移时间可能较长,当使用同步迁移时源codis server将无法处理数据的读写请求,降低codis的性能,为了解决这个问题codis提供另外一种数据迁移方式,即异步迁移。另外还有一个问题是对bigkey处理,bigkey因为较大,一次迁移完成可能会占用较多的宽带和CPU等资源,给服务器的稳定性造成隐患,因此对bigkey的迁移方式是通过将其拆分成一个个命令来迁移,即化整为零,如有一万个元素的key,先通过lpop从源codis server获取数据,然后发送命令rpush key value到新codis server,直到全部执行完成,并且这个过程中为了保证迁移的原子性,会给新codis server的key设置一个有效时间,这样如果是迁移过程中出现问题,数据也会自动删除,而迁移完成后只需要删除过期时间 就行了。

2.5:客户端需要重新开发吗?

codis proxy支持RESP协议,可以像访问一个普通的redis实例一样访问,所以不需要修改客户端代码,但是因为codis proxy是集群的,所以客户端需要有简单的负载均衡逻辑,即选择一个codix proxy来访问,当然,这个改动其实是不大的,因为只要动态的修改redis的数据源地址就可以了,业务代码丝毫不会受到影响。

2.6:集群的可靠性保证

2.6.1:codis proxy

是多实例的,且信息动态维护在zookeeper集群中,所以codis proxy组件是可靠的。

2.6.2:zookeeper

集群部署,只要有超过一半的节点正常,就可以正常提供服务,所以zookeeper组件是可靠的。

2.6.3:codis server

codis server本质上就是一个redis实例,将其配置主从的集群,然后通过哨兵 实现主节点故障时的主从切换,此时codis server组件也是可靠的。

3:codis VS redis cluster

codis大概是在2014年左右就发布的版本,提供了基于redis的集群功能,截止到写这篇文章,已经走了8年多将近九年的时间,而redis cluster是在redis3.0版本,大概是在2017年发布的,这部分我们就来对比下二者的优势和劣势,以及在实际应用中应该如何选择。

对比项

codis

redis cluster

可靠性

可靠

可靠

扩容

支持

支持

数据迁移

同步迁移,异步迁移

同步迁移

客户端兼容性

兼容

不兼容,需要支持cluster的客户端

组件数量


不需要额外组件,只需要redis实例

成本

组件多,成本高

不需要额外组件,成本低

成熟度


低于codis

我司选择的是Redis cluster,原因如下:

1:官方提供,可靠性比较有保障
2:组件少,部署和运维成本都更低
3:组件少,金钱成本更低(该因素很重要!!!)

写在后面

参考文章列表:

吃透Redis系列(九):Redis代理twemproxy和predixy详细介绍 。