整体架构
Binlog的同步是基于物理库的,在分库分表模式下,一个库对应一个同步任务。在精卫上创建数据同步服务时,精卫会按照物理库的数量创建对应的TASK任务。任务内Binlog按时间顺序消费,全局不保证顺序,只保证最终一致性。
MySQL Binlog
数据同步涉及源库和目标库,源库数据分为已经存在的部分(精卫称为全量)和实时写入的部分(精卫称为增量)。如果对集团数据库内核各个版本不太了解的话,本篇文档里可简单认为所有数据库都是MySQL。精卫的增量数据是通过解析MySQL的Binlog实现的,Binlog的详细介绍可参考MySQL官方文档,这里仅给出有助于理解精卫的几个关键点。
精卫使用的是Row-based Binlog 格式,该格式按照时间顺序精确的记录了数据库中每张表结构和每行数据的变更。表结构的变更称为DDL,数据的变更称为DML。DML变更包括三种事件类型,即INSERT, UPDATE, DELETE,分别表示插入一行数据,更新一行数据,删除一行数据。需要注意两点,一是这三种事件都是描述的一行数据的变化,二是这三种变更跟业务上执行的SQL不构成一一对应关系。另外,UPDATE事件包含变更前和变更后的全部信息。
一个比较直接的推理是,若数据库从创建开始后的变更都记录Binlog,那么重放这份Binlog可以精确还原该库所有表和数据。
所以精卫是一个采用Single Leader模型的异步数据复制系统。这种方式面临的问题主要有一致性如何保障、Leader不可用、复制延迟(Replication Lag)以及由此引发的多种不一致问题(如 read-after-write consistency, monotonic reads, consistent prefix reads 等)。
数据复制包括现有数据(全量)和新增数据(增量)复制两部分。全量复制可以形式化的证明其本质跟增量复制相同,所以这里只讲增量复制,精卫称之为增量同步。
精卫通过解析源库的Binlog实现增量同步,精卫只同步DML变更
设计原则
1. 最终一致
数据一致性是精卫首先要保障的设计原则。通俗的讲,精卫会保证复制到目标系统的数据与源库条数相同、每条数据所有列值相同(知道过滤代码功能的用户可以把这种一致理解为更宽泛意义上的一致)。因为精卫使用的是异步复制方式,所以精卫提供的是数据最终一致性保障。
这里讲下一致性的几个关键点。
精卫在消费Binlog这个队列时,会一批一批消费,每消费成功一批,会将该批变更的主键按顺序逐条记录在commit log中,记录完成后会将队列的消费位点做持久化保存,之后开始消费下一批变更。
这个过程中会有很多潜在问题需要考虑,业务需要关注以下几个问题:
a. 消费位点
这里先明确“消费位点”这个概念,消费位点是指精卫当前已经成功消费的Binlog队列的位置,位点是一个 'yyyy-MM-dd HH:mm:ss' 格式的时间戳,后面简称位点。
跟位点经常一起讨论的话题是位点延迟,即位点与当前时间的时间差。
b. Binlog队列长度
受存储成本限制,日常Binlog队列保存最近2小时的变更数据,线上为24小时。若位点超出这个范围,那么无法获取相应的变更数据,此时精卫无法自动处理该异常,会报警位点超出范围的异常。
c. 至少投递一次(At Leaest Once)与幂等消费
精卫任务在消费Binlog队列时随时可能停止,比如上图中步骤②成功但步骤③因磁盘满抛异常,此时精卫任务会停止从而触发自动恢复机制。为了保证消息不丢,精卫任务恢复时会从系统记录的位点重新开始投递,那么这里就有可能重复投递消息,所以精卫要求目标数据系统有幂等能力,对于精卫负责写入的数据系统,精卫会保证写入的幂等,对于自主消费类任务,会要求业务代码消费是幂等的。
产品架构
Worker
- Worker 是一个集群,其中包含一个 Leader 和多个 Worker。
- Worker 集群推荐大小:<= 300 台,更大会影响调度性能。
- Leader 本身也是 Worker,只是身兼 Leader 职责。
TaskLoader
- TaskLoader 负责执行任务。
- 所有不同类型的服务,不同的只是 Applier 部分。
- 过滤代码只有同步到 Mysql 的链路可能会有,过滤代码由用户提供,目的是清洗掉一部分不需要同步的数据。关于过滤代码:https://yuque.antfin-inc.com/jingwei3/user_wiki/pdvx78
- Pipeline 只会有两种类型会用到,Serial 和 HashGrouping,前者串行,后者并行,后者效率高。HashGrouping 保证数据按照主键有序,全局乱序。
- 集团内同步到 Mysql/ADB 的链路默认使用 Serial,原因是曾经碰到过用户修改了主键的场景。但这种场景并不常见,故如果用户遇到性能问题,我们建议用户使用 HashGrouping
高可用
- 依赖zk,把组件做成无状态的。Console 和worker 所在机器都跨机房部署。
- Console 容灾:console 集群有多台机器,其中一台抢注为 leader。
- Worker 容灾:worker 及群众所有 worker 都是无状态的,元数据信息在 zk 存储,一台 worker 挂了,任务会自动调度到其他可运行的机器上。一个机房的 worker 都挂了,也可以在另外的机房上正常的机器进行调度。
drc store
drc store负责抓取数据库的binlog增量,是数据库变更消息最起始的入口,一般一个drc store对应一台物理的db,能够保证毫秒级别的时间延迟。它的作用有以下几个方面:
连接多种数据源类型(如:mysql、oracle、hbase、oceanBase等),提供统一的增量数据格式
屏蔽数据源的主备切换、拆库扩容的情形
避免数据循环复制
保存数据表的结构信息,支持数据表DDL变更后的数据回放
metaq writer(精卫分发服务)
metaq writer也称为jingwei writer或者精卫分发服务。
数据库增量订阅平台以表的维度订阅数据,当申请一个或多个表的增量通道时,drc的rtdsq系统会负责启动若干个的metaq writer去拉取drc store的增量,一个metaq writer可以拉取多个drc store,负责把拉取到的增量数据写入到metaq,时间延迟也是在毫秒级别。它的作用有:
接受drc store中数据库所有表的变更,筛选过滤出用户订阅的表的变更
处理一条记录时,按照用户设置的散列字段做hash,和metaq分区数取模,决定一条记录写到到metaq的具体哪一个分区
经过中间metaq的分发有以下几个优势:
- 可以重用精卫binlog订阅平台的topic(了解binlog订阅平台,可以参考此文)
- binlog文件或者说drc store topic数量一般都比较少,和mysql实例数一致。如果是更新缓存的需求,就需要顺序消费,一个文件或者topic只能对应一个消费线程,或者采用进程内打散成多个内存小队列的方式,总之并发度不高。经过一层metaq,会把数据打散到多个metaq分区,通常metaq分区数会是几百,这样即使是顺序消费,并发消费的线程也可以做到几百的数量(和metaq分区数一致),能够很明显的提高性能。而且,消费metaq支持消费端机器横向扩展,可以通过简单加机器的方式做到水平扩容。在精卫3平台上表现为,可以直接为这个任务指定所需机器数量,机器扩容更加灵活。
- 环节drc store多个订阅者并发拉取的压力
- 一个库下的表关联一个topic,支持一对多的订阅,同一张表的订阅可以节约精卫侧的资源
PS:使用精卫通道,同一个库下表的下游订阅者(consumer)使用的是一个分发服务(producer),任务隔离程度没有DRC直连效果好,同时还有最大消息大小的限制,用户请按照自己的实际情况来选择
metaq
作为分布式的消息队列,暂存数据库中表的变更消息。
- 以topic的形式对外提供不同的表的增量
- topic支持多个分组同时消费,不同分组拥有不同的消费位点,支持消息回溯
- metaq的过滤代码和tag特性,能够支持对topic的数据在metaq服务端进行过滤,如对insert\update\delete消息的过滤
- metaq对相同分区内的消息可以保证消费顺序,结合散列键的设置,可以保证同一条记录的多次变更,散落到metaq相同的分区,以达到顺序消费的目的
- metaq的分区数量可以动态调整,可以通过增大metaq分区数,提高消费并发度,加快分布式消费的速度
精卫client
- 精卫client用来消费增量数据通道,一个通道包含一个消费分组,包含多个metaq topic。负责拉取平台上生成的配置,初始化metaq的client,订阅topic、注册消费分组。
- 继承metaq client的所有特性,比如:按照机器数量对topic的多个分区负责均衡;顺序消费、乱序消费等
- 动态加载最新配置,支持应用不停的情况下,修改通道,如:订阅新的表、修改表的action类型
- 通过zk,调度client的启动和停止
上传任务运行时的统计信息到zk,精卫可以监控任务运行状态和异常时报警
直连drc链路
顾名思义,精卫client会直接从drc store中获取数据,不经过metaq,链路较短,性能较好。适用于源端没有并发订阅的场景。对于直连的模式,精卫3现在主要使用drc store。
直连drc store:数据链路是binlog-->drc store-->精卫失效(更新)缓存服务,如果是单元化应用,建议选择此链路类型。 原因是:
- 这样数据链路最短,中间不经过metaq,不需要依赖拉drc store写metaq的上游服务,在单元化环境里面成本最低。
- 单元一键建站要求在很短的时间内做到一键建立新的单元环境,对精卫这里来说就是,需要把中心环境有单元化标签的服务的元信息一键复制到新单元里。对于直连drc store链路类型的服务,就可以做到一键复制到单元后即可启动运行,不存在服务的上下游依赖。
- 单元环境里的服务一般都是单元化失效缓存的需求,不太存在drc store并发订阅的问题。
直连binlog
精卫本身也有解析binlog的能力。该链路主要用于配合TDDL做一些小表广播的服务等,一般对于直连的链路,普通用户建议选择直连DRC。
binlog的解析结果在精卫中实际上是流经一个管道的。整个管道模型的结构如下图所示: