基于 Binlog 的数据同步与数据库迁移

一、海量数据存储与异构数据同步核心原理

1.1 数据分片的痛点与解决方案

  • 分片痛点:以用户 ID 为分片键的订单表,无法高效支持商家按店铺 ID 查询(全分片扫描性能极低)。
  • 通用解决方案空间换时间 ,根据业务查询需求构建多份数据存储:
    1. 订单数据:一份按用户 ID 分片供用户查询,一份按店铺 ID 分片供商家查询;
    2. 商品数据:MySQL 存储业务数据,ElasticSearch 存储供关键字搜索的索引数据(tulingmall-canal 中由ProductESData负责同步)。
  • 核心设计原则 :大规模系统中,从业务查询需求反向设计数据存储方案(数据库选型、数据结构、分片规则),而非先存储后查询。

1.2 异构数据实时同步的核心方案

  • 分布式事务的局限性:无法解决大规模、多存储的实时数据同步问题。
  • 主流实现方案 :基于MySQL Binlog + Canal + 消息队列实现,核心是将 Canal 伪装为 MySQL 从库,实时解析 Binlog 并分发数据。
  • 架构设计 :引入消息队列(RocketMQ/Pulsar)解耦上下游,解决两个核心问题:
    1. 避免 Canal 直接写入下游多数据库导致的写入性能瓶颈;
    2. 为下游数据库提供数据转换、过滤的处理时间。
异构数据同步架构图

二、不停机更换数据库

2.1 数据库更换的常见场景

  1. MySQL 单实例→分库分表集群;
  2. 自建数据库→云数据库(系统上云);
  3. MySQL→分析型数据库(如 HBase,解决 OLAP 性能不足问题)。

2.2 核心设计原则

迁移过程可逆:每一步操作后若出现故障,能快速回滚到上一稳定状态(唯一不可逆步骤为最终停旧库单写新库),避免业务长时间不可用或数据丢失。

2.3 完整迁移流程(以订单库为例)

步骤 1:全量复制 + 实时同步新旧库
  • 操作:将旧库全量数据复制到新库,基于 Binlog 开发实时同步程序,保证新旧库数据实时一致;
  • 特性:对原有业务无侵入,同步程序故障可直接停掉,无需回滚。
步骤 2:改造订单服务 DAO 层(双写 + 热切换 + 多读模式)
  1. 写操作 :支持「只写旧库」「只写新库」「同步双写」三种状态,通过热切换开关控制(无代码重启);
  2. 读操作:支持「读旧库」「读新库」切换,同样通过热切换开关控制;
  3. 业务层:无需修改,仅修改数据访问层,符合 "开闭原则"。
步骤 3:上线新版服务,仅读写旧库
  • 操作:新版服务部署后,保持「只读写旧库」模式运行1-2 周
  • 验证:服务稳定性 + 新旧库数据一致性,故障则直接回滚到旧版本服务。
步骤 4:开启双写,停同步程序(核心注意点)
  1. 双写规则:先写旧库,后写新库,以旧库结果为准(Java 代码中需保证执行顺序);
  2. 异常处理:
    • 旧库成功、新库失败:返回业务成功,记录异常日志(后续补偿);
    • 旧库失败:直接返回业务失败,不写新库(避免新库影响核心业务);
  3. 数据一致性:上线比对和补偿程序,解决 "同步程序停止 + 双写开启" 的衔接不一致问题。
步骤 5:灰度切换读请求到新库
  • 操作:以灰度发布方式逐步将读请求切到新库,故障则立即切回旧库;
  • 验证:新库的读性能、数据准确性。
步骤 6:全量切读 + 单写新库,下线旧库
  1. 全量读请求切到新库后,稳定运行一段时间,停比对程序;
  2. 将写状态改为「只写新库」,旧库正式下线(唯一不可逆步骤);
  3. 可选优化:若需可逆,可增加「双写以新库为准」过渡状态,比对程序改为 "新库补偿旧库"(成本较高,一般不采用)。
不停机数据库迁移全流程图

2.4 数据表结构变更的迁移思路

  • 新增表:直接回滚旧版本程序即可,无复杂操作;
  • 字段变更:采用双写新旧表 + 热切换开关,思路与数据库迁移一致,先双写保证数据一致,再逐步切到新表。

三、比对和补偿程序实现

3.1 核心难点

