禧云Redis跨机房双向同步实践( 三 )


4.4 高堆积能力
由于跨机房网络的不确定性,网络隔离随时可能发生 。为了保证同步指令不丢失,我们需要把指令写到磁盘文件中,等到网络恢复时再从磁盘队列读出来写到目标机房,
为了保证同步效率,我们这里使用的是磁盘和内存混合队列MixBlockingQueue
……
下面我们再来看看磁盘队列是怎么实现的
磁盘队列包含两个文件:数据文件和索引文件 。数据结构如图4-4

禧云Redis跨机房双向同步实践

文章插图
图4-4
其中索引文件是定长的18字节:
  • redisOffset(8字节):存储每条同步指令在复制积压缓冲区的offset,每次重新启动同步任务时可以通过二分查找确定是否需要从磁盘中继续读取指令 。
  • dataOffset(8字节):存储指定在磁盘文件中的位置
  • dataLength(2字节):存储当前指令的长度
由于索引文件中数据长度为2字节,所以单条指令长度最大值为32kb,超过此大小则会丢弃这条指令
五、其他问题
5.1 Rotter连接业务Redis时造成Redis全量dump而影响业务系统
背景知识一:复制积压缓冲区
复制积压缓冲区是一个保存在主节点的一个固定长度的先进先出的队列,默认大小 1MB 。这个队列在 slave 连接时创建 。这时主节点响应写命令时,不但会把命令发送给从节点,也会写入复制缓冲区 。他的作用就是用于部分复制和复制命令丢失的数据补救 。通过 info replication 可以看到相关信息 。
背景知识二:Redis主从同步协议
禧云Redis跨机房双向同步实践

文章插图
 
背景知识三:Redis全量同步流程
  1. slave发送Replication ID, offset到master
  2. master开启一个进程执行bgsave,生成RDB文件 。在此期间所有新的指令都会缓存到当前slave的输出缓冲区中
  3. master把RDB文件发送到slave
  4. slave把RDB文件加载到内存
  5. master把输出缓冲区中的指令增量同步到slave
在这个过程中,如果Redis存储数据量过大,会导致生成RDB文件大,对磁盘IO的压力会非常大,一旦磁盘IO打满会导致Redis进入假死状态,进程没挂,客户端拿不到连接 。
我们的解决方案有两点:
  1. 优先连接Redis从节点,减少bgsave对业务的影响
  2. 配置同步任务时可以选择是否忽略全量dump,当忽略全量dump时,Rotter会通过redis info命令拿到复制积压缓冲区的offset,从最新的位置开始增量同步 。
5.2 如何防止Rotter同步反向污染源Redis数据
Redis数据同步和MySQL数据同步是相互独立的,当MySQL同步延时较大时可能会出现Redis数据反向污染的情况 。案例如下:
禧云Redis跨机房双向同步实践

文章插图
图5-2
如图5-2流程所示,Rotter同步会造成业务系统原本已经A机房删掉了记录a又被同步到A机房Redis了 。
为了解决这个问题,我们引入了删除保护的概念:一段时间(默认2分钟)内在A机房删除的数据不会从B机房同步到A机房 。具体做法如下:
  1. 图5-2中第3步Rottor-A将del a指令同步到B机房之前,生成删除保护指令setex rotter:delete:a 120 1,将这两条指令都写入redis-B
  2. 图5-2中第6步Rotter-B同步指令set a oldValue先执行 exists rotter:delete:a,返回成功判定key a是刚被删除的,不会同步A机房
原文出处: http://www.cnblogs.com/zhengyun_ustc/p/rotter.html




推荐阅读