作者简介
布莱德,携程技术专家,负责Redis和Mongodb的容器化和服务化工作,喜欢深入分析系统疑难杂症。
向晨,携程资深数据库工程师,专注于数据库和缓存智能运维工作。
一、背景
2019年,随着携程G2战略和国际化的推进,有一些大容量的Redis集群需要出海对海外客户提供服务,相比私有云的单GB成本,公有云上的Redis要贵10倍左右,这迫切需要我们寻找一种能替代Redis的廉价方案部署在海外,我们开始着手调研Redis On SSD的可行性。
二、调研和选型
携程大部分Redis数据是通过xpipe同步到海外(图1),而xpipe是实现了Redis复制协议的伪slave, 为了让海外基于SSD存储的替代Redis的方案能够顺利落地,需要兼容Redis的协议,Redis的协议基本分为两大块:
1)面向客户端的协议,如ping/set/get等客户端的命令。
2)复制协议,slave同步master时需要用到。
图1
我们调研了目前绝大部分Redis的替代方案,如Redislabs的Redis On Flash(https://redislabs.com/lp/redis-enterprise-flash/), 360的pika(https://github.com/Qihoo360/pika)和美图的kvrocks(https://github.com/bitleak/kvrocks),其中Redis On Flash是商业化的产品,无开源代码,pika市面上使用的公司比较多,但缺点也很明显:
1)面向客户端的协议是Redis的二进制协议,而面向复制的却是基于google的protobuf格式,语义层面有割裂感。
2)复制是基于Rsync的多进程模式,这种复制模式比较重,出现问题也不好定位。
3)代码风格比较乱,此外网络类库也用的是360自家的pink,二次开发比较困难。
而kvrocks很好的避免了pika的这些问题,语义和复制上与Redis原生的更加接近,缺点是刚刚开源,几乎无任何公司来使用kvrocks,经过权衡,我们发现kvrocks的整体框架和代码比较好把握,我们还是决定基于kvrocks做二次开发。
为什么要二次开发呢?因为面向客户端的协议pika/kvrocks可以达到90%以上的Redis兼容,但复制协议都不兼容,究其原因在于,无论pika还是kvrocks,其底层的存储引擎都是rocksdb,而rocksdb是基于磁盘的KV存储方案,数据已经落盘成文件的无需再像Redis那样复制时将Master内存的数据保存到文件中再发送到slave端,直接传输文件更高效。为了让业务和中间件少改动,我们基于kvrocks进行二次开发,用来支持Redis的SYNC/PSYNC协议,也就等于支持了xpipe,最终的同步模式也就如图2所示。
图2
三、二次开发
二次开发前,必须厘清,一个kvrocks实例要成为一个Redis的slave,有以下几个步骤:
1)执行slaveof后的Redis slave状态机模拟,如下图3所示。
2)对于全量同步的逻辑,也就是图三中的REPL_STATE_TRANSFER状态,会接受来自master的RDB文件,接受完成后,需要解析RDB。
3)完成RDB文件解析后,模仿正常客户端命令写入Rocksdb中。
4) 进入CommandPropogate阶段后,死循环接受Master传来的增量命令,每一秒ACK一次当前的offset。