REdis功能强大众所周知,能够大幅简化开发和提供大并发高性能,但截止到REdis-5.0.5仍然存在如下几大问题:

1) 一致性问题

这是由于REdis的主从复制采用的是异步复制,异常时可能发生主节点的数据未能复制到从节点,导致从节点提升为主节点后缺失部分数据。虽然REdis提供WAIT命令来使得主节点将数据同步给了从节点,但当前此命令可用性低。

2) 分布式事务问题

当前REdis只支持单机事务,从官方的文档来看,推荐使用“EVAL+lua”方式实现事务,而不是“MULTI+EXEC”方式。分布式事务对任何系统都是难点和挑战,短期内无实现可能,但如果只实现低级别的隔离性满足部分应用场景,则可大幅度降低实现的复杂性。

3) 从节点重启全量复制

REdis虽然有部分复制能力,但针对的是网络连接断开后重连接。部分复制依赖“repl”信息,所以当前并不直接支持(可手工操作)。

4) 进程启动速度慢

当数据量比较大时,进程要花较长时间完成启动,在启动过程中一直处于“Loading”状态,影响可用性。慢的原因不在读磁盘,而是全量逐条内存中回放重建数据。

本文专注探讨一致性问题的解决。受Hadoop的NameNode HA方案启发,REdis也可采用相同的解决方案,此方案对REdis架构基本无影响,而且代码改动量小。

redisdesktopmanager 多个节点 redis多节点数据一致性_重启

基于同样的思路,为REdis引入QJM:

redisdesktopmanager 多个节点 redis多节点数据一致性_重启_02

 

REdis主节点接收和处理写(Write)操作,然后同步到QJM,只QJM写成功后才返回给Client。数据一旦写入到QJM,由一致性协议(PaxOS或Raft等)可保证数据不会丢。

redisdesktopmanager 多个节点 redis多节点数据一致性_重启_03

一般QJM的实现可基于一致性协议PaxOS或Raft,当前也有开源的PaxOS和Raft库可直接使用,比如微信开源的PhxOS,而开源的Raft则更多,比如百度的braft等。

考虑到单个QJM集群性能有限,可以分组,比如一组REdis节点(一个主节点,加一到多个从节点组成)一组QJM集群。由于QJM只需多数写成功,因此正常情况下,新增的性能开销多数应用场景可接受。

基于此方案,不需改变REdis现有架构,并且只需要少量代码修改,主要改动点在:

1) REdis主节点不再直接同步数据到从节点,部分复制功能也不需要了(直接基于QJM做部分复制,可随意重启节点);

2) REdis主节点同步数据到QJM,并且只有同步QJM成功后才向Client返回成功(相当于WAIT命令应用在QJM写);

3) REdis从节点持续从QJM同步数据并回放;

4) REdis从节点获得选举后,并不立即进入可服务状态,而是在提供服务之前先保证已取得了QJM上最新的数据,然后才进入可服务状态。由于从节点在选举之前持续同步QJM数据,因此在获得选举时一般已是或很快包含了最新数据。

 

如果是一个新的从节点加入,则可象Hadoop NameNode一样,从节点先从主节点下载image文件(或叫快照文件),然后再从QJM部分复制形成完整数据。