MySQL主从同步分析
1 同步原理
slave 从 master 节点复制数据主要有 4 个步骤
- 1,master 对所有 DDL 和 DML 产生的日志写入 binlog
- 2, Slave 的 IO Thread 线程从主库中 bin log 中读取取日志。类似 tailf 命令
- 3, Slave 的 IO Thread 线程把读取的日志放到 relay-bin 文件里,如果不放到文件里,SQL Thread 线程重放过慢的会导致丢数据
- 4, Slave 的 SQL Thread 线程将主库的 DDL 和 DML 操作事件在 slave 中重放
1,2,3 步骤都是顺序读写,在不考虑网络延迟的情况下,slave 不会产生延迟.但是第 4 步 DML 和 DDL 的 IO 操作是随即的,不是顺序的.不考虑硬件,主从复制延迟主要在这里
1.1 随机读写与顺序读写区别
如下是内存块,每个块最大存 4k
1k | 2k |
---|---|
4k | 3k |
3k |
我如果删除 1k 这个块的数据再加个 2k 的块的数据
如果是顺序读写
1k 的数据删除掉之后就丢掉,新加数据直接在后面的块添加数据
2k | |
---|---|
4k | 3k |
3k | 2k |
如果是随机读写
1k 的数据删除掉之后改成 2k 的数据
2k | 2k |
---|---|
4k | 3k |
3k |
2 主从复制产生原因
硬件原因
- Master 负载
- Slave 负载
- 网络延迟
- 机器配置(cpu、内存、硬盘)
软件原因
- SQL Thread 是随机读写并且单线程,master 并发写入的话会导致 SQL Thread 来不及重放导致 slave 产生延迟,解决方案就是改成多线程
改进为多线程
注意点:
- 不能造成更新覆盖.这就需要更新同一行的两个事务,必须分发到同一个 worker 中
- 同一个事务不能拆开,必须放到同一个 worker 中
SQL Thread Corrdinator 负责给 SQL Thread Worker 分配重写任务
MySQL5.6 及以上版本支持多线程,但是 5.7 版本才实现真正的多线程,区别如下
- 5.6: I/O thread 同步并发线程是以库级别并行的,也就是说两个库可以并行两个线程,三个库可以并行三个线程,但是注意一个库不要开启并行,影响性能.而且就算开启也会存在 slave 同步延迟
- 5.7: I/O thread 同步并发线程可以做到按行级别并行,线程数量一般与 CPU 数量一样,可以做到 slave 节点无延迟,slave_parallel_workers=4,slave_parallel_type=LOGICAL_CLOCK,这两个参数一定要加上
3 mysql5.7 如何分配 SQL Thread 任务
一句话: 一个组提交的事务都是可以并行回放 ,因为这些事务都已进入到事务的 prepare 阶段,则说明事务之间没有任何冲突(否则就不可能提交)。
3.1 数据更新流程
- 执行器先从引擎找到数据,如果在内存中直接返回,如果不再内存中,查询后返回
- 执行器拿到数据后先修改数据,然后调用引擎接口重新写入数据. 如果这步 mysql 服务宕机,因为 redo 里没有 prepare 状态,会放弃这部分数据
- 引擎数据更新到内存,同事写数据到 redo 中,此时处于 prepare 阶段,并通知执行器执行完成,随时可以操作. 如果这步 MySQL 宕机,重启后先查看 redolog 的 prepare 状态的数据在 binlog 里有没有,如果有就提交,没有丢弃
- 执行器生产这个操作的 binlog.如果这步 MySQL 宕机,重启后先查看 binlog 日志对比 redolog,只有在他俩一致的情况提交,否则丢弃
- 执行器调用引擎的事务提交接口,引擎把刚刚写完的 redo 改成 commit 状态,更新完成
通过两阶段提交保证数据准确性,要么没有,要么有就是最全的
3.2 GTID
这里我有些薄弱,先简单写写后期补上
当事务提交时,它们将在单个操作中写入到二进制日志中。如果多个事务能同时提交成功,那么它们意味着没有冲突,因此可以在 Slave 上并行执行,所以通过在主库上的二进制日志中添加组提交信息。所有已经处于 prepare 阶段的事务,都是可以并行提交的。这些当然也可以在从库中并行提交,因为处理这个阶段的事务都是没有冲突的。在一个组里提交的事务,一定不会修改同一行。这是一种新的并行复制思路,完全摆脱了原来一直致力于为了防止冲突而做的分发算法,等待策略等复杂的而又效率底下的工作。
并且不开启 GTID 的话 MySQL 会自动生成匿名的 GTID,完全不需要担心 GTID 限制
而 MySQL5.7 版本就是按照组提交分发 SQL Thread 任务的
4 MTS 调优
1 | slave-parallel-type=LOGICAL_CLOCK # 基于组提交的并行复制 |
5 监控
复制的监控依旧可以通过 SHOW SLAVE STATUS\G,但是 MySQL 5.7 在 performance_schema 架构下多了这些表,用户可以更细力度的进行监控:
1 | show tables like 'replication%'; |
总结:MTS+二阶段提交,配合主从切换是服务不可用时间,基本上不会出现 slave 与 master 数据不一致问题
但是有个遗留问题:如果 master 频繁修改一行,其他数据修改不频繁,性能可能比但进程复制性能要差