一、背景

MySQL作为最流行的关系型数据库产品之一,当数据规模增大遭遇性能瓶颈时,最容易想到的解决方案就是分库分表。无论是进行水平拆分还是垂直拆分,第一步必然需要数据迁移与同步。由此可以衍生出一系列数据迁移过程中的需求:

  • 原本一张表迁移到单库多表(或多库多表),这是最基本的需求;
  • 原本单库多表(或多库多表)迁移到新的多库多表(因表设计不合理、数据规模增大等原因导致需要再次分库分表)
  • 新表与旧表的表结构可能不一致,如:类型表更(自增主键id由int改为bigint)、字段数量不一致(删减、增加)、字段名称变更等
  • 字段映射,如:旧表中的多个字段映射为新表的一个字段,或旧表中的一个字段映射为新表的多个字段
  • 增量数据的实时同步,以及当涉及表结构转换时增量部分(binlog)如何方便地实现同样的转换
  • 如何支持垂直拆分的数据迁移
  • MySQL到NewSQL的迁移(如:TiDB、CockroachDB)
  • 异构数据源的实时迁移,如:MySQL到HBase、MongoDB(关于异构数据源的实时同步设计不在本文内容范围,后续将专题介绍)
  • 迁移前后的数据一致性校验

二、设计

为满足以上需求,下面将从全量迁移和增量同步两部分来说明MySQL数据迁移同步工具的设计与实现。


2.1 全量迁移

mysqldump是MySQL官方自带的数据备份工具,也可以用于数据迁移,但不足之处是单线程处理,迁移大表时速度极慢,并且不支持写入分库分表。因此开源社区还开发了一个多线程的类似工具mydumper,性能有不少提升,但同样不支持写入分库分表,也不支持字段的转换。

接下来介绍下快速分片并行读取MySQL表数据的做法:

  1. 自动查找表的主键pk;
  2. 查询主键的最大值及最小值:max(pk),min(pk);
  3. 对主键范围分片,每个分片跨度1万(即最多读取1万行数据),由此即可将整张表的查询分成多个查询分片:

第1个分片查询条件为pk >= min(pk) AND pk < min(pk)+10000
      第2个分片查询条件为pk>= min(pk)+10000 AND pk < min(pk)+20000
      第3个分片查询条件为pk >= min(pk)+20000 AND pk < min(pk)+30000
      以此类推。

以上分片查询除了可以并行读取之外,另外一个优势是失败可恢复,某个分片查询失败并不影响整体查询的进度,只需失败重试即可。当然也可以将所有分片持久化,即使程序异常退出,重启后也可以恢复,避免重新查询全表数据。

2.2 增量同步

增量数据的读取基于MySQL的binlog主从复制。在全量迁移之前首先获取当前MySQL的位点信息(FileName、Position),以便全量数据迁移完成之后从该位点继续重放binlog。

三、实现

3.1 全量迁移

基于RxJava的观察者(或生产者消费者)模式实现链式最大化并行处理:多张表并行生成查询分片(Query Split),然后由Source并行执行查询分片从MySQL中读取数据,然后统一由Sink Selector根据分库分表的sharding字段及规则计算出每行数据所属的slot(即应该写入到哪张分表),当一个slot中的数据积累到一个batch size时会生成一个插入分片(Insert Split),最终由Sink并行地批量写入对应的目标表中。

为了避免累积的数据过多造成GC压力,slot超过一定时间后即使没有累积到一个batch size也会生成Insert Split分发给Sink执行写入。此外还要考虑另外一个问题:当生产者生产过快导致消费者来不及处理时,将会导致事件堆积,严重时还会OOM,即所谓的背压(Backpressure)。幸好RxJava作为一个成熟的Reactive框架已经对背压处理有很好的支持,这也是为什么要基于RxJava来实现的重要原因之一。

3.2 增量同步

binlog的抽取使用了开源的Java类库mysql-binlog-connector-java,与Canal相比更加轻量,源码清晰易懂,不依赖其他第三方jar包,也没有那么多不需要的繁杂功能。

为了实现对binlog的字段转换,采用了Apache开源的SQL引擎calcite来实现:将binlog的每行数据根据原表的表结构映射为一张内存表,然后由calcite执行SQL转换后输出结果。(PS:calcite当前已被多个开源项目采用,Hive用calcite优化查询,Flink的Streaming SQL基于calcite实现,Kylin的查询引擎也采用calcite)

