阿里云redis和豌豆荚codis架构分析

未来已来2018-09-18 09:37

本文来自网易云社区


作者:乔安然

阿里云redis
阿里云redis集群由三个组件构成,尚未开源实现细节目前不太清楚:
  • redis-config:集群管理工具
  • redis-server:优化过源码的redis,支持slot,扩容迁移等
  • redis-proxy:单线程,c++14语言实现
架构图:


redis-proxy无状态,集群可挂多个proxy节点
redis-config双节点,集群的元数据存储在关系型数据库内。config逻辑不清楚,目前没有开源。
集群的主备切换由独立的HA组件负责

水平扩展:
阿里云redis除了提供指定源、节点、slot外,还提供按节点的容量、slot的大小等考量参数动态分配slot,以最小粒度影响集群可用性作为分配原则。迁移大体步骤如下:
  • 步骤1): 由redis-config计算源、目标节点、slot
  • 步骤2): redis-config向redis-server发送迁移slot指令
  • 步骤3): redis-server启动状态机,分批量迁移key
  • 步骤4): redis-config定时检查redis-server并更新slot状态
与codis不同,阿里云redis在内核上同样维护了slot的信息,并且抛弃了codis迁移整个slot和redis cluster迁移单个key的做法,从内核上支持批量迁移,加快迁移速度。
阿里云redis迁移数据是异步的流程,不等待目标节点是否restore成功,由目标节点通知和源节点定时检查来验证是否成功。以此缩小同步阻塞对其他slot访问的影响。
同时也是因为迁移异步化,所以在保证数据一致性时,判断请求如果是写请求并且key存在且不在迁移的key列表中,走正常的写请求流程。其他数据一致性保证与redis4.0 cluster相同


codis
选择最新codis 3.x版本,codis由以下组件组成:
  • Codis Server :基于redis-3.2.8版本开发。
  • Codis Proxy: go语言实现,采用多线程
  • Codis Dashboard:go实现,集群管理工具,支持codis-proxy、codis-server的添加、删除,以及数据迁移等操作。
    • 所有对集群的修改必须通过codis-dashboard完成
    • 对于同一个业务集群而言,同一个时刻 codis-dashboard 最多1个
  • Codis Admin:集群管理的命令行工具。
    • 可用于codis-proxy、codis-dashboard状态以及访问外部存储
  • Codis FE:集群管理界面
    • 前端展示页面可以集成多个集群实例
    • 通过配置文件管理后端 codis-dashboard 列表,配置文件可自动更新。
  • Storage:为集群状态提供外部存储。仅存储集群元数据
    • 使用Namespace概念,不同集群按照product name组织。
    • 目前提供zookeeper、etcd、fs三种实现,但提供了接口可自行扩展
架构图:
codis使用了redis cluster中slot功能,但slot只有1024个,而非16384。集群主从切换由sentinel负责,没有采用redis cluster的无中心、gossip传播,所以不同group的redis节点彼此独立、无感知。

高可用:
由redis-sentinel负责切换。codis-proxy去订阅redis-sentinel,获取节点变化。
在3.1版本之前使用codis-ha组件来实现,通过codis-dashboard开放的api实现自动切换主从。
codis-ha默认以5s为周期,从codis-dashboard中拉取集群状态,并进行主从切换,而且切换必须得到所有proxy的确认。在3.2版本不再使用,估计可靠性无法保证。

Codis proxy:
使用go语言实现采用多线程,支持部署多个实例。
支持MGET、MSET、SELECT 命令,支持pipeline模式
slot分布表依赖Dashboard同步,自己不主动更新
提供http接口由Dsshboard调用,主要的接口:
/api/proxy/xping : 探活ping接口
/api/proxy/stats : 状态
/api/proxy/slots : 获取proxy slot分布表
/api/proxy/fillslots : 更新slot状态,在slot迁移操作时,Dashboard会先调用此接口将slot更新为 迁移状态,迁移完成后,Dashboard再调用该接口更新slot迁移完成。
/api/proxy/sentinels/{xauth}/rewatch : watch 新的sentinel

Codis Dashboard:
每个集群只有一个该组件,多集群管理通过前端页面集成各集群的Dashboard接口构成。
定时主动检查和同步codis-proxy、redis、sentinel状态,检测间隔时间1s
slot管理:
slot分布表数据保存在storage组件中,Dashboard也自身缓存
slot迁移:
codis中定义group概念,可以理解为一对主从。当slot由一个group迁移到另一group时,Dashboard将slot分布表数据更新到storage组件和自身缓存。Dashboard中处理slot的定时任务(间隔1s)检测中slot变化,会将其信息同步给所有的proxy,proxy将其对应的slot标记为迁移中。再对源redis节点不停发送异步的slot迁移命令 SLOTSMGRTTAGSLOT-ASYNC直至slot迁移完成,在迁移的过程中,proxy处理slot上的key请求都会先执行 SLOTSMGRTTAGONE,再去处理key请求。Dashboard将slot迁移完成之后再更新所有的proxy,proxy更新后slot的请求正常处理。

水平扩展:
1、添加新group,新增redis节点
2、通过codis Dashboard分配些slot到新group,这个动作只是更新storage组件中的slot分布表。有定时任务检测执行slot迁移,具体的执行见上面的slot迁移。
3、redis异步执行过程:
  • redis接受到SLOTSMGRTTAGSLOT-ASYNC或者SLOTSMGRTTAGONE,将扫描出指定的key或者指定数量的一批key值
  • 初始化slot迁移客户端连接目标redis节点,发送SLOTSRESTORE-ASYNC-AUTH和SLOTSRESTORE-ASYNC-SELECT命令进行验证和指定迁移的db。
  • 发送SLOTSRESTORE-ASYNC命令将key-value出传播到目标节点,源redis节点迁移操作结束。
  • 目标节点接受到key-value时进行处理,之后返回slotsrestore-async-ack确认。源节点再对key进行delete处理。
数据一致性保证:
codis Dashboard将所有proxy中slot信息更新,状态为迁移中。所有该slot的key经过proxy时,proxy都会先执行 SLOTSMGRTTAGONE,这样可以保证key迁移到新节点,再处理key请求。但该解决办法简单粗暴,重复的key请求仍会执行迁移命令。
vs redis cluster:
相对于redis cluster的迁移slot,改进就是不再阻塞等待目标节点restore成功,由后续slotsrestore-async-ack来保证

jodis:
codis客户端,配合jedis使用,只是对jedis连接池做了扩展。连接地址从zk中获取。

本文来自网易云社区,经作者乔安然授权发布

网易云免费体验馆0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区