Syncer 使用文档

警告:

Syncer 目前已经不再维护,其功能已经完全被 TiDB Data Migration取代,强烈建议切换到 TiDB DM。

Syncer 简介

Syncer 是一个数据导入工具,能方便地将 MySQL 的数据增量导入到 TiDB。

Syncer 包含在 tidb-enterprise-tools 安装包中,可在此下载

Syncer 架构

Syncer 架构

Syncer 部署位置

Syncer 可以部署在任一台可以连通对应的 MySQL 和 TiDB 集群的机器上,推荐部署在 TiDB 集群。

Syncer 增量导入数据示例

使用前请详细阅读 Syncer 同步前预检查

设置同步开始的 position

设置 Syncer 的 meta 文件, 这里假设 meta 文件是 syncer.meta:

  1. cat syncer.meta
  1. binlog-name = "mysql-bin.000003"
  2. binlog-pos = 930143241
  3. binlog-gtid = "2bfabd22-fff7-11e6-97f7-f02fa73bcb01:1-23,61ccbb5d-c82d-11e6-ac2e-487b6bd31bf7:1-4"

注意:

  • syncer.meta 只需要第一次使用的时候配置,后续 Syncer 同步新的 binlog 之后会自动将其更新到最新的 position。
  • 如果使用 binlog position 同步则只需要配置 binlog-namebinlog-pos;如果使用 binlog-gtid 同步则需要设置 binlog-gtid,且启动 Syncer 时带有 --enable-gtid

启动 Syncer

Syncer 的命令行参数说明:

  1. Usage of Syncer:
  2. -L string
  3. 日志等级: debug, info, warn, error, fatal (默认为 "info")
  4. -V
  5. 输出 Syncer 版本;默认 false
  6. -auto-fix-gtid
  7. mysql master/slave 切换时,自动修复 gtid 信息;默认 false
  8. -b int
  9. batch 事务大小 (默认 100)
  10. -c int
  11. Syncer 处理 batch 线程数 (默认 16)
  12. -config string
  13. 指定相应配置文件启动 Sycner 服务;如 `--config config.toml`
  14. -enable-ansi-quotes
  15. 使用 ANSI_QUOTES sql_mode 来解析 SQL 语句
  16. -enable-gtid
  17. 使用 gtid 模式启动 Syncer;默认 false,开启前需要上游 MySQL 开启 GTID 功能
  18. -flavor string
  19. 上游数据库实例类型,目前支持 "mysql" "mariadb"
  20. -log-file string
  21. 指定日志文件目录;如 `--log-file ./syncer.log`
  22. -log-rotate string
  23. 指定日志切割周期, hour/day (默认 "day")
  24. -max-retry int
  25. SQL 请求由于网络异常等原因出错时的最大重试次数(默认值为 100
  26. -meta string
  27. 指定 Syncer 上游 meta 信息文件 (默认与配置文件相同目录下 "syncer.meta")
  28. -persistent-dir string
  29. 指定同步过程中历史 schema 结构的保存文件地址,如果设置为空,则不保存历史 schema 结构;如果不为空,则根据 binlog 里面包含的数据的 column 长度选择 schema 来还原 DML 语句
  30. -safe-mode
  31. 指定是否开启 safe mode,让 Syncer 在任何情况下可重入
  32. -server-id int
  33. 指定 MySQL slave sever-id (默认 101)
  34. -status-addr string
  35. 指定 Syncer metric 信息; `--status-addr 127:0.0.1:10088`
  36. -timezone string
  37. 目标数据库使用的时区,请使用 IANA 时区标识符,如 `Asia/Shanghai`

Syncer 的配置文件 config.toml

  1. log-level = "info"
  2. log-file = "syncer.log"
  3. log-rotate = "day"
  4. server-id = 101
  5. ## meta 文件地址
  6. meta = "./syncer.meta"
  7. worker-count = 16
  8. batch = 100
  9. flavor = "mysql"
  10. ## Prometheus 可以通过该地址拉取 Syncer metrics,也是 Syncer 的 pprof 调试地址
  11. status-addr = ":8271"
  12. ## 如果设置为 true,Syncer 遇到 DDL 语句时就会停止退出
  13. stop-on-ddl = false
  14. ## SQL 请求由于网络异常等原因出错时的最大重试次数
  15. max-retry = 100
  16. ## 指定目标数据库使用的时区,binlog 中所有 timestamp 字段会按照该时区进行转换,默认使用 Syncer 本地时区
  17. # timezone = "Asia/Shanghai"
  18. ## 跳过 DDL 语句,格式为 **前缀完全匹配**,如:`DROP TABLE ABC` 至少需要填入 `DROP TABLE`
  19. # skip-ddls = ["ALTER USER", "CREATE USER"]
  20. ## 在使用 route-rules 功能后,
  21. ## replicate-do-db & replicate-ignore-db 匹配合表之后 (target-schema & target-table) 数值
  22. ## 优先级关系: replicate-do-db --> replicate-do-table --> replicate-ignore-db --> replicate-ignore-table
  23. ## 指定要同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始
  24. #replicate-do-db = ["~^b.*","s1"]
  25. ## 指定 **忽略** 同步数据库;支持正则匹配,表达式语句必须以 `~` 开始
  26. #replicate-ignore-db = ["~^b.*","s1"]
  27. # skip-dmls 支持跳过 DML binlog events,type 字段的值可为:'insert','update' 和 'delete'
  28. # 跳过 foo.bar 表的所有 delete 语句
  29. # [[skip-dmls]]
  30. # db-name = "foo"
  31. # tbl-name = "bar"
  32. # type = "delete"
  33. #
  34. # 跳过所有表的 delete 语句
  35. # [[skip-dmls]]
  36. # type = "delete"
  37. #
  38. # 跳过 foo.* 表的 delete 语句
  39. # [[skip-dmls]]
  40. # db-name = "foo"
  41. # type = "delete"
  42. ## 指定要同步的 db.table 表
  43. ## db-name 与 tbl-name 不支持 `db-name ="dbname,dbname2"` 格式
  44. #[[replicate-do-table]]
  45. #db-name ="dbname"
  46. #tbl-name = "table-name"
  47. #[[replicate-do-table]]
  48. #db-name ="dbname1"
  49. #tbl-name = "table-name1"
  50. ## 指定要同步的 db.table 表;支持正则匹配,表达式语句必须以 `~` 开始
  51. #[[replicate-do-table]]
  52. #db-name ="test"
  53. #tbl-name = "~^a.*"
  54. ## 指定 **忽略** 同步数据库
  55. ## db-name & tbl-name 不支持 `db-name ="dbname,dbname2"` 语句格式
  56. #[[replicate-ignore-table]]
  57. #db-name = "your_db"
  58. #tbl-name = "your_table"
  59. ## 指定要 **忽略** 同步数据库名;支持正则匹配,表达式语句必须以 `~` 开始
  60. #[[replicate-ignore-table]]
  61. #db-name ="test"
  62. #tbl-name = "~^a.*"
  63. # sharding 同步规则,采用 wildcharacter
  64. # 1. 星号字符 (*) 可以匹配零个或者多个字符,
  65. # 例子, doc* 匹配 doc 和 document, 但是和 dodo 不匹配;
  66. # 星号只能放在 pattern 结尾,并且一个 pattern 中只能有一个
  67. # 2. 问号字符 (?) 匹配任一一个字符
  68. #[[route-rules]]
  69. #pattern-schema = "route_*"
  70. #pattern-table = "abc_*"
  71. #target-schema = "route"
  72. #target-table = "abc"
  73. #[[route-rules]]
  74. #pattern-schema = "route_*"
  75. #pattern-table = "xyz_*"
  76. #target-schema = "route"
  77. #target-table = "xyz"
  78. [from]
  79. host = "127.0.0.1"
  80. user = "root"
  81. password = ""
  82. port = 3306
  83. [to]
  84. host = "127.0.0.1"
  85. user = "root"
  86. password = ""
  87. port = 4000

启动 Syncer:

  1. ./bin/syncer -config config.toml
  1. 2016/10/27 15:22:01 binlogsyncer.go:226: [info] begin to sync binlog from position (mysql-bin.000003, 1280)
  2. 2016/10/27 15:22:01 binlogsyncer.go:130: [info] register slave for master server 127.0.0.1:3306
  3. 2016/10/27 15:22:01 binlogsyncer.go:552: [info] rotate to (mysql-bin.000003, 1280)
  4. 2016/10/27 15:22:01 syncer.go:549: [info] rotate binlog to (mysql-bin.000003, 1280)

在 MySQL 中插入新的数据

  1. INSERT INTO t1 VALUES (4, 4), (5, 5);

登录到 TiDB 查看:

  1. mysql -h127.0.0.1 -P4000 -uroot -p
  1. select * from t1;
  1. +----+------+
  2. | id | age |
  3. +----+------+
  4. | 1 | 1 |
  5. | 2 | 2 |
  6. | 3 | 3 |
  7. | 4 | 4 |
  8. | 5 | 5 |
  9. +----+------+

Syncer 每隔 30s 会输出当前的同步统计,如下所示:

  1. 2017/06/08 01:18:51 syncer.go:934: [info] [syncer]total events = 15, total tps = 130, recent tps = 4,
  2. master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74,
  3. syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-17
  4. 2017/06/08 01:19:21 syncer.go:934: [info] [syncer]total events = 15, total tps = 191, recent tps = 2,
  5. master-binlog = (ON.000001, 11992), master-binlog-gtid=53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-74,
  6. syncer-binlog = (ON.000001, 2504), syncer-binlog-gtid = 53ea0ed1-9bf8-11e6-8bea-64006a897c73:1-35

由上述示例可见,使用 Syncer 可以自动将 MySQL 的更新同步到 TiDB。

Syncer 配置说明

指定数据库同步

本部分将通过实际案例描述 Syncer 同步数据库参数的优先级关系。

  • 如果使用 route-rules 规则,参考 Sharding 同步支持
  • 优先级:replicate-do-db —> replicate-do-table —> replicate-ignore-db —> replicate-ignore-table
  1. # 指定同步 ops 数据库
  2. # 指定同步以 ti 开头的数据库
  3. replicate-do-db = ["ops","~^ti.*"]
  4. # china 数据库下有 guangzhou / shanghai / beijing 等多张表,只同步 shanghai 与 beijing 表。
  5. # 指定同步 china 数据库下 shanghai 表
  6. [[replicate-do-table]]
  7. db-name ="china"
  8. tbl-name = "shanghai"
  9. # 指定同步 china 数据库下 beijing 表
  10. [[replicate-do-table]]
  11. db-name ="china"
  12. tbl-name = "beijing"
  13. # ops 数据库下有 ops_user / ops_admin / weekly 等数据表,只需要同步 ops_user 表。
  14. # 因 replicate-do-db 优先级比 replicate-do-table 高,所以此处设置只同步 ops_user 表无效,实际工作会同步 ops 整个数据库
  15. [[replicate-do-table]]
  16. db-name ="ops"
  17. tbl-name = "ops_user"
  18. # history 数据下有 2017_01 2017_02 ... 2017_12 / 2016_01 2016_02 ... 2016_12 等多张表,只需要同步 2017 年的数据表
  19. [[replicate-do-table]]
  20. db-name ="history"
  21. tbl-name = "~^2017_.*"
  22. # 忽略同步 ops 与 fault 数据库
  23. # 忽略同步以 www 开头的数据库
  24. ## 因 replicate-do-db 优先级比 replicate-ignore-db 高,所以此处忽略同步 ops 不生效。
  25. replicate-ignore-db = ["ops","fault","~^www"]
  26. # fault 数据库下有 faults / user_feedback / ticket 等数据表
  27. # 忽略同步 user_feedback 数据表
  28. # 因 replicate-ignore-db 优先级比 replicate-ignore-table 高,所以此处设置只忽略同步 user_feedback 表无效,实际工作会忽略同步 fault 整个数据库
  29. [[replicate-ignore-table]]
  30. db-name = "fault"
  31. tbl-name = "user_feedback"
  32. # order 数据下有 2017_01 2017_02 ... 2017_12 / 2016_01 2016_02 ... 2016_12 等多张表,忽略 2016 年的数据表
  33. [[replicate-ignore-table]]
  34. db-name ="order"
  35. tbl-name = "~^2016_.*"

Sharding 同步支持

根据配置文件的 route-rules,支持将分库分表的数据导入到同一个库同一个表中,但是在开始前需要检查分库分表规则,如下:

  • 是否可以利用 route-rules 的语义规则表示
  • 分表中是否包含唯一递增主键,或者合并后是否包含数据上有冲突的唯一索引或者主键

暂时对 DDL 支持不完善。

sharding

分库分表同步示例

  1. 只需在所有 MySQL 实例下面,启动 Syncer, 并设置 route-rules。
  2. replicate-do-db & replicate-ignore-db 与 route-rules 同时使用场景下,replicate-do-db & replicate-ignore-db 需要指定 route-rules 中 target-schema & target-table 的内容。
  1. # 场景如下:
  2. # 数据库A 下有 order_2016 / history_2016 等多个数据库
  3. # 数据库B 下有 order_2017 / history_2017 等多个数据库
  4. # 指定同步数据库A order_2016 数据库,数据表如下 2016_01 2016_02 ... 2016_12
  5. # 指定同步数据库B order_2017 数据库,数据表如下 2017_01 2017_02 ... 2017_12
  6. # 表内使用 order_id 作为主键,数据之间主键不冲突
  7. # 忽略同步 history_2016 与 history_2017 数据库
  8. # 目标库需要为 order ,目标数据表为 order_2017 / order_2016
  9. # Syncer 获取到上游数据后,发现 route-rules 规则启用,先做合库合表操作,再进行 do-db & do-table 判定
  10. ## 此处需要设置 target-schema & target-table 判定需要同步的数据库
  11. [[replicate-do-table]]
  12. db-name ="order"
  13. tbl-name = "order_2016"
  14. [[replicate-do-table]]
  15. db-name ="order"
  16. tbl-name = "order_2017"
  17. [[route-rules]]
  18. pattern-schema = "order_2016"
  19. pattern-table = "2016_??"
  20. target-schema = "order"
  21. target-table = "order_2016"
  22. [[route-rules]]
  23. pattern-schema = "order_2017"
  24. pattern-table = "2017_??"
  25. target-schema = "order"
  26. target-table = "order_2017"

Syncer 同步前检查

  1. 检查数据库版本。

    使用 select @@version; 命令检查数据库版本。目前,Syncer 只支持以下版本:

    • 5.5 < MySQL 版本 < 8.0
    • MariaDB 版本 >= 10.1.2(更早版本的 binlog 部分字段类型格式与 MySQL 不一致)

      注意:

      如果上游 MySQL/MariaDB server 间构成主从复制结构,则

      • 5.7.1 < MySQL 版本 < 8.0
      • MariaDB 版本 >= 10.1.3
  2. 检查源库 server-id

    可通过以下命令查看 server-id

    1. show global variables like 'server_id';
    1. +---------------+-------+
    2. | Variable_name | Value |
    3. +---------------+-------+
    4. | server_id | 1 |
    5. +---------------+-------+
    6. 1 row in set (0.01 sec)
    • 结果为空或者为 0,Syncer 无法同步数据。
    • Syncer server-id 与 MySQL server-id 不能相同,且必须在 MySQL cluster 中唯一。
  3. 检查 Binlog 相关参数。

    1. 检查 MySQL 是否开启了 binlog。

      使用如下命令确认是否开启了 binlog:

      1. show global variables like 'log_bin';
      1. +--------------------+---------+
      2. | Variable_name | Value |
      3. +--------------------+---------+
      4. | log_bin | ON |
      5. +--------------------+---------+
      6. 1 row in set (0.00 sec)

      如果结果是 log_bin = OFF,则需要开启 binlog,开启方式请参考官方文档

    2. binlog 格式必须为 ROW,且参数 binlog_row_image 必须设置为 FULL,可使用如下命令查看参数设置:

      1. select variable_name, variable_value from information_schema.global_variables where variable_name in ('binlog_format','binlog_row_image');
      1. +------------------+----------------+
      2. | variable_name | variable_value |
      3. +------------------+----------------+
      4. | BINLOG_FORMAT | ROW |
      5. | BINLOG_ROW_IMAGE | FULL |
      6. +------------------+----------------+
      7. 2 rows in set (0.001 sec)
      • 如果以上设置出现错误,则需要修改磁盘上的配置文件,然后重启 MySQL。
      • 将配置的更改持久化存储在磁盘上很重要,这样在 MySQL 重启之后才能显示相应更改。
      • 由于现有的连接会保留全局变量原先的值,所以不可以使用 SET 语句动态修改这些设置。
  4. 检查用户权限。

    1. 全量导出的 Mydumper 需要的用户权限。

      • Mydumper 导出数据至少拥有以下权限:select, reload
      • Mydumper 操作对象为 RDS 时,可以添加 --no-locks 参数,避免申请 reload 权限。
    2. 增量同步 Syncer 需要的上游 MySQL/MariaDB 用户权限。

      需要上游 MySQL 同步账号至少赋予以下权限:

      1. select, replication slave, replication client
    3. 下游 TiDB 需要的权限

      | 权限 | 作用域 | |——:|:———| | SELECT | Tables | | INSERT | Tables | | UPDATE | Tables | | DELETE | Tables | | CREATE | Databases,tables | | DROP | Databases, tables | | ALTER | Tables | | INDEX | Tables |

      为所同步的数据库或者表,执行下面的 GRANT 语句:

      1. GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX ON db.table TO 'your_user'@'your_wildcard_of_host';
  5. 检查 SQL mode。

    必须确认上下游的 SQL mode 一致;如果不一致,则会出现数据同步的错误。

    1. show variables like '%sql_mode%';
    1. +---------------+-----------------------------------------------------------------------------------+
    2. | Variable_name | Value |
    3. +---------------+-----------------------------------------------------------------------------------+
    4. | sql_mode | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
    5. +---------------+-----------------------------------------------------------------------------------+
    6. 1 row in set (0.01 sec)
  6. 检查字符集。

    TiDB 和 MySQL 的字符集的兼容性不同,详见 TiDB 支持的字符集

  7. 检查同步的表是否都有主键或者唯一索引。

    如果表没有主键或唯一索引,就没法实现幂等,并且此时在下游更新每条数据时都是扫全表,可能导致同步速度变慢,所以建议同步的表都加上主键。

监控方案

Syncer 使用开源时序数据库 Prometheus 作为监控和性能指标信息存储方案,使用 Grafana 作为可视化组件进行展示,配合 AlertManager 来实现报警。其方案如下图所示:

monitor_scheme

配置 Syncer 监控与告警

Syncer 对外提供 metric 接口,需要 Prometheus 主动获取数据。配置 Syncer 监控与告警的操作步骤如下:

  1. 在 Prometheus 中添加 Syncer job 信息,将以下内容刷新到 Prometheus 配置文件,重启 Prometheus 后生效。

    1. - job_name: 'syncer_ops' // 任务名字,区分数据上报
    2. static_configs:
    3. - targets: ['10.1.1.4:10086'] // Syncer 监听地址与端口,通知 Prometheus 获取 Syncer 的监控数据。
  2. 配置 Prometheus 告警,将以下内容刷新到 alert.rule 配置文件,重启 Prometheus 后生效。

    1. # syncer
    2. ALERT syncer_status
    3. IF syncer_binlog_file{node='master'} - ON(instance, job) syncer_binlog_file{node='syncer'} > 1
    4. FOR 1m
    5. LABELS {channels="alerts", env="test-cluster"}
    6. ANNOTATIONS {
    7. summary = "syncer status error",
    8. description="alert: syncer_binlog_file{node='master'} - ON(instance, job) syncer_binlog_file{node='syncer'} > 1 instance: {{ $labels.instance }} values: {{ $value }}",
    9. }

Grafana 配置

  • 进入 Grafana Web 界面(默认地址: http://localhost:3000 ,默认账号: admin 密码: admin)

  • 导入 dashboard 配置文件

    点击 Grafana Logo -> 点击 Dashboards -> 点击 Import -> 选择需要的 Dashboard 配置文件上传 -> 选择对应的 data source

Grafana Syncer metrics 说明

title: binlog events

  • metrics: rate(syncer_binlog_event_count[1m])
  • info: 统计 Syncer 每秒已经收到的 binlog 个数

title: binlog event transform

  • metrics: histogram_quantile(0.8, sum(rate(syncer_binlog_event_bucket[1m])) by (le))
  • info: Syncer 把 binlog 转换为 SQL 语句的耗时

title: transaction latency

  • metrics: histogram_quantile(0.95, sum(rate(syncer_txn_cost_in_second_bucket[1m])) by (le))
  • info: Syncer 在下游 TiDB 执行 transaction 的耗时

title: transaction tps

  • metrics: rate(syncer_txn_cost_in_second_count[1m])
  • info: Syncer 在下游 TiDB 每秒执行的 transaction 个数

title: binlog file gap

  • metrics: syncer_binlog_file{node="master"} - ON(instance, job) syncer_binlog_file{node="syncer"}
  • info: Syncer 已经同步到的 binlog position 的文件编号距离上游 MySQL 当前 binlog position 的文件编号的值;注意 MySQL 当前 binlog position 是定期查询,在一些情况下该 metrics 会出现负数的情况

title: binlog skipped events

  • metrics: rate(syncer_binlog_skipped_events_total[1m])
  • info: Syncer 跳过的 binlog 的个数,你可以在配置文件中配置 skip-ddlsskip-dmls 来跳过指定的 binlog

title: position of binlog position

  • metrics: syncer_binlog_pos{node="syncer"} and syncer_binlog_pos{node="master"}
  • info: 需配合 file number of binlog position 一起看。syncer_binlog_pos{node="master"} 表示上游 MySQL 当前 binlog position 的 position 值,syncer_binlog_pos{node="syncer"} 表示上游 Syncer 已经同步到的 binlog position 的 position 值

title: file number of binlog position

  • metrics: syncer_binlog_file{node="syncer"} and syncer_binlog_file{node="master"}
  • info: 需要配置 position of binlog position 一起看。syncer_binlog_file{node="master"} 表示上游 MySQL 当前 binlog position 的文件编号,syncer_binlog_file{node="syncer"} 表示上游 Syncer 已经同步到的 binlog 位置的文件编号

title: execution jobs

  • metrics: sum(rate(syncer_add_jobs_total[1m])) by (queueNo)
  • info: Syncer 把 binlog 转换成 SQL 语句后,将 SQL 语句以 jobs 的方式加到执行队列中,这个 metrics 表示已经加入执行队列的 jobs 总数

title: pending jobs

  • metrics: sum(rate(syncer_add_jobs_total[1m]) - rate(syncer_finished_jobs_total[1m])) by (queueNo)
  • info: 已经加入执行队列但是还没有执行的 jobs 数量