本文主要介绍Redis 4.0、Codis和云数据库Redis版集群的对比分析。
Redis 4.0版本的集群是去中心化的结构,集群元数据信息分布在每个节点上,主备切换依赖于多个节点协商选主。Redis提供了redis-trib工具做部署集群及运维等操作。客户端访问散列的数据库节点需依赖smart client,也就是客户端需要对Redis返回的节点信息做判断选择路由等操作。例如客户端请求一个节点,如果所请求的Key不在该节点上,客户端需要判断返回的move或ask等指令,重定向请求到对应的节点。
Codis由3大组件构成。
list proxy
命令获取所有Proxy列表,并根据自身的轮询策略决定访问哪个Proxy节点以实现负载均衡。
云数据库Redis版集群版架构图如下。
在3台物理机上分别搭建了以上3种Redis集群。每台物理机千兆网卡、24核CPU、内存189GB。3台物理机分别跑压测工具memtier_benchmark、Codis Proxy或阿里云Proxy、Redis server。Redis server使用各种集群配套的Redis内核。固定Key大小为32个字节,set或get操作比例为1:10。每个线程16个客户端。连续压测5分钟,分8个、16个、32个、48个、64个线程压测。因为Redis 4.0集群需要额外的客户端选择节点,而memtier_benchmark不支持,所以使用了hashtag来压测Redis 4.0。每个集群有8个master数据库和8个slave数据库,aof打开。aof rewrite的最小buffer为64 MB。压测的对象分别为单个Redis 4.0节点, 单个阿里云redis-proxy, 单核的codis-proxy,8核的codis-proxy。Codis使用的Go版本为1.7.4。压测结果图如下所示。
可以看出,单核的codis-proxy性能最弱。8核的codis-proxy压测没有对Key使用hashtag,相当于将请求分散到后端8个数据库节点上, 也可以说相当于8个阿里云的redis-proxy,自然性能数据就比较高了。单核的阿里云redis-proxy在压力够大的情况下性能逼近原生的Redis数据库节点。在实际生产环境中,使用原生的Redis Cluster,客户端需要实现Cluster protocol,解析move、ask等指令并重定向节点,随意访问Key可能需要两次访问操作才能完成,性能上并不能完全如单节点一样。
特性 | Redis 4.0集群 | codis集群 | 阿里云Redis集群 |
---|---|---|---|
事务 | 支持相同slot | 不支持 | 支持相同slot |
sub/pub | 支持相同slot | 不支持 | 支持 |
flushall | 支持 | 不支持 | 支持 |
select | 不支持 | 不支持 | 支持 |
mset/mget | 支持相同slot | 支持 | 支持 |
Redis 4.0 Cluster、Codis、阿里云Redis分布式集群均实现了面对slot的管理,扩展的最小单元是slot。分布式集群水平扩展的本质是对集群节点的路由信息管理以及数据的迁移。3种集群迁移数据的最小单位均是Key。
Redis 4.0 Cluster支持指定slot在节点中移动,也支持加入空节点后根据集群节点中已存在的slot分布自动进行再分布。以redis-trib的move_slot为例解析slot移动的过程。
迁移过程中如何保证数据的一致性:Redis Cluster提供迁移状态中的重定向机制,向客户端返回ASK,客户端收到后需先发送asking指令到目标节点上,然后再发请求到目标节点上才可以访问。当访问的Key满足以下全部条件时会出现重定向返回。
如上所述,migrate是一个同步阻塞型的操作,如果Key并不为空,即使slot处于迁移状态,Key依然能被读写,以此保证数据的一致性。
Codis对slot的再分布策略与Redis Cluster相同。codis-server内核并没有存储slot的信息,也不解析Key所在的slot,只有在dbadd等操作时将对应的Key记录到以slot为Key的dict中。如果Key带有tag,则将tag做crc32运算后将Key插入到以crc32值为key的skiplist中。Codis Dashboard后台起迁移状态机程序,先确保通知到所有Proxy开始迁移,即prepare阶段,如有一台以上Proxy失败,则迁移任务失败。迁移步骤与Redis Cluster类似,不同点是。
迁移过程中如何保证数据的一致性:Codis同样也是同步阻塞型的迁移操作。在保持数据一致性方面,因为codis-server内核不维护slot的状态,所以一致性的保证落在了Proxy组件上。codis-proxy在处理请求时,先判断Key所在slot的状态,如slot处于迁移中,则向codis-server发起指定Key迁移的命令,等Key迁移完成后,codis-proxy转向目标的codis-server请求。做法简单,对Redis内核修改较少,但同时也导致迁移慢,客户端卡住的时间较久。
阿里云Redis除了提供指定源、节点、slot外,还提供按节点的容量、slot的大小等考量参数动态分配slot,以最小粒度影响集群可用性作为分配原则。迁移大体步骤如下。
迁移过程中如何保证数据的一致性:与Codis不同,阿里云Redis在内核上同样维护了slot的信息,并且抛弃了Codis迁移整个slot和Redis Cluster迁移单个Key的做法,从内核上支持批量迁移,加快迁移速度。阿里云Redis迁移数据是异步的流程,不等待目标节点是否restore成功,由目标节点通知和源节点定时检查来验证是否成功。以此缩小同步阻塞对其他slot访问的影响。同时也是因为迁移异步化,所以在保证数据一致性时,如果是写请求并且Key存在于不在迁移的Key列表中,走正常的写请求流程。其他数据一致性保证与Redis 4.0 Cluster相同。阿里云redis-server优化了迁移大Key的方法,之前Redis瓶颈在重构数据模型,所以现优化的思路就是将源节点的数据模型一并序列化打包至目标节点。目标节点解析后预构内存,再按照解析后的member填充进去即可。
阿里云Redis内核和Proxy的热升级过程中均不断连接,对客户端无影响。
特性 | Redis 4.0 | Codis | 阿里云Redis |
---|---|---|---|
内核热升级 | 不支持 | 不支持 | 支持 |
Proxy热升级 | 无Proxy | 不支持 | 支持 |
slots槽数 | 16384 | 1024 | 16384 |
密码 | 不支持,需改redis-trib脚本。 | 支持,所有组件密码必须一致。 | 支持 |