MySQL数据库同步CDC方案调研

本文涉及的产品
对象存储 OSS,标准 - 本地冗余存储 20GB 3个月
对象存储 OSS,内容安全 1000 次 1年
对象存储OSS,敏感数据保护2.0 200GB 1年
简介: 数据库同步是一个比较常见的需求,业务数据一般存储在一致性要求比较高的OLTP数据库中,在分析场景中往往需要OLAP数据库或者比较火的数据湖方案;CDC是数据库同步较为流行的方案,全称是Change Data Capture,主要用于捕捉数据库中变化的数据,然后根据变化的数据写入不同的目标存储。接下来是一些数据库CDC方案的调研及原理探讨,调研方案基于MySQL数据库。

前言

数据库同步是一个比较常见的需求,业务数据一般存储在一致性要求比较高的OLTP数据库中,在分析场景中往往需要OLAP数据库或者比较火的数据湖方案;CDC是数据库同步较为流行的方案,全称是Change Data Capture,主要用于捕捉数据库中变化的数据,然后根据变化的数据写入不同的目标存储。接下来是一些数据库CDC方案的调研及原理探讨,调研方案基于MySQL数据库。

本文会主要关注同步过程中一致性的技术点,如有偏颇,欢迎拍砖。

CDC方案大致可以分为基于查询的和基于日志的方案,基于查询的方案是基于SELECT语句来查询发现变化的数据,基于日志是指MySQL的binlog,天然记录了数据库的变化数据。

基于查询的方案

基于查询是指通过定期执行SELECT语句来查看两次查询的结果的差别,每次查询都全量查询数据,然后比较两次数据的差别的方案比较重,并且对于大数据量场景效率也比较低,一般会借助数据库原有数据的递增字段来查询,比较常见的追踪变化的字段类型包括:

基于更新时间戳

在数据库的行的定义中定义更新字段,比如update_time;将上次同步的时间记为last_update_time,然后下次查询时只拉取update_time比last_update_time大的数据;

此方案实现简单,但是对于update_time有要求,在两次查询期间可能有update_time相同的数据可能会造成数据重复(update_time >= last_update_time)或者漏查(update_time > last_update_time)的风险。

基于递增主键

数据库的行中一般会定义主键,比如订单ID,用户ID等可以定义成自增主键,这些主键也可以用于跟踪变化的数据,下次查询数据只要比上次查询的数据最大的主键大就可以获取到变化的数据;

此方案对于主键有一个要求就是主键必须是递增的,新的数据的主要一定要比原有数据的主键大(类型不限),比如uuid作为主键是不适合的(uuid作为主键一般也不是最佳实践)。

还有一些其他类似的字段或者是多个字段的组合,本质上都是通过字段的递增变化来发现变化的数据。基于查询的方案有如下一些特点:

  • 要求数据库表包含递增字段,最好是严格递增字段(不含等于)。
  • 适合appendonly的数据库表,例如归档订单数据,消息表等,如果含有更新或删除操作,查询的方案往往不能发现。
  • 使用基于查询的产品有Splunk DBConnect,Kafka Connect。

基于Binlog方案

binlog是在MySQL服务层实现的独立于存储引擎的事务日志,会记录所有的DDL和和包含变更的DML,以Event的格式记录,同时会记录语句的执行时间。可以认为是MySQL的ChangeLog。binlog主要用在数据库的崩溃恢复和主从复制场景。数据同步方案类一般是模拟主从复制场景。开源领域有很多成熟的方案,如阿里的Canal,debezium等。

以下是MySQL借助binlog实现主备复制的原理:

master写入binlog后,slave通过IO线程将binlog写到自己的relay log,然后slave通过sql线程重放relay log中的事件,来实现主备的数据同步。

canal是基于master/slave的同步协议,将自己注册成slave来实现同步,主要步骤:

  • canal发送dump协议给MySQL master。
  • master收到dump请求,将binlog推送到canal。
  • canal解析binlog事件对象。

在该方案中,主要通过注册slave和dump协议来完成对数据的同步,对于订阅数据库的变更是很理想的方案,特点如下:

  • binlog记录了数据库的变更,对于增量数据的同步非常适合,比如数据的变更更新到消息系统或者更新缓存。
  • 由于master的binlog可能会删除,所以对于全量同步还是有一定局限性。

基于Snapshot+Binlog

Flink CDC 2版本在2021年发布,包含了MySQL CDC的版本更新,接下来根据分别介绍下其旧版本的原理和新版本的改进。

如果要全量读取MySQL的数据并且保持增量数据的更新,直观的方案就是先对MySQL的数据进行读取snapshot,然后接着从binlog消费变更数据。这个方案的关键点在于binlog消费与snapshot的无缝衔接。总体来说:Flink CDC 1.x使用了锁方案,Flink CDC 2使用了无锁方案。

全局锁方案

Flink CDC背后使用的是Debezium对数据进行同步,同步一张表包含两个阶段:

  • 全量同步:拉取所有表中的现有数据。
  • 增量同步:消费binlog变更数据。

