至此本节将介绍如何实现从 SQL Server 到 TiDB 的整体迁移流程,包括全量与增量同步,数据校验及注意事项等内容,希望本节可以帮助想要将 SQL Server 迁移到 TiDB 的用户提供上手操作指导。

    5.3.2 流程介绍

    下图为在线迁移数据库的基本流程,供读者对整体流程有个大致的认识:

    执行过程中,可根据实际情况,结合如下表格制定迁移操作手册:

    1. 迁移工具

    迁移工具采用 yugong。yugong 是阿里开发的一款去Oracle数据迁移同步工具, 版本基于阿里的版本增加了对SQL Server数据源的支持。

    2. 操作步骤

    (1) 下载 yugong
    1. # 方法一:直接下载可执行文件 jar 包
    2. wget https://github.com/alswl/yugong/releases/download/541e5f8/yugong-shaded.jar
    3. # 方法二:自行编译
    4. git git@github.com:alswl/yugong.git
    5. cd yugong
    6. mvn clean package
    (2) 修改配置

    运行 yugong 需要用到两个配置文件 yugong.propertiesyugong.yaml

    • yugong.properties 文件用于配置数据库链接和同步任务
    1. # vi 编辑 yugong.properties
    2. vi yugong.properties
    1. # 源数据库配置
    2. yugong.database.source.url=jdbc:sqlserver://192.168.1.88:1433;databaseName=example
    3. yugong.database.source.username=sa
    4. yugong.database.source.password=sa
    5. yugong.database.source.type=SQL_SERVER
    6. yugong.database.source.encode=UTF-8
    7. yugong.database.source.poolSize=200
    8. # 目标数据库配置,TiDB 使用 MySQL 协议
    9. yugong.database.target.url=jdbc:mysql://192.168.1.99:3306/example?autoReconnect=true
    10. yugong.database.target.username=root
    11. yugong.database.target.password=root
    12. yugong.database.target.type=MYSQL
    13. yugong.database.target.encode=UTF-8
    14. yugong.database.target.poolSize=200
    15. yugong.table.batchApply=true
    16. yugong.table.onceCrawNum=1000
    17. yugong.table.tpsLimit=0
    18. # 使用数据库链接中的 schema
    19. yugong.table.ignoreSchema=false
    20. # skip Applier Load Db failed data
    21. yugong.table.skipApplierException=false
    22. # 需要迁移的数据库表
    23. yugong.table.white=user
    24. yugong.table.black=
    25. # 是否开启并发
    26. yugong.table.concurrent.enable=true
    27. # 并发数
    28. yugong.table.concurrent.size=6
    29. yugong.table.retry.times=3
    30. # retry interval or sleep time (ms)
    31. yugong.table.retry.interval=1000
    32. # MARK/FULL/INC/ALL(REC+FULL+INC)/CHECK/CLEAR
    33. # 设置为FULL(全量模式)
    34. yugong.table.mode=FULL
    35. # yugong extractor
    36. yugong.extractor.concurrent.enable=true
    37. yugong.extractor.concurrent.global=false
    38. yugong.extractor.concurrent.size=60
    39. yugong.extractor.noupdate.sleep=1000
    40. yugong.extractor.noupdate.thresold=0
    41. yugong.extractor.once=false
    42. # yugong applier
    43. yugong.applier.concurrent.enable=true
    44. yugong.applier.concurrent.global=false
    45. yugong.applier.concurrent.size=20
    46. yugong.applier.dump=false
    47. # stats
    48. yugong.stat.print.interval=5
    49. yugong.progress.print.interval=1
    50. # alarm email
    51. yugong.alarm.email.host=
    52. yugong.alarm.email.username=
    53. yugong.alarm.email.password=
    54. yugong.alarm.email.stmp.port=
    55. yugong.alarm.email.ssl.support=
    • yugong.yaml 文件用于定制 translator 的定制,直接使用范例中的配置即可
    (3) 运行 yugong
    • 执行 yugong 的运行命令
    1. # -c yugong.properties 数据库和任务配置文件
    2. # -y yugong.yaml ETL 中 translator 流程的配置
    3. # 执行命令
    4. java -jar yugong-shaded.jar -c yugong.properties -y yugong.yaml
    • 程序运行后,控制台会输出运行日志。
    1. # 程序启动
    2. 2019-12-02 20:49:23.923 [main] INFO com.taobao.yugong.YugongApp - ## start the YuGong.
    3. # 检查源数据库和目标数据库连接情况
    4. 2019-12-02 20:49:24.000 [main] INFO
    5. com.taobao.yugong.controller.YuGongController - check source database connection ...
    6. 2019-12-02 20:49:24.017 [main] INFO com.taobao.yugong.controller.YuGongController - check source database is ok
    7. 2019-12-02 20:49:24.017 [main] INFO com.taobao.yugong.controller.YuGongController - check target database connection ...
    8. 2019-12-02 20:49:24.028 [main] INFO com.taobao.yugong.controller.YuGongController - check target database is ok
    9. 2019-12-02 20:49:24.028 [main] INFO com.taobao.yugong.controller.YuGongController - check source tables read privileges ...
    10. # 初始化连接池
    11. 2019-12-02 20:49:24.071 [main] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
    12. 2019-12-02 20:49:24.277 [main] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-2} inited
    13. 2019-12-02 20:49:25.418 [main] INFO com.taobao.yugong.controller.YuGongController - check source tables is ok.
    14. # 启动同步任务线程
    15. 2019-12-02 20:49:26.933 [main] INFO com.taobao.yugong.controller.YuGongController - ## prepare start tables[1] with concurrent[6]
    16. 2019-12-02 20:49:26.959 [main] INFO com.taobao.yugong.YugongApp - ## the YuGong is running now ......
    17. # 同步进度打印
    18. 2019-12-02 20:51:08.801 [Thread-7] INFO com.taobao.yugong.common.stats.ProgressTracer - {未启动:0,全量中:0,已完成:1,异常数:0}
    19. # 完成的任务
    20. 2019-12-02 20:51:08.801 [Thread-7] INFO com.taobao.yugong.common.stats.ProgressTracer - 已完成:[example.user]
    21. 2019-12-02 20:51:08.806 [Thread-7] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-1} closed
    22. 2019-12-02 20:51:08.807 [Thread-7] INFO com.taobao.yugong.YugongApp - ## YuGong is down.
    (4) 检查日志
    • 日志记录在 logs 目录下,结构如下:
    1. logs
    2. ├── example.user # 表名为目录
    3. ├── applier.log # 写入日志
    4. └── table.log # 表操作日志
    5. └── yugong
    6. └── table.log # 系统日志
    7. positioner_data
    8. └── example_user.dat # 同步进度,用于断点续传

    5.3.4 增量同步

    1. 增量同步的原理

    2. 实操流程

    (1) 开启 SQL Server CDC
    (2) CDC 开启后,系统会生成一张 Change Table 的表,表名为: cdc.dbo_example_CT
    1. .schema cdc.dbo_example_CT
    2. name default nullable type length indexed
    3. -------------- ------- -------- ------------ ------ -------
    4. __$end_lsn null YES binary 10 NO
    5. __$operation null NO int 4 NO
    6. __$seqval null NO binary 10 NO
    7. __$start_lsn null NO binary 10 YES
    8. __$update_mask null YES varbinary 128 NO
    9. id null YES int 4 NO
    10. name null YES varchar(255) 255 NO
    (3) 读取 CDC 日志
    • 对 example 表做一些添删改的操作,而后通过系统函数查询 CDC 记录。
    1. -- 定义参数
    2. DECLARE @begin_time datetime, @end_time datetime, @begin_lsn binary(10), @end_lsn binary(10);
    3. -- 设定查询记录的开始和结束时间
    4. SET @begin_time = '2020-03-08 10:00:00.000';
    5. SET @end_time = '2020-03-08 10:10:00.000';
    6. -- 将时间转换为系统的 lsn
    7. SELECT @begin_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than', @begin_time);
    8. SELECT @end_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
    9. -- 根据开始和结束的 lsn 查询该表的所有变化
    10. SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_example(@begin_lsn, @end_lsn, 'all');
    • 查出数据如下:
    1. __$start_lsn __$end_lsn __$seqval __$operation __$update_mask id name
    2. -------------------- ---------- -------------------- ------------ -------------- -- ------
    3. 0000dede0000019f001a null 0000dede0000019f0018 2 03 1 AAA
    4. 0000dede000001ad0004 null 0000dede000001ad0003 2 03 2 BBB
    5. 0000dede000001ba0003 null 0000dede000001ba0002 3 02 2 BBB
    6. 0000dede000001ba0003 null 0000dede000001ba0002 4 02 2 CCC
    7. 0000dede000001c10003 null 0000dede000001c10002 2 03 3 DDD
    8. 0000dede000001cc0005 null 0000dede000001cc0002 1 03 3 DDD
    (4) 消费 CDC 日志

    确认 CDC 正确开启,且得到了变更数据后,编写一个程序,采用定时任务的方式,设定时间间隔,通过上述 SQL 语句持续读取 Change Table 中的记录,并根据 __$operation 将数据转换为对应添删改操作的 SQL 语句写入 TiDB。

    选择 yugong 作为 ETL 工具的一大原因也是因为它提供了多种模式。支持 CHECKFULLINCAUTO 四种模式。 其中 CHECK 模式就是将 yugong 作为数据一致性检查工具使用。 yugong 工作原理是通过 根据主键范围变化,将数据取出进行批量对比。

    有一点需要注意,当表没有主键信息时,yugong 默认会使用 SQL Server 的物理地址信息—— physloc 。 此时读取性能会大幅下降,所以大表通常建议先建好主键。

    在增量同步时,还有另一个方式来实现数据校验功能,再增加一个消费程序,延迟 5 秒消费同一队列,并通过提取主键(或索引)的方式从 TiDB 中查出该条已经写入的数据,将两侧的整行数据做比较(本实践中去除主键后比较),如果有问题会进行尝试重新写入,如出现异常则向相关人员发送报警。

    5.3.6 迁移注意事项

    在迁移过程中需要注意的一些点:

    1. 原有 SQL server 语句一定要在程序里检查仔细,尤其是对于一些时间久远且项目比较多的程序,最好是让 DBA 同学在 SQL server 服务请求上开启 DMV,多抓几天的语句,然后根据这些语句再去核对。

    2. SQL Server 与 TiDB(MySQL)的字段类型略有出入,需要仔细对比。

    3. SQL Server 与 TiDB(MySQL)的语法也不尽相同,在实现之后需要仔细验证,以防出现语义变化,影响业务。

    4. 索引机制不同,可以利用迁移的机会重新梳理业务索引。

    5. 对于大型系统迁移,演练不可缺少。演练成功标准为单次演练无意外,时间控制在计划内。