知识卡片

技巧3:采用多种手段同步数据,而非只依赖存储系统自带同步

结构图卡

内容

大部分存储系统本身就自带同步能力(MySQL主备复制、Redis Cluster、Elasticsearch集群),这看起来能直接拿来用,但也容易让人陷入”只用存储系统自带同步功能”这个思维误区——绝大多数场景下确实够用,但极端情况下往往难以满足业务需求。以MySQL为例,5.1版本的复制是单线程的,网络抖动或大批量数据同步时经常出现延迟,短则十几秒、长则十几分钟,即使靠监控发现了延迟,也基本只能干等,没什么办法主动干预。Redis也有类似问题:3.0之前没有Cluster功能,只有主从复制,而且2.8之前的版本里从机一旦宕机或和主机断连,重连时会触发全量的主从复制——这个过程主机要生成内存快照(主机本身能继续对外服务,但作为读节点的从机在此期间完全无法对外提供服务),数据量一大,恢复时间会相当长。这说明存储系统自带的同步功能在异地多机房这种容易出现各种异常的部署场景下未必够用,只依赖它反而可能做不到真正的异地多活。解决办法是打开思路,把多种手段配合存储系统同步一起用,甚至完全自己设计同步方案。以[[技巧1:保证核心业务的异地多活,而非所有业务]]提到的用户子系统为例,可以按数据特性分别采用不同手段:账号数据只会新建不会改删,用消息队列同步到其他中心即可;如果消息队列也出现延迟(用户刚在A中心注册就跑去访问B中心),可以用二次读取(本地读不到就按路由规则去对端中心再读一次)来兜底;密码数据和用户信息数据修改频率低(用户不可能1秒内连续改多次密码),直接靠数据库自带的同步机制复制就够了;session数据量很大,可以完全不同步,A中心登录后跑去B中心,B中心拿着session id按路由判断出这条session属于A中心、直接回源到A中心去取即可(反之亦然),这叫回源读取;如果回源读取也失败了(比如A中心整个宕机了),就只能让用户在B中心重新登录、生成一份新的session数据,这叫重新生成数据。这几种手段配合下来,才真正撑起了这个用户子系统的异地多活同步方案,实际设计里的细节还会比这个示意更多。

结构图

flowchart TB
  A["为何不能只依赖存储系统自带同步"]
  A --> A1["MySQL 5.1单线程复制<br/>网络抖动/大量同步时延迟十几秒到十几分钟,只能干等"]
  A --> A2["Redis 2.8前从机重连触发全量复制<br/>期间从机无法对外提供读服务"]
  A1 --> B["解法:多种手段配合甚至自研同步方案"]
  A2 --> B
  B --> C["消息队列:账号数据(只增不改)"]
  B --> D["二次读取:消息队列也延迟时<br/>本地读不到就去对端读一次"]
  B --> E["存储系统同步:密码/用户信息(修改频率低)"]
  B --> F["回源读取:session数据不同步<br/>按路由回源到归属中心取"]
  B --> G["重新生成数据:回源也失败(如A中心整体宕机)<br/>让用户在B中心重新登录生成新session"]

参考来源

- 位置:《从零开始学架构》第29讲《异地多活设计4大技巧》"技巧3:采用多种手段同步数据"(源文件:_epub-src/OEBPS/text00002.html) - 结论依据:原文说明MySQL 5.1"复制是单线程的复制,在网络抖动或者大量数据同步时,经常发生延迟较长的问题"、Redis 2.8之前"从机宕机或者和主机断开连接都需要重新连接主机,重新连接主机都会触发全量的主从复制……作为读的从机,就无法提供对外服务了",并列出消息队列方式、二次读取方式、存储系统同步方式、回源读取方式、重新生成数据方式五种具体应对手段,直接支撑本卡片结论与结构图。 - 原始内容:MySQL 5.1 版本的复制是单线程的复制……短则延迟十几秒,长则可能达到十几分钟……Redis……从机宕机或者和主机断开连接都需要重新连接主机,重新连接主机都会触发全量的主从复制……解决的方案就是拓开思路,避免只使用存储系统的同步功能。