计算机系统应用  2018, Vol. 27 Issue (6): 60-68   PDF    
MySQL集群到Oracle数据库的数据同步方法
杨明珉, 陈勇     
中国移动(深圳)有限公司, 深圳 518048
摘要:随着开源技术的蓬勃发展, 开源数据库在很多业务场景中已经完成对商用数据库的替换, 其中MySQL数据库对于Oracle数据库的替换最为常见. 在分阶段替换的过程中往往存在MySQL数据库和Oracle数据库在同一套业务系统中并存, MySQL数据库需要向Oracle数据库进行数据同步的情况. 同时, MySQL数据库多节点高可用集群的部署方式进一步增加了数据同步的难度. 通过研究运用Oracle GoldenGate软件对MySQL集群进行数据抽取的方法, 设计出一套行之有效的方案, 实际解决从MySQL集群向Oracle数据库同步数据的难题, 同时保证了同步过程中数据库的一致性和完整性.
关键词: Oracle    MySQL集群    GoldenGate    异构数据库同步    
Data Synchronization Method for MySQL Cluster to Oracle Database
YANG Ming-Min, CHEN Yong     
China Mobile (ShenZhen) Limited, Shenzhen 518048, China
Abstract: With the rapid development of open source technology, open source database has completed the replacement of commercial database in many business scenarios. The substitution of MySQL database for Oracle database is the most common. In the process of staged substitution, MySQL database and Oracle database often exist in the same set of business system, and MySQL database needs to synchronize data with Oracle database. At the same time, the deployment mode of multi node and high availability cluster in MySQL database further increases the difficulty of data synchroni-zation. By researching the method of data extraction of MySQL cluster by using Oracle GoldenGate software, we design a set of effective schemes to solve the problem of synchronizing data from MySQL cluster to Oracle database, and ensure the consistency and integrity of database in the process of synchronization.
Key words: Oracle     MySQL cluster     GoldenGate     heterogeneous database synchronization    

引言

从新兴的互联网行业到其他的传统行业, 使用开源的数据库替代传统商业数据库一直是IT系统建设的一个趋势. 以MySQL数据库为代表的开源数据库, 在多种业务场景中已经完成或者正在进行对以Oracle数据库为代表的大型商用数据库的替换. 然而, 在很多IT系统中, 由于应用程序的开发与数据库的紧密关联, 数据库的更替涉及到大量的应用程序改造和数据库迁移, 不可能做到一蹴而就. 这将存在开源数据库和原有商用数据库在同一套IT系统中长期并存, 数据相互耦合的情况. 其中, MySQL数据库向Oracle数据库做数据同步是最为常见的需求之一. 异构数据库之间的数据同步向来是IT系统工程实施的难点, 而在核心IT系统中, MySQL数据库往往以多节点高可用集群的方式部署, 这又为其向Oracle数据库做数据同步进一步增加了难度.

本文采用在异构数据库同步中表现良好的Oracle GoldenGate作为MySQL数据库到Oracle数据库的数据同步工具, 意在研究设计出一套行之有效的方案, 实际解决从MySQL集群往以Oracle为代表的异构数据库同步数据的难题.

1 MySQL集群与Oracle GoldenGate介绍 1.1 基于主从复制的MySQL集群简介

MySQL集群架构有多种实现方式, 最为常见的包括基于主从复制、基于磁盘复制和基于网络存储引擎(ndb)的集群架构, 其中目前使用最为广泛的是基于主从复制的集群架构, 也是本文论述的MySQL集群架构.

主从复制技术在MySQL 5.5版本被引入, 可用于构建MySQL高可用架构方案, 其原理是通过把主数据库(以下简称主库)记录事务信息的二进制日志传递和应用到从数据库(以下简称从库), 从而保证主库和从库的数据一致性. 主从复制的实现总体上分为3步:

1) 主库在完成每个事务的数据更新之前, 首先将相应的事务变更信息记录到二进制日志中, 所有的事务变更信息是以串行的方式写入二进制日志. 只有当每个事务变更信息被成功写入二进制日志后, 该事务的数据更新才能提交完成.

2) 从库会开启一个本地工作线程——I/O线程. I/O线程与主库建立一个客户端连接, 主库随即启动一个二进制抽取线程, 该线程从主库的二进制日志中依次读取事务变更信息并发送给从库的I/O线程, I/O线程将收到的事务变更信息存储进本地的中继日志中.

3) 从库启动SQL线程, 该线程依次读取中继日志中的事务变更信息并解析, 然后在从库中重做执行这些事务, 完成与主库相同的数据更新[14].

