MySQL 的并行复制, 从 5.6 开始, 经过几代的改进, 终于在性能上有了不小的提升.
MySQL 5.6
该版本开始提供并行复制功能, 但是 5.6 的并行复制是 schema 级别的, 所以只有 binlog 的 row event 操作的是不同的 schema 对象, 且没有 DDL 和 Foreign Key 依赖的情况下, 才能实现并行复制. 由于单 schema 的情况实际上是很常见的, 所以这并不是真正意义上的并行复制.
如上图所示, 5.6 的并行复制由 Coordinator 判断 event 的 schema, 并把不同 schema 的 event 提交到不同的 worker 上实现并行复制.
MySQL 5.7
开始, 并行复制使用了 "组提交 (Group Commit)" 的方法实现, 即是说 5.7 的并行复制打破了 5.6 并行复制不能在单个 schema 的限制, 5.7 可以基于主库上事务的提交顺序, 在从库上回放. 也就是说, 如果两个事务不会相互影响, 在主库可以同时提交刷盘, 从库复制时也就可以同时提交. 通过设置 binlog_group_commit_sync_delay 参数, 可以延长主库 commit 时日志刷盘前等待的时间 (会影响主库写入性能), 从而使更多不会冲突的事务可以作为组提交, 从而提高从库的复制效率. 虽然 5.7 的这种方式算得上是真正的并行复制了, 但是由于依赖主库上并行, 从库才能并行, 假如主库上并发不高, 从库上就只能 "线性" 复制了.
MySQL 8.0
MySQL 8.0 新增参数 binlog_transaction_dependency_tracking, 可以配置为基于 5.7 的并行复制 COMMIT_ORDER, 并较 5.7 新添加了 WRITESET 或 WRITESET_SESSION 模式 (WRITESET 跟 WRITESET_SESSION 的区别就是, WRITESET_SESSION 需要保证同一个会话内的事务的先后顺序), 即事务在提交时, 会影响的行的主键, 唯一键, 外键等信息以 HASH(DB 名, TABLE 名, KEY 名称, KEY_VALUE1, KEY_VALUE2,.....) 加入到当前事务的 WRITESET 中, 在复制之前, 只需要检测 WRITESET 是否有并集, 即可知道事务是否可以并行回放.
如图, 在主库的并发情况如下时
在 WRITESET 开启后, 备库的复制将会如下图的方式并行执行
性能对比 (COMMIT_ORDER & WRITESET & WRITESET_SESSION)
首先准备 3 对主从复制的副本集, binlog_transaction_dependency_tracking 分别配置为 COMMIT_ORDER,WRITESET,WRITESET_SESSION.
使用 sysbench 的 oltp 并发操作数据库的主库:
- mysqladmin create sbtest
- sysbench --MySQL-host=127.0.0.1 --MySQL-port=3306 --MySQL-user=root --MySQL-password= \
- --test=/usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --oltp_tables_count=2 --oltp-table-size=10000000 --rand-init=on prepare
- sysbench --MySQL-host=127.0.0.1 --MySQL-port=3306 --MySQL-user=root --MySQL-password= \
- --test=/usr/share/sysbench/tests/include/oltp_legacy/oltp.lua --oltp_tables_count=2 \
- --oltp-table-size=10000000 --num-threads=100 --oltp-read-only=off \
- --report-interval=10 --rand-type=uniform --max-time=120 \
- --max-requests=0 --percentile=99 run
同时使用 mysqladmin 分别在主库, 从库执行, 可以看到主库, 从库上的并发和负载情况, 下面的命令将会每隔 1 秒输出 3 列数据, 分别为: 正在执行请求数, 当前连接数, 正在运行线程数
(mysqladmin ext -i1 | awk '/Queries/{q=$4-qp;qp=$4}/Threads_connected/{tc=$4}/Threads_running/{printf"] ] ]\n", q, tc, $4}')
通过性能测试不难发现, MySQL 8.0 WRITESET_SESSION 模式在单线程时和 COMMIT_ORDER 模式差距不大, 但随着线程数增加, WRITESET_SESSION 优势很明显, 而 WRITESET 在线程较少时, 性能上有了质的飞跃. 但随着线程数的增加, 各种方式性能趋近于相同.
MySQL 8.0 现已登陆 云数据库 RDS 版, 如有需要, 可在阿里云控制台云购买使用!
(本文图片来源于网络)
参考文献:
来源: https://yq.aliyun.com/articles/700596