比对实时变化的两个数据库 数据,无通用的 "复制状态机" 类方案,需根据业务数据特性定制实现。

3.2 按业务数据分类的实现方案

方案 1:时效性强的静态数据(如订单)
  • 特性:订单完成后几乎无变更,数据具有 "终态";
  • 比对逻辑:按订单完成时间划分窗口,仅比对窗口内完成的订单;
  • 补偿逻辑:发现不一致,直接用旧库数据覆盖新库(以旧库为基准)。
方案 2:动态变化的数据(如商品信息)

前提 :数据带更新时间戳 (Java 实体类中需设计updateTime字段,面试常问字段设计)

  1. 比对逻辑:按更新时间划分窗口,读取旧库窗口内数据,按主键匹配新库数据;
  2. 时间窗口优化:结束时间比当前时间早 1 分钟,避免比对正在写入的脏数据
  3. 异常处理:若新库数据更新时间晚于旧库,说明比对期间数据变更,暂不补偿,放到下一个窗口重新比对。
方案 3:无时间戳的通用数据
  • 核心思路:解析旧库 Binlog获取数据变更记录,按主键到新库比对,不一致则基于 Binlog 记录补偿。

3.3 核心目标

将新旧库的数据差异逐步收敛到一致,保证双写期间数据无永久性不一致。

四、基于 Binlog 的 MySQL 数据备份与恢复

4.1 数据安全的两大核心需求

  1. 高可靠性:避免数据丢失导致的直接财产损失(如订单丢失);
  2. 高可用性:避免存储系统故障导致的业务停服损失(如电商停服)。

4.2 传统全量备份的痛点

  • 备份命令:mysqldump -uroot -p test > test.sql(MySQL 原生命令);
  • 核心问题:
    1. 备份文件大,占用大量磁盘空间;
    2. 备份过程占用 CPU/IO 资源,易锁表,导致数据库性能下降;
    3. 无法频繁备份,数据丢失后只能恢复到最近一次全量备份时间点,存在数据丢失风险。

4.3 全量备份 + Binlog 增量备份的最优方案

4.3.1 Binlog 增量备份原理
  • Binlog 是 MySQL 的数据变更操作日志,开启后会记录所有数据更新操作(增删改);
  • 核心特性:可回放,按顺序执行 Binlog 中的操作,可将数据恢复到任意时间点;
  • Java 开发关联:Canal 的核心就是解析 Binlog 日志,面试常问 Canal 与 Binlog 的关系。
4.3.2 备份恢复流程
  1. 定期执行全量备份(如每日一次);
  2. 实时保存Binlog 日志(按时间切割,避免单文件过大);
  3. 数据恢复:先恢复全量备份,再回放全量备份时间点后的 Binlog,恢复到指定时间点。
4.3.3 备份恢复的核心注意点
  1. 异地存储 :全量备份文件和 Binlog 日志不能与数据库同服务器 / 同机房,最好跨城市存储,避免机房级故障;
  2. Binlog 格式 :设置为ROW 格式 ,保证回放的幂等性(避免重复执行导致数据异常);
  3. 时间偏移 :回放 Binlog 的起始时间比全量备份时间稍提前,保证全量备份后的所有操作都被回放,无数据遗漏。
相关推荐
小高不会迪斯科9 小时前
CMU 15445学习心得(二) 内存管理及数据移动--数据库系统如何玩转内存
数据库·oracle
e***8909 小时前
MySQL 8.0版本JDBC驱动Jar包
数据库·mysql·jar
l1t9 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
失忆爆表症11 小时前
03_数据库配置指南:PostgreSQL 17 + pgvector 向量存储
数据库·postgresql
AI_567811 小时前
Excel数据透视表提速:Power Query预处理百万数据
数据库·excel
SQL必知必会12 小时前
SQL 窗口帧:ROWS vs RANGE 深度解析
数据库·sql·性能优化
Gauss松鼠会12 小时前
【GaussDB】GaussDB数据库开发设计之JDBC高可用性
数据库·数据库开发·gaussdb
+VX:Fegn089512 小时前
计算机毕业设计|基于springboot + vue鲜花商城系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
识君啊13 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端
一个天蝎座 白勺 程序猿13 小时前
破译JSON密码:KingbaseES全场景JSON数据处理实战指南
数据库·sql·json·kingbasees·金仓数据库