全量同步阶段使用了锁,默认使用全局锁,在全局锁不可用的时候会使用表锁。我们来看下为什么需要锁,假如不用锁的情况下,可能分为如下两种情况:

  • 1)SELECT所有数据,2)读取binlog消费点,3)从binlog消费点消费:这种情况SELECT数据在执行的过程中,会消耗一定的时间,这段时间内可能会有新的更新,这个更新在SELECT数据中不存在;在SELECT数据读取完毕后,在获取binlog消费点,这时候binlog消费点可能丢失了SELECT数据后的一小段更新,造成数据丢失。
  • 1)读取binlog消费点,2)SELECT所有数据,3)从binlog消费点消费。在步骤2中的SELECT数据可能已经包含了步骤1中的消费点后的数据,比如SELECT包含了数据a,binlog消费点后包含数据a的insert,这时候步骤3从binlog消费点消费时,数据a又会插入,出现数据重复。

简单原理可以通过下图示意:图中每个格子表示一个CUD操作,可以简单的把每个格子连起来当做binlog。如果在读取Snapshot时加锁,在读完的时候再读取binlog的位置,可以保证数据是连续的,不重不漏,过早或者过晚读取binlog都会造成数据的不一致。

所以为了保证数据的一致性,需要增加全局锁或者表锁,然后借助MySQL的可重复读事务进行读取全量数据和binlog消费点,最后释放锁;在可重复事务中,可以保证消费点和当前数据的无缝衔接。在最后的binlog消费过程中,保证数据不重不漏。

该方法有如下特点:

  • 可重复读事务保证了数据库表的schema和binlog消费位点更当前数据的匹配。
  • 全局锁或者表锁,会阻止数据的更新,锁的时间越长对于数据库影响越多,特别是线上业务可能会造成业务的阻塞。

无锁方案

Flink CDC 2.0使用了无锁方案,避免了1.x中的锁造成的阻塞。方案借鉴了Netflix的DBlog的设计。主要改进在于Chunk并发读取和无锁操作。所以这里直接看下DBLog的基于Chunk的无锁实现。直接拿文中的实例来看算法的实现。


以MySQL为例,在执行SELECT前后在binlog中增加Low watermark和High watermark,这时候SELECT出的resultset一定是lw和hw之间的快照。然后在result set中去掉与lw和hw之间有重叠的数据,最后再把去掉后的数据作为output buffer,最后在执行binlog的replay,这样就能做到数据的不重不漏。可以通过一些例子来看是否有重复和遗漏:

  • 一个insert事件在lw之后,select之前,这时select的数据是包含insert的数据,把select中的数据去掉insert的条目,在执行从lw到hw的binlog replay,insert的数据还是会出现在最终结果中。
  • insert事件在select之后,hw之前,这时select不包含insert的数据,在select数据去掉insert的条目(没有改变),在执行lw到hw的binlog replay,insert的数据还是会出现在最终结果中。

同理,对于update和delete事件,都可以做到保证数据的一致性。

接下来以一个简单的图示来描述根据snapshot和binlog如何做到一致性:

上图中排除chunk的影响,把数据库的数据可以想象成binlog的序列,假设binlog是无大小限制,图中每个格子代表一个原子操作,操作序列从开始到任意一个格子按顺序apply可以得到当前数据库的所有内容。图中LW,HW代表获取的binlog位置的低水位和高水位,执行流程:

  1. 首先通过 SHOW MASTER STATUS 获取当前binlog文件的偏移量当做LW;
  2. 然后通过SELECT读取全量数据的快照Snaphost,在读取的过程中无锁操作,允许数据的插入和更新;
  3. 读取完快照Snaphost再通过SHOW MASTER STATUS获取当前binlog文件偏移量当做HW;
  4. 读取LW到HW中的数据集称为delta,设置Snapshot = Snapshot - delta;
  5. 基于最新的Snaphost,从LW开始消费binlog;从此之后可以获取数据库的Full State。

从这张图的可以看出提前读取binlog可以做到无锁读取数据库的Full State,根本原因在于从Snaphot排除掉LW到HW的binlog的影响,第4步得到的结果可以当作LW之前的全量数据;这里第4步有一个前提:数据行必须有主键,否则不好做差集操作。


通过上面的例子可以看出无锁方案获取完整数据的思路,但是在获取Snapshot时,往往数据量很庞大,由于无锁方案一般要求数据行有主键,所以可以根据主键将数据拆分成多个chunk,然后在每个chunk中执行类似操作,使用并发的方式可以提供读取的性能。细节在参考文件中会有介绍,本文主要关注在数据表Full State的获取方案,chunk方案可以参考论文或者Flink CDC 2.0的实现。还有很多细节文中没有过多介绍,比如binlog中数据库schema的变更,也会影响到数据的同步。

总结

在CDC方案中,基于查询和binlog的方案都有一定的劣势,在全量数据下,一致性方面都会有所欠缺,基于Snapshot+binlog的方案结合了两者的特点,可以保证同步数据的一致性。但是原生的基于锁的全量数据获取具有一定的性能问题,基于DBLog的无锁方案在性能和一致性上可以兼得。是比较理想的方案。

