一、背景

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. PhotoShop CS6实现照片背景虚化效果

    在摄影实践中,虚化背景是突出主体的常用手段.但是由于消费级DC镜头的实际焦距都很短,因此实现浅景深而虚化背景的难度较大.如果我们希望用消费级DC也能达到虚化背景突出主体的效果,那么,Photoshop ...

  2. IReport5.6.0创建数据库连接找不到驱动(iReport中ClassNotFoundError错误的解决)

    情景:iRoport中选择com.microsoft.jdbc.sqlserver.SQLServerDriver的JDBC Driver;连接时出现ClassNotFoundError错误 当见到下 ...

  3. 服务端 https和SSL

    String keyStoreFilePassword = System .getProperty("keystore.file.password"); /usr/java/jdk ...

  4. jQuery Direct and delegated events 直接事件与委托事件

    ref: http://api.jquery.com/on/ 直接事件: 将事件委托直接绑定到dom元素上,当事件发生时触发handler. 委托事件:  将事件委托绑定到dom元素的外层容器上,当事 ...

  5. confluence数据库的配置文件

    mysql> select u.id,u.user_name,u.active from cwd_user u join cwd_membership m on u.id=m.child_use ...

  6. HTML5学习笔记(二十):JavaScript中的标准对象

    这里提到的标准对象指ECMAScript中定义的对象,无论JavaScript运行那种环境(浏览器.Node.js)下都存在的对象. typeof 在JavaScript的世界里,一切都是对象. 但是 ...

  7. http缓存机制之304状态码

    在网上看到一篇关于解释浏览器缓存更新机制304状态码的文章,里面说如果请求头中的If-Modified-Since字段和If-None-Match字段的值分别和响应头中的Last-Modified字段 ...

  8. FFmpeg(3)-AVFormatContext 结构体内容分析

    AVIOContext *pb                          IO Context,.自定义一些读写格式或者从内存当中读时用到此成员变量. char filename[1024]; ...

  9. 【C/C++】深入理解指针和数组的关系

    对数组名进行取地址运算 ,,}; ] = &a; //注意左值 对数组名取地址,得到的指针为指向整个数组的指针. 形参数组 形参为数组时勿须带数组长度,因为计算机不会处理,如果需要传数组长度, ...

  10. error LNK2005: _DllMain@12 已经在 MSVCRTD.lib(dllmain.obj) 中定义

    备注:我上次遇到这个问题是Win32 DLL项目中无意中include了afxwin.h,这个是MFC的头文件,把这个include删掉就解决了 ================ 转自:http:// ...