-
从节点接收到主节点发送过来的数据把它放置到中继日志(Relay log)文件中。并记录该次请求到主节点的具体哪一个二进制日志文件内部的哪一个位置(主节点中的二进制文件会有多个,在后面详细讲解)。
-
从节点启动另外一个线程(sql Thread ),把 Relay log 中的事件读取出来,并在本地再执行一次。
在最开始的复制实现版本中,I/O thread 和 SQL thread 为一个线程,后续将 I/O thread 和 SQL Thread 拆开,但是 I/O thread 和 SQL Thread 依然是单线程。由于 Master 实例是多线程并发执行,而 Slave 仅仅是一个单线程执行,所以导致在这种模式下,在 Master 并发较高时,会出现比较严重的主从延迟。
5. 数据同步格式
==========
数据同步的格式分为三种:
-
基于语句复制
-
基于行复制
-
混合复制
5.1 基于语句复制
基于语句复制实现原理就是从库(slave)基于产生变化的SQL语句从主库(master)进行复制。在MySQL5.1.4版本之前是binlog和复制唯一支持的模式,也是MySQL5.5中默认的格式。
优点
-
久经考验、技术成熟
-
产生数据少
例如 delete 一张表的所有记录,假设有 10000 行,基于语句则只需要写入一行 SQL,而基于行则需要写入每一行的变更情况
- 由于 binLog 文件记录了所有变更,可以用来审计数据库
缺点
- 基于语句复制,可能产生数据不一致。
例如在主库上执行不确定函数 UUID,每次执行产生的数据都不一样,就会导致主从数据不一致。还有一些其他的情况可以参考 MySQL 官方文档。
- 对于复杂的语句,在 Slave 执行前还需要进行解析,优化。
5.2 基于行复制
基于行的复制不复制SQL语句,而是将插入,删除或更新操作的各行进行复制。
优点
-
所有的改变都可复制,这是最安全的复制模式。
-
基于行复制的实现的技术和其它大多数的数据库是一样的。
-
在Master上需要的行锁会很少,从而获得更高的并发性。
缺点
-
需要写入更多的数据
-
大 SQL 产生大量行记录变更,会导致复制变慢
-
不能从 binLog 中看到执行过那些具体的语句(目前有工具可以翻译行记录)
-
对MyISAM表并发插入时,不支持基于行的模式。
5.3 基于混合模式的复制
混合模式复制背后的原理很简单:正常情况下使用基于语句的复制,对于不安全的语句切换为基于行的复制。
5.4 目前主流使用的复制模式
现在使用最多的依然是行复制模式,虽然混合模式可以结合基于行和基于语句的优点。我理解是因为在我们日常的使用中,MySQL 的复制不仅仅是用来作为主从实例之间的复制,还有用来作为不同存储介质之间的数据同步。例如有时候我们会将 MySQL 的 BinLog 同步到 ES 中作为搜索,也会将 MySQL 同步到 kafka 作为流式计算的源头。所以需要统一的格式。
6. 数据同步方式
==========
数据同步的方式分为四类:
-
基础模式
-
基于库的并行复制
-
基于组提交的并行复制
-
基于记录集的并行复制
6.1 基础模式
基础模式就是在第 4 节提到的基础模型,基础模型存在的问题,我们也提到了基础模型的缺点,即 Slave 实例的 I/O thread 以及 SQL thread 都是单线程,在 master 并发较高时,将和 Master 产生较大的主从延迟。
6.2 基于库的并行复制
基于库的并行复制原理非常简单,即在 Slave 上执行变更时,不同库的变更可以并发执行。因为 MySQL 不存在跨库事务,不同库之间不存在竞争,所以可以直接并发执行。
基于库并行复制并没有解决多少问题,因为目前在高并发的情况下,我们时常将重要的库单独放在一个实例上面,这个时候基于库的并行复制就失去了作用。依然会存在较高主从延迟的风险。
6.3 基于组提交的并行复制
理解基于组提交的并行复制就需要前面我们提到的 commit 二阶段流程以及组提交。即在 Master 上将 binLog 写入磁盘时,处于 commit 二阶段流程的 binLog Stage 阶段。在该阶段已经完成了锁竞争,所以此时在 Master 上并发写 binLog 的事务,在 Slava 上也可以并发执行。在写入 binLog 时会在行变更记录中写入一个 last_commit 字段,即上一次组提交的提交号。
例如:
初始 last_commit = 0
第一次组提交:
事务一和事务二并发提交,写入两条记录。
事务一: last_commit = 0
事务二: last_commit = 0
第一次组提交写入完成之后 last_commit = 1
第二次组提交:
事务三和事务四并发提交,写入两条记录。
事务三:last_commit = 1
事务四:last_commit = 1
在 Slave 上执行时,事务一和事务二 last_commit 相同可以并发执行。等到事务一和事务二执行完成之后,又可以开始并发执行事务三和事务四。
基于组提交的并发复制还有什么问题吗?
诚然基于组提交解决了在高并发场景下的一些问题,但是还是有一些问题没有解决。例如我们需要从 0 开始构建一个从库,这是时候主库上的一些 SQL 可能并没有并发竞争,可以并发执行。但是因为他是分散在不同的时间段执行的,所以并没有在同一个组提交的事务组里面。导致只能顺序执行。那么有什么办法能够解决这个问题吗?当然有,就是下面提到的基于记录集的并行复制。
6.4 基于记录集的并行复制
基于记录集的并行复制在 Slave 执行阶段并没有任何变化,而是在 Master 中 binLog 写入时改变了 last_commit 的实现方式。从图中可以看到,在 Master 写入 BinLog 的时候会有一张 Hash 表,然后有一个 m_writeset_history_start 的值。当我们事务写入一个变更时,会依据当前事务所涉及的索引、主键等数据通过一个算法计算出一个哈希值。然后判断当前哈希值在哈希表中的槽位是否被占用,如果未被占用则使用 m_writeset_history_start 作为 last_commit 的值。
如图:
事务一:更新 id 为 1 的数据,占用槽位 1 ,不存在冲突,last_commit = 1
事务二:更新 id 为 2 的数据,占用槽位 2 ,不存在冲突,last_commit = 1
事务三:更新 id 为 3 的数据,占用槽位 3 ,不存在冲突,last_commit = 1
这样即使三个事务不在一个组提交事务里面,在从库执行时依然可以并发执行。
6.5 我应该用哪一种呢?
参见复制性能比较:blogs.oracle.com/mysql/post/…
7. 数据同步时机
==========
数据同步的时机分为四类:
-
异步复制
-
全同步复制
-
半同步复制
-
无损复制
7.1 异步复制
-
原理:在异步复制中,master写数据到binlog且sync,slave request binlog后写入relay-log并flush disk
-
优点:复制的性能最好
-
缺点:master挂掉后,slave可能会丢失事务
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
技术学习总结
学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。
最后面试分享
大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!
r-1710699764560)]
技术学习总结
学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。
[外链图片转存中…(img-f49MDEl3-1710699764561)]
[外链图片转存中…(img-lB5C5X2z-1710699764561)]
[外链图片转存中…(img-9HGmMDFD-1710699764562)]
最后面试分享
大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!
[外链图片转存中…(img-rdjnXURY-1710699764562)]
[外链图片转存中…(img-FeKc9LJR-1710699764563)]