主从复制的架构可以很灵活地实施, 根据不同的需求场景, 可以采用一主一从, 一主多从, 互为主从等架构. 当主库发生故障时, 从库可以代替主库接管业务, 成为新的主库, 并继续向其他从库进行数据同步, 从而最大程度保证数据一致性和服务高可用性. 在主从复制的基础之上部署一套主从复制的自动化管理程序, 即可组建一套MySQL高可用集群[5,6].

本文介绍的MySQL集群采用的是一主多从架构, 即集群中一个节点用作主库, 其他多个从节点用作从库. 集群管理程序是基于开源的MHA(Master High Availability)集群软件改进而成, 可以实现主从复制状态的实时监控, 秒级故障自动切换和自动主从提升等功能.

图 1 MySQL主从复制架构示意图

1.2 Oracle GoldenGate简介

GoldenGate, 即Oracle GoldenGate Transactional Data Management, 是一种基于日志的数据同步软件. GoldenGate从源数据库读取并解析在线日志或归档日志, 捕捉到数据变化, 再将这些数据变化投递到目标端, 在目标端将数据变化重新解析为SQL语句并应用到数据库, 从而完成源数据库到目标数据库的数据同步.

GoldenGate的核心进程包括: 抽取进程、复制进程和管理进程.

1) 抽取进程(Extract)

抽取进程运行在源端, 负责从源数据库的源数据表和日志中抽取数据和数据变化, 用于目标数据库的初始数据装载和变化数据的同步.

需要同步数据的对象写在配置文件中, 抽取进程读取配置文件获取同步的对象, 对这些对象进行的DML (Data Manipulation Language)和DDL (Data Define Language)操作, 都被抽取进程从日志中捕获, 并将其中完成提交的事务输出到Trail文件中以传送到目标端. 抽取进程周期性地完成检查点(checkpoint), 记录其完成捕获的日志位置, 可以进行断点续传, 保证数据同步的完整性.

2) 复制进程(Replicat)

复制进程在目标端运行, 该进程读取目标端接收到的trail文件, 并将文件内容解析为可以执行的SQL语句, 然后在目标数据库中执行这些SQL语句. 与Extract进程一样, 复制进程也是使用内部的检查点(checkpoint)机制来保证进程意外中断后, 可以从中断的位置重新启动恢复, 从而避免数据丢失的风险.

3) 管理进程 (MGR)

在GoldenGate的源端和目标端分别有一个控制进程, 称为管理进程. 该进程主要负责监控GoldenGate的其他进程状态, 发现进程异常, 发送超时或阀值告警, 报告进程错误, 为其他进程分配存储空间和重启异常进程等.

数据的变化信息存储在trail文件中, 目标端的复制进程通过读取该文件来获取需要应用到目标数据库的SQL语句. 从源端到目标端的数据传输, 大多情况下建议采用数据泵进程. 该进程在数据库源端启动, 负责把源端的trail文件以数据块级别通过网络传输到目标端. 运行在目标端的收集进程(Collector)把从远端传输过来的数据进行过滤, 映射和转换, 重新生成目标端的trail文件[7].

图 2 GoldenGate工作原理示意图

图 3 GoldenGate关键进程示意图

GoldenGate支持几乎所有主流操作系统和数据库的异构平台之间的实时复制. 此外, GoldenGate复制的拓扑结构非常灵活, 除了支持一对一单向复制以外, 还支持双向复制、一对多复制、多对一复制、多级复制等. 因此, GoldenGate可以应用于系统的应急容灾、业务双中心、数据库备份、数据库迁移、数据搬迁、异构数据库数据同步等多种应用场景[8,9].

2 MySQL集群的GoldenGate复制架构设计 2.1 架构设计难点分析

在使用GoldenGate从MySQL到Oracle的异构数据同步架构中, MySQL数据库作为复制的源端, Oracle数据库作为复制的目标端, 整个复制过程涉及3个环节:

1) GoldenGate的抽取进程从源端MySQL数据库的二进制日志中抽取事务日志.

2) 抽取的事务日志通过网络传输到目标端Oracle数据库.

3) GoldenGate的复制进程对接收到的事务日志进行解析并在目标端Oracle数据库内应用.

在这三个环节中, 环节2)事务日志的传输稳定性主要依赖于网络方案保障, 本文不做论述. 环节3)中由于GoldenGate与Oracle数据库具有原生兼容性, 搭配使用的方案非常成熟, 不是架构的难点, 本文也不做论述.