参考

Change data capturehttps://en.wikipedia.org/wiki/Change_data_capture#Methodology

Alibaba canalhttps://github.com/alibaba/canal

Flink CDC 2.0 正式发布,详解核心改进:https://flink-learning.org.cn/article/detail/3ebe9f20774991c4d5eeb75a141d9e1e

DBLog: A Generic Change-Data-Capture Frameworkhttps://netflixtechblog.com/dblog-a-generic-change-data-capture-framework-69351fb9099b

splunk DB Connect:https://splunkbase.splunk.com/app/2686/

MySQL Source (JDBC) Connector for Confluent Cloud:https://docs.confluent.io/cloud/current/connectors/cc-mysql-source.html#step-2-add-a-connector


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
2月前
|
运维 监控 关系型数据库
MySQL高可用方案:MHA与Galera Cluster对比
本文深入对比了MySQL高可用方案MHA与Galera Cluster的架构原理及适用场景。MHA适用于读写分离、集中写入的场景,具备高效写性能与简单运维优势;而Galera Cluster提供强一致性与多主写入能力,适合对数据一致性要求严格的业务。通过架构对比、性能分析及运维复杂度评估,帮助读者根据自身业务需求选择最合适的高可用方案。
|
1月前
|
NoSQL 算法 Redis
【Docker】(3)学习Docker中 镜像与容器数据卷、映射关系!手把手带你安装 MySql主从同步 和 Redis三主三从集群!并且进行主从切换与扩容操作,还有分析 哈希分区 等知识点!
Union文件系统(UnionFS)是一种**分层、轻量级并且高性能的文件系统**,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem) Union 文件系统是 Docker 镜像的基础。 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
320 5
|
3月前
|
存储 关系型数据库 MySQL
修复.net Framework4.x连接MYSQL时遇到utf8mb3字符集不支持错误方案。
通过上述步骤大多数情况下能够解决由于UTF-encoding相关错误所带来影响,在实施过程当中要注意备份重要信息以防止意外发生造成无法挽回损失,并且逐一排查确认具体原因以采取针对性措施解除障碍。
247 12
|
8月前
|
SQL 关系型数据库 数据库
【YashanDB知识库】OM仲裁节点故障后手工切换方案和yasom仲裁重新部署后重新纳管数据库集群方案
本文介绍了主备数据库集群的部署、OM仲裁故障切换及重新纳管的全过程。首先通过解压软件包并调整安装参数完成数据库集群部署,接着说明了在OM仲裁故障时的手动切换方案,包括关闭自动切换开关、登录备节点执行切换命令。最后详细描述了搭建新的yasom仲裁节点以重新纳管数据库集群的步骤,如生成配置文件、初始化进程、执行托管命令等,确保新旧系统无缝衔接,保障数据服务稳定性。
|
8月前
|
关系型数据库 MySQL Shell
MySQL 备份 Shell 脚本:支持远程同步与阿里云 OSS 备份
一款自动化 MySQL 备份 Shell 脚本,支持本地存储、远程服务器同步(SSH+rsync)、阿里云 OSS 备份,并自动清理过期备份。适用于数据库管理员和开发者,帮助确保数据安全。
|
4月前
|
SQL 关系型数据库 MySQL
解决MySQL "ONLY_FULL_GROUP_BY" 错误的方案
在实际操作中,应优先考虑修正查询,使之符合 `ONLY_FULL_GROUP_BY`模式的要求,从而既保持了查询的准确性,也避免了潜在的不一致和难以预测的结果。只有在完全理解查询的业务逻辑及其后果,并且需要临时解决问题的情况下,才选择修改SQL模式或使用 `ANY_VALUE()`等方法作为短期解决方案。
621 8
|
3月前
|
监控 NoSQL 关系型数据库
保障Redis与MySQL数据一致性的强化方案
在设计时,需要充分考虑到业务场景和系统复杂度,避免为了追求一致性而过度牺牲系统性能。保持简洁但有效的策略往往比采取过于复杂的方案更加实际。同时,各种方案都需要在实际业务场景中经过慎重评估和充分测试才可以投入生产环境。
224 0
|
8月前
|
消息中间件 关系型数据库 MySQL
基于 Flink CDC YAML 的 MySQL 到 Kafka 流式数据集成
基于 Flink CDC YAML 的 MySQL 到 Kafka 流式数据集成
861 0
|
4月前
|
关系型数据库 MySQL Java
MySQL 分库分表 + 平滑扩容方案 (秒懂+史上最全)
MySQL 分库分表 + 平滑扩容方案 (秒懂+史上最全)
|
9月前
|
Java 关系型数据库 MySQL
SpringBoot 通过集成 Flink CDC 来实时追踪 MySql 数据变动
通过详细的步骤和示例代码,您可以在 SpringBoot 项目中成功集成 Flink CDC,并实时追踪 MySQL 数据库的变动。
2297 45

推荐镜像

更多