美文网首页
解决关系型数据库的数据同步难题

解决关系型数据库的数据同步难题

作者: 东山公园 | 来源:发表于2021-07-01 16:46 被阅读0次

    Overview

    关系型数据库,以OLTP(Online Transaction Process)形式在存储和实体逻辑关联领域带来的价值毋庸置疑,然而在搜索,缓存,数据分析等场景却并不见长。

    关系型数据库作为企业重要的数据源,为了丰富数据的应用场景,由此产生了数据同步的需求。

    下文以搜索场景的数据同步为例说明

    Solutions

    1、同步双写

    以搜索系统建设的场景为例,业务侧应用中触发的dml事件,同时应用于rdb和Search,将dml的事件上下文以同步的形式分发到需要扩展的目标数据源,以满足Search的数据要求。

    问题:

    1)能力复用:数据同步的能力复用性不够。

    2)耦合性:业务的侵入性较大,开发阶段和运行时,对应用侧都有额外的开销。

    3)一致性:双写成功率的保证,需要额外的工作去实现。

    2、批量更新

    通过可调度的批量任务,拉取并加工数据,推送到指定的异构系统(Search),

    以满足对数据需要。

    问题:

    1)同步时延:同步延时受scheduled job的周期影响,需要根据场景定制。

    2)耦合:同步任务的开发质量影响rdb的资源。

    3)可复用的能力不够,不同场景需要多次介入;比如:同步的目标数据源是Cache、Queue、Hive。

    Syner

    我们的方案,整体采用事件驱动模式,设计如下:

    binlog-parser:通过同步binlog-parser(databus,canal)模拟rdb从库解析binlog,实时感知dml操作的变化,将rdb的binlog当成是事件源,解决同步延时的问题。

    Queue:事件驱动模式中,很重要的一部分是事件存储,我们通过MQ来做的实现。存储基于数据库表的维度来做Queue的切分,以保证表级别的事件顺序。

    Syner:核心能力是将具体的事件映射到N个目标异构系统(Search,Cache…)。简单的逻辑映射如下,左侧表示事件的来源,其本质是rdb表的行的变更(binlog基于row模式解析),右侧表示目标系统(异构系统的数据建模考虑,留待其他文章讨论)。

    Syner的工作过程:

    1)获取存储层的事件信息

    2)过滤异构系统不关注的事件信息

    3)基于事件的数据模型,转换事件的数据模型(普遍情况下与目标异构系统数据模型存在差异,源事件需要一个转换的过程)以满足异构系统的模型要求

    4)基于转换后的数据,下沉到异构系统

    Syner的行为抽象:

    1)连接存储层获取事件

    2)事件分发到应用场景,并依据“规则”转换

    3)下沉数据到异构系统

    规则引擎模式是流程自动化

    基于抽象,在步骤相对确定的情况下,通过规则引擎模式来表达整个过程,可以使得整体流程趋于自动化,达到降低开发和接入成本的目标。

    确定以规则引擎的建设思路后,工作内容分为了以下两个大的部分:

    定义规则

    1)subscribe:表示当前规则“感兴趣”的事件源范围,细化到field级别

    2)mapping:包含两个部分:

        a.事件源与目标异构系统之间的数据模型映射;

        b.事件的数据模型,普遍情况下与目标异构系统数据模型存在差异,需要有一个转换的过程,这个过程通过业务侧提供的api来实现;api的设计目标有两个:其一、将数据转换的过程从Syner脱离出来,业务侧自由定制,提高灵活性;其二、api的去向也是一种默认的sink方向(此处结合下文提到的“命令模式”理解)

    3)sinker:表示需要数据需要被分发的目标异构系统。

    实现引擎

    相对上一步来说,解析规则是引擎的一个部分工作内容,另外还需考虑:

    1)规则本身的生命周期的管理

    2)可用性:错误隔离,资源分配(比如:线程数量,队列大小,网络IO timeout 等等)

    3)吞吐量:数据一致性问题对吞吐量的影响

    4)API动态集成:对转换API的动态集成与管理

    5)同步过程管理:全量、增量、修复、校验...

    6)监控、告警

    整体架构如下

    admin:负责规则生命周期的管理,同步过程的管理(未来可包括引擎本身的动态调优)

    api-srv:负责提供指定的api接口实现,并注册到服务发现集群

    如何保证数据一致性?

    1)binlog本身的记录方式基于时间的全局序列事件;

    2)Queue,存储以表维度的拆分binlog的全局序列,保证局部有序即可;用table hash mode 可能存在Queue数据量倾斜问题,未来可通过一致性hash等的思路来解决数据平衡的问题;

    3)Syner作为事件驱动模型的dispatcher部分,为了提高吞吐量,使用的是异步多线程模型,未解决数据的不一致问题,引入趋势递增的序列号(原理借鉴snowflake)。趋势递增序列号为什么能解决这个问题?binlog本质上还是数据的snapshot,而且在到达Queue之前是严格的时间顺序,比如某一行数据x=a,第一次update之后 x=b,第二次update之后x=c,第一次update事件标记序列号为1,第二次标记为2(趋势递增必定>=2),从数据的最终一致性来理解,编号2的事件才是数据的最终版本。因此事件在最终消费时,只消费编号>=上一次的事件即可解决多线程消费下的数据一致问题。基于这个思路,还可以优化事件容量,原理类似Redis的AOF重写,一段时间内多个事件可以聚合为一个最终事件。

    针对高可用的工作内容

    1)binlog-parser的集群多节点主备,主备节点自动切换;

    2)Syner集群在规则引擎之间的相互隔离;

    3)enrich api的异步使用(结合Queue)

    4)enrich api的response的使用命令模式(SAVE、UPDATE、DELETE、NONE、ASYNC)编排sink行为

    5)同步过程中各环节数据的修复能力(自动和手动形式结合)

    命令模式

    这是一个整体的tradeoff,Syner可在不关注invoke的结果的情况下,将目标数据源的操作行为全部交由api-srv自行处理,如下图的一种实现方案(实际并未采用

    tradeoff

    1)成本:中等规模团队首要发展,仍以业务迭代为主,且对于异构数据源API学习成本偏高,投入产出相对不高

    2)质量:API的实现质量因人而异

    3)安全:目标异构源的安全性(对一个中小型团队来说仍然需要不少工作内容)。

    命令模式(指令)的划分

    Syner统一实现对于目标异构源的操作(写操作无外乎增、删、改),invoke api的返回结构中包含两个部分:1)转换后的数据内容;2)将数据内容应用于目标数据源的操作指令。

    SAVE、UPDTE、DELETE 理解为针对写的常规操作;

    NONE:表示当前事件,无需执行任何后续的操作;

    ASYNC:表示异步模式,收到当前请求后立即结束后续流程;

    NONE与ASYNC的区别在于:NONE表示不存在任何后续的操作行为,ASYNC表示收到当下的请求返回,即可结束,但是会存在异步线程处理数据结果。

    最终效果

    通过管理端(admin)对规则的定义,Syner自动感知规则生命周期变化,并动态管理规则引擎无需重启。通过已经注册好的enriche api实现数据模型的转换。同时在admin中管理同步过程。

    对于用户来说,整体过程的感知只有以下两个步骤:

    1)开发enriche api

    2)可视化的规则配置

    相关文章

      网友评论

          本文标题:解决关系型数据库的数据同步难题

          本文链接:https://www.haomeiwen.com/subject/awojultx.html