利用redissyncer实现数据双向同步

贾世闻 / 2021-07-01 16:08:44

利用redissyncer实现数据双向同步

原创 贾世闻 京东科技开发者 昨天

图片

不知不觉【数据迁移专题】已经进行了两期,在先前《跨越异构鸿沟,Redis 迁移同步过程中的挑战与解决方案》和《在线数据迁移,数字化时代的必修课》中,我们为大家介绍了数据迁移挑战与技术选型,并详细分享京东云自研开源的RedisSyncer 项目。本篇是系列内容第三篇,我们来聊一聊如何用RedisSyncer实现数据双向同步。




redissyncer简介


RedisSyncer是京东云自研的redis多任务同步中间件工具集,应用于redis单实例及集群同步。该工具集包括

  • redis 同步服务引擎 redissyncer-server
  • redissycner 客户端 redissyncer-cli
  • redis 数据校验工具 redissycner-compare
  • 基于docker-compse的一体化部署方案 redissyncer

目前在github开源:

https://github.com/TraceNature/redissyncer-server


缓存同步的定义及必要性


  • 双向同步是指在两个实例都有存量数据和写流量的情况下进行两实例同步,最终达到两实例数据动态一致的过程
  • 缓存数据全局可读,防止缓存击穿
  • 保证缓存命中率,为数据库减压
  • 当单一数据中心发生故障时,保证数据在另一中心完全可见
双向同步的操作难度与冷启动问题

  • 原生redis同步无法区分缓存数据来源
  • 由于redis本身没有实例标识(类似mysql的GTID),在双向同步时形成数据回环
  • redis环状缓冲区覆盖后,数据混淆且难于清理


基于数据冲销的双向同步方案


利用数据冲销的方式破除数据写入环。该方案的必要条件是,同步的实例或集群写入的key无冲突,即在数据中心A写入的key,不会同一时间在B中心写入相异值。


假设我们有两个redis实例redis1和redis2,再分别定义两个冲销池set1和set2,记录key及同步次数。

  1. 启动redis1->redis2的全量同步任务
  2. 启动redis1->redis2增量任务 2-1。增量任务先在set1做冲销(set1中存在的数据删除并丢弃同步) 2-2. 未被冲销数据同步到redis2
  3. 启动redis2->redis1的全量任务,此全量同步数据一定会作为增量形成回环,所以要先写入set1再写入redis1,以便数据作为增量回环同步到redis2时利用set1冲销 3-1,写入set1 3-2,写入redis1
  4. 启动redis2->redis1增量任务,增量任务先在set2做冲销(set2中存在的数据删除并丢弃同步),增量任务先写入set1在写入redis1避免循环复制 4-1。通过set2冲销数据 4-2,数据写入set1 4-3,数据写入redis1
  5. 改变redis1->redis2增量任务行为,增量任务先在set1做冲销(set1中存在的数据删除并丢弃同步),未冲销数据先写入set2再同步到redis2 5-1 写入set2 5-2 写入redis2


为什么增加第五步改变redis1->redis2增量任务行为呢?因为在第四步完成时set2中并没有从redis1->redis2的增量数据,这会造成从redis1->redis2的增量数据会转换成redis2->redis1增量数据且在本地无法被冲销,只有数据进入set1且被写入redis1后再次作为增量数据向redis2同步时才会被冲销,增加了网络开销同时redis1也增加了一次写入负载。


数据冲销方式及其缺陷


  • 数据冲销方式需要在每次发送数据前对数据进行缓冲,正常情况下缓冲内存占用不大。但当网络阻塞或由于网络不畅无法冲销数据时,会造成缓冲区暴增导致OOM
  • 数据冲销方式带来的冷启动问题
    • 当任务异常中断且redis offset被覆盖的情况下,因为数据矫正依据缺失,需要重建缓存
    • 若采用数据持久化的方式先持久化后发送的方式,那么在冲销过程中会大大降低同步效率


数据双写,看似美好其实坑多多


业务双写是最符合人类直觉的双向方案,同一份数据写入两个数据中心以保障数据冗余。但是在实际操作中会遇到数据写入顺序问题。


双写方案中的数据顺序问题


  • 并发环境中同时写入同一个key的情况下,并不能保障key写入redis的顺序。造成key的结果不一致。

  • 通过统一队列解决顺序问题
  • 网络中断导致数据缺失
  • 强一致性会导致单机房不可用的情况下写操作全局不可用,并需要在数据在某一次提交不完全成功的情况下提供回滚机制、及数据补偿机制
  • 队列带来写效率损失,redis失去作为缓存层的意义


双读方案



热门文章
最新文章
推荐文章