此架构的重点在于GoldenGate的抽取进程如何从MySQL数据库源端抽取事务日志. 当复制的源端MySQL数据库为单节点时, GoldenGate的抽取进程直接从二进制日志中抽取事务日志即可. 如果在源端的抽取进程发生异常中断, GoldenGate会记录下事务中断位置, 事务中断位置是一个二进制日志文件号对应的文件中所记录的标记该事务开始的位置号. 当源端的抽取进程恢复时, GoldenGate会找到中断时记录的二进制日志文件及该文件中的事务位置号, 从这个位置继续开始事务日志的抽取, 从而保证不会有事务遗漏和事务被重复抽取的情况, 这样就能保证数据复制在事务日志抽取环节的完整性和一致性. 但是复制源端的MySQL数据库为多节点集群架构时, MySQL集群的主库是复制的源端, GoldenGate需要在主库所在服务器上启动, 并从主库的二进制日志中进行事务日志的抽取. 当集群发生切换的时候, 原有的从库之一接管主库的业务, 成为新的主库. 此时, 要保证业务数据继续往Oracle数据库做同步, 就需要GoldenGate在新的主库上继续抽取二进制日志, 即GoldenGate的复制源端需要从MySQL集群的原主库变为集群切换后的新主库, 且GoldenGate可以在新主库上完成断点续传. 这就需要在新主库的二进制日志中能够准确的找到抽取中断的位置, 确保从中断的准确位置开始抽取, 而不会抽取的位置靠后造成事务遗漏或者抽取的位置靠前造成事务被重复抽取, 因为无论事务遗漏还是事务重复都会造成最终的不一致. 要确保做到这一点就会面临以下两个难点:

1) 需要GoldenGate能够感知到MySQL集群发生的主从切换行为, 且能够在MySQL集群发生主从切换后即刻在原主库上停止抽取进程, 然后在新主库上启动抽取进程.

2) 在从新主库的二进制日志开始抽取事务日志之前, GoldenGate如何找到准确的抽取起始位置. 因为MySQL原主库和新主库的二进制日志是两套完全独立的日志, 没有继承性, 在原主库和新主库中, 记录同一个事务的二进制日志文件号和文件内的事务position号完全不一样. 这会让GoldenGate通过原主库抽取中断时记录的二进制日志文件号和事务position号, 在新主库的二进制日志中确定准确的抽取起始位置变得非常困难.

图 4 GoldenGate日志抽取源端切换示意图

2.2 总体方案设计

根据GoldenGate要能完成集群切换后即刻在新的主库上启动需求, 本文设计了一套针对GoldenGate部署的共享存储方案:

首先, 在MySQL集群的各节点间部署一套共享存储, 该存储与集群各节点服务器均相连, 但该存储上的文件系统同一时刻只能挂载在一台服务器上, 没有挂载共享存储的服务器不能对该存储上的文件系统进行读写.

然后, 将GoldenGate的应用程序安装部署在共享存储的文件系统上, GoldenGate的启动文件、配置文件和日志文件均放置在该文件系统上. 这样, 只要挂载了该共享文件系统的服务器, 就可以在其上启动GoldenGate.

最后, 要保证MySQL集群发生切换的时候, 共享文件系统能够从切换前的主库服务器卸载下来, 重新挂载到切换后的新主库服务器上, 这一系列共享文件系统的操作均可以通过开发切换控制程序来实现.

这样就实现了MySQL集群原主库崩溃, 新主库接管业务后, GoldenGate能够在新主库上启动并从新主库捕捉数据变化继续进行同步.

图 5 GoldenGate共享存储部署方案

本文在方案中引用了MySQL5.6的新特性—GTID (Global Transaction ID), 来解决GoldenGate在新主库服务器上启动后, 如何找到准确抽取起始位置的难题. GTID是在MySQL集群中的一个全局编号, 该编号对应于一个已提交事务, 同一个事务在MySQL集群中所有节点对应的GTID是完全一致的. 这样只要选择MySQL 5.6以上的版本, 在主从复制配置时开启GTID功能, GTID就会显式输出到集群每个节点的二进制日志中. 那么在MySQL集群发生切换的时候, 根据原主库二进制日志抽取停止点的GTID找到新主库二进制日志上对应的GTID, 就可以唯一定位到日志续传的起始点. 根据这个思路, 只要对MySQL集群管理程序进行改造, 完成如下功能即可:

1) 根据GoldenGate输出的原主库的二进制日志名称和日志位置号找到对应的GTID.

2) 根据GTID定位出新主库对应的二进制日志名称和日志位置号, 并将定位结果输出.

图 6 二进制日志断点位置定位流程

综合以上设计思路, 总体方案设计的关键点归纳如下:

1) 在集群各节点间部署共享存储, 将GoldenGate部署在共享存储的文件系统上.

2) 开发GoldenGate切换控制程序, 负责与GoldenGate的交互和共享存储在集群各节点间的切换.

3) 开启MySQL集群主从复制的GTID功能.

4) 改造MySQL集群管理程序, 新增与GoldenGate切换控制程序的交互接口, 能够发送切换通知, 并在接收到GoldenGate切换控制程序反馈的日志抽取停止点后, 将切换后日志续传起始点告知GoldenGate切换控制程序.

方案的总体工作流程设计如图7.

当由于某个触发条件触发MySQL集群开始切换时, MySQL集群管理程序同时出发GoldenGate日志抽取的切换流程:

1) MySQL集群管理程序向GoldenGate切换控制程序发出切换通知, 并将切换目的地, 即新主库所在服务器的IP地址告诉GoldenGate切换控制程序.

2) GoldenGate切换控制程序将部署着Golden-Gate的共享存储切换到新主库所在服务器.

3) GoldenGate切换控制程序获取GoldenGate抽取进程在MySQL集群切换前所抽取到原主库的最新的二进制文件名和日志位置号.

4) GoldenGate切换控制程序把原主库的二进制文件名和日志位置号发送给MySQL集群管理程序, 请求返回新主库对应的二进制文件名和日志位置.

5) MySQL集群管理程序根据原主库的二进制文件名和日志位置号定位出新主库对应的二进制文件名和日志位置, 将定位结果发送给GoldenGate切换控制程序.

6) GoldenGate切换控制程序在新主库所在服务器启动GoldenGate, 并指定GoldenGate切换控制程序从新主库对应的二进制文件名和日志位置开始抽取日志.

图 7 方案总体流程设计

3 方案实现

以上设计的同步方案的关键实现主要包括:

1) 对MySQL集群管理程序进行改造, 实现日志定位, 即二进制文件名、日志位置号与GTID的转换功能.

2) 实现GoldenGate切换控制程序的切换控制和断点续传功能.

3.1 MySQL集群管理程序日志定位的功能实现

日志定位功能的核心实现思路是:

Step 1. 通过传入的二进制日志文件路径和位置号, 查找出该二进制日志文件中包含该位置号的事务, 再输出在该事物之前完成复制的最新事务的GTID.

Step 2. 根据Step 1获取的GTID, 遍历新主库的二进制日志文件, 查找出GTID所在的二进制日志文件和对应的已完成复制的事务, 再输出该事务之后第一个未完成复制的事务对应的位置号.

其中, Step 1代码实现逻辑如下:

1) 读取二进制日志文件.

2) 读取文件头信息, 根据输入的位置号获取前一事务的事件位置.

3) 解析前一事务的事件内容, 获取该事务GTID的位置信息.

4) 从获取的GTID位置信息获取GTID字符串并输出.

关键步骤代码实现如下:

func getPreviousGtids(binlogPath string) (gtidDesc string, err error) {

 file, err := newBinlogReader(binlogPath)

 p := int64(4)

 headerBs := make([]byte, EVENT_HEADER_SIZE)

 payloadBs := make([]byte, 1024)

 length := binary.LittleEndian.Uint32(headerBs[9:13])

 eventType := int(headerBs[4])

 payloadLength := length – EVENT_HEADER_SIZE

 if payloadLength > uint32(len(payloadBs)) {

  payloadBs = make([]byte, payloadLength)

 }

 ret := ""

 sidNumberCount := bytesToUint(payloadBs[0:8])

 pos := 8

 for i := uint(0); i < sidNumberCount; i++ {

  if "" != ret {

   ret = ret + ", "

  }

  uuid := bytesToUuid(payloadBs[pos : pos+16])

  ret = ret + uuid

  internalCount := bytesToUint(payloadBs[pos+16 : pos+16+8])

  pos = pos + 16 + 8

  for i := uint(0); i < internalCount; i++ {

   from := bytesToUint64(payloadBs[pos:pos+ 8])

   to := bytesToUint64(payloadBs[pos+8:pos+ 16]) – 1

   pos = pos + 16

   ret = ret + ":" + strconv.FormatUint(from, 10) + "-" + strconv.FormatUint(to, 10)

  }

 }

 file.close()

 return gtidDesc, nil

}

Step 2的代码逻辑与实现与Step 1类似, 在此不再做详述.

3.2 GoldenGate切换控制程序的实现

GoldenGate切换控制程序主要实现的核心功能是, 在接到MySQL集群的切换通知后, 完成GoldenGate的切换, 关键步骤如下:

1) 判断原主库服务器是否宕机. 如果没有宕机, 则在原主库服务器上停止GoldenGate复制, 然后触发GoldenGate切换, 如果已经宕机, 则直接触发GoldenGate切换.

2) 将部署着GoldenGate的共享存储切换到新主库所在服务器.

3) 通过MySQL集群将原主库二进制日志的位置转换为新主库二进制日志的位置, 并启动GoldenGate从新主库二进制日志的位置开始抓取.

这两个步骤实现的部分代码如下:

1) 将原主库的IP地址记录到配置文件old_master_ip.conf中, 在切换时需要先停止原主库服务器上的GoldenGate的情况下需要使用.

2) 切换时判断原主库所在服务器是否已经宕机, 如果已经宕机不进行停止GoldenGate操作, 如果没有宕机, 则进行停止GoldenGate操作.

3) 把共享盘从原主库服务器切换到新主库服务器.

4) 在新主库上获取原主库停止同步时的二进制日志位置, 然后通过MySQL集群接口转换, 找到新主库对应的二进制日志位置, GoldenGate从新的二进制日志位置上启动进程进行同步.

3.3 效果验证

通过实际的部署使用, 在MySQL集群发生主从切换的情况下, GoldenGate可以跟随主库的切换而自动进行故障切换, 完成抽取进程与新主库的自动对接, 并能够准确定位断点, 复制的数据无重复无丢失, 完美保障数据同步的连续性和一致性.

4 方案对比

使用GoldenGate进行MySQL数据库和Oracle数据库的异构数据库同步复制, 是行业内最常用和最成熟的方法. 多数情况下主要是针对MySQL数据库单实例和Oracle数据库进行同步, 当涉及MySQL集群环境和Oracle数据库进行同步的情况, 主要有两种部署方案:

(1) GoldenGate的抽取进程部署在MySQL集群的主库上. 缺点是一旦主库发生故障切换, GoldenGate的抽取进程将无法继续工作, 需要人工介入处理.

(2) GoldenGate的抽取进程部署在MySQL集群的从库上. 缺点是MySQL集群主库和从库数据存在一定的同步延迟, 导致GoldenGate的抽取进程抽取的数据也将与主库存在一定的延迟.

本文介绍的实现方法是在第一种部署方案的基础上进行了架构强化, 能够完美解决第一种部署方案的缺点, 在主库发生故障切换时, GoldenGate的抽取进程能够自动的进行故障切换并继续无缝的完成事务抽取, 全自动无需人工干预. 表1为3种方案的对比结果.

表 1 方案对比矩阵

5 结语

本文介绍了利用GoldenGate构建MySQL数据库到Oracle数据库的异构数据库同步复制架构, 实现了在MySQL集群发生主从切换时, GoldenGate能够自动的进行故障切换并继续无缝的完成事务抽取, 保障了异构数据库间数据同步复制的连续性和可靠性. 同时, 本文介绍的复制架构不仅仅适用于MySQL数据库到Oracle数据库的异构数据库同步复制, 对于MySQL数据库到其他类型数据库的同步复制同样具有指导借鉴意义, 在整体架构不需要做大的改动的情况下, 只用对GoldenGate的复制端稍作调整, 就能满足MySQL数据库到其他类型数据库的同步复制需求.

参考文献
[1]
张伟丽, 江春华, 魏劲超. MySQL复制技术的研究及应用. 计算机科学, 2012, 39(11A): 168-170.
[2]
邢志峰. MySQL主从复制的研究与应用. 电子技术与软件工程, 2017(15): 188.
[3]
刘腾. MySQL复制技术的研究与改进[硕士学位论文]. 杭州: 浙江大学, 2011.
[4]
田关伟. MySQL复制技术分析研究. 哈尔滨师范大学自然科学学报, 2015, 31(4): 45-48, 64.
[5]
韦一鸣. 基于MySQL复制技术的数据库集群研究[硕士学位论文]. 杭州: 杭州电子科技大学, 2014.
[6]
宣振国. 基于Mysql的数据库集群设计与实现[硕士学位论文]. 北京: 北京邮电大学, 2013.
[7]
曲波, 邓旭东, 姜锋. Oracle GoldenGate数据同步机制研究与应用. 微型电脑应用, 2014, 30(6): 55-58.
[8]
曹建辉. 基于GoldenGate高级复制技术实现数据库同步. 甘肃科技, 2012, 28(24): 23-25. DOI:10.3969/j.issn.1000-0952.2012.24.008
[9]
王二暖. Goldengate实现异构数据库间的数据同步. 电脑开发与应用, 2014, 27(5): 70-72.