【转】MySQL分库分表数据迁移工具的设计与实现的更多相关文章

  1. Mysql分库分表方案

    Mysql分库分表方案 1.为什么要分表: 当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. m ...

  2. MYSQL分库分表和不停机更改表结构

    在MYSQL分库分表中我们一般是基于数据量比较大的时间对mysql数据库一种优化的做法,下面我简单的介绍一下mysql分表与分库的简单做法. .分库分表 很明显,一个主表(也就是很重要的表,例如用户表 ...

  3. 【分库、分表】MySQL分库分表方案

    一.Mysql分库分表方案 1.为什么要分表: 当一张表的数据达到几千万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间. ...

  4. Java互联网架构-Mysql分库分表订单生成系统实战分析

    概述 分库分表的必要性 首先我们来了解一下为什么要做分库分表.在我们的业务(web应用)中,关系型数据库本身比较容易成为系统性能瓶颈,单机存储容量.连接数.处理能力等都很有限,数据库本身的“有状态性” ...

  5. 高可用Mysql架构_Mysql主从复制、Mysql双主热备、Mysql双主双从、Mysql读写分离(Mycat中间件)、Mysql分库分表架构(Mycat中间件)的演变

    [Mysql主从复制]解决的问题数据分布:比如一共150台机器,分别往电信.网通.移动各放50台,这样无论在哪个网络访问都很快.其次按照地域,比如国内国外,北方南方,这样地域性访问解决了.负载均衡:M ...

  6. mysql分库分表(二)

    mysql分库分表 参考: https://www.cnblogs.com/dongruiha/p/6727783.html https://www.cnblogs.com/oldUncle/p/64 ...

  7. mysql分库分表(一)

    mysql分库分表 参考: https://blog.csdn.net/xlgen157387/article/details/53976153 https://blog.csdn.net/cleve ...

  8. 思考--mysql 分库分表的思考

    查询不在分库键上怎么办,扫描所有库?由于分库了,每个库扫描很快?所以比单个表的扫描肯定快,可以这样理解吗. 多表jion怎么弄,把内层表发给每个分库吗? citus,tidb 都有这些问题,citus ...

  9. 你们要的MyCat实现MySQL分库分表来了

    ❝ 借助MyCat来实现MySQL的分库分表落地,没有实现过的,或者没了解过的可以看看 ❞ 前言 在之前写过一篇关于mysql分库分表的文章,那篇文章只是给大家提供了一个思路,但是回复下面有很多说是细 ...

随机推荐

  1. 微服务,ApiGateway 与 Kong

    一. 微服务 二. Api Gateway 三. Kong 的使用 一. 微服务 对于一些传统的 大型项目,传统的方式会有一些缺陷,比如说 新人熟悉系统成本高(因为整个系统作为一个整体,彼此会有一定的 ...

  2. mysql SQLyog导入csv数据失败怎么办?

    分享下mysql使用SQLyog导入csv数据失败的解决方法 给mysql导入数据,选中某个表选择导入--导入使用本地csv数据即可,单有的时候不知道什么问题导入不成功!!! 给mysql导入数据,使 ...

  3. PHP mysqli方式连接类

    分享一个PHP以mysqli方式连接类完整代码实例,有关mysqli用法实例. 一个在PHP中以mysqli方式连接数据库的一个数据库类实例,该数据库类是从一个PHP的CMS中整理出来的,可实现PHP ...

  4. [na]wireshark排查打印机问题

    抓包工具排除故障 前言:上网慢,可能是内网堵了.装上wireshark,可抓到广播包,多播包,以及发给自己的包.如果想抓lan内其他人之间的通信包,那就要在sw上做端口镜像. 1.背景 调试打印机的人 ...

  5. Java经典问题:传值与传引用?

    转自:http://developer.51cto.com/art/201104/254715.htm Java到底是传值还是传引用?相信很少有人能完全回答正确.通常的说法是:对于基本数据类型(整型. ...

  6. 【Web】Tomcat中利用Session识别用户的基本原理

    HTTP无状态的特性与Session.Cookie的存在 HTTP有一个特性:无状态的,就是前后两个HTTP事务它们并不知道对方的信息. 而为了维护会话信息或用户信息,一般可用Cookie或Sessi ...

  7. DLL中获取主程序句柄

    一.问题由来及说明 在实际编程中遇到一些系统模块(或API)调用初始化需要窗口句柄,在主程序中(MFC或者win32)都可以很容易获得,比如mfc中可以直接调用AfxGetMainWnd().GetS ...

  8. 为python 添加新功能-dump

    一直觉得thinkphp提供的dump函数挺好用的,但是python里面没有,就一直想着写个简单的. dir是我比较常用的一个内置函数了,但是显示效果实在有点受不了,每次我都要从大量的字符串里找到我需 ...

  9. maven项目强制自动更新所有jar包

    选中即可:

  10. iOS中 语音识别功能/语音转文字教程具体解释 韩俊强的博客

    原文地址:http://blog.csdn.net/qq_31810357/article/details/51111702 前言:近期研究了一下语音识别,从百度语音识别到讯飞语音识别:首先说一下个人 ...