Contents
mysql复制
参考: mysql主从复制场景: https://cloud.tencent.com/developer/article/1662191
参考: mysql5.7文档: https://dev.mysql.com/doc/refman/5.7/en/replication.html
参考: mysql8文档: https://dev.mysql.com/doc/refman/8.0/en/server-configuration.html
MySQL版本辨析
mysql server (community)
mysql innodb cluster
mysql NDB cluster
复制场景

mysql8提供的复制
底层技术
异步复制(mysql5+), 半同步复制(mysql5+), 并行复制, gtid全局事务(mysql5.6+),组复制(mysql5.7+)
什么是主从复制
主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;主数据库是业务数据库, 从库相当于主库的备份。
\2. 主从复制原理(实现过程)?
步骤一:主库db的更新事件(update、insert、delete)被写到主库的binlog
步骤二:从库发起连接,连接到主库
步骤三:此时主库创建一个binlog dump 线程,把binlog的内容发送到从库
步骤四:从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log
步骤五:从还会创建一个SQL线程,从relaylog里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db
简单来说就是:主库db的更新事件被写入到主库的bin-log;从库读取主库的bin-log,并将bin-log的内容写到到自己的relad log;从库读取relady log,解析成sql语句,将更新的内容写到的从库的db。
复制的作用
MySQL 中复制的优点包括:
- 横向扩展解决方案 – 在多个副本之间分散负载以提高性能。在这种环境中,所有写入和更新都必须在源服务器上进行。然而,读取可能发生在一个或多个副本上。该模型可以提高写入性能(因为源专用于更新),同时显着提高副本数量的读取速度。
- 数据安全——因为副本可以暂停复制过程,所以可以在副本上运行备份服务而不会损坏相应的源数据。
- 分析 – 可以在源上创建实时数据,而对信息的分析可以在副本上进行,而不会影响源的性能。
- 远程数据分发——您可以使用复制来创建数据的本地副本以供远程站点使用,而无需永久访问源。
复制的方法
- 传统的方法是基于从源的二进制日志中复制事件,并且要求日志文件和其中的位置在源和副本之间同步。(binlog+pos)
- 基于全局事务标识符(GTID) 的较新方法是事务性的,因此不需要处理日志文件或这些文件中的位置,这极大地简化了许多常见的复制任务。只要在源上提交的所有事务也已在副本上应用,使用 GTID 的复制可以保证源和副本之间的一致性. (binlog+gtid)
复制时的同步
参考: MySQL – 异步复制,半同步复制,增强半同步复制,组复制: https://blog.csdn.net/qq_33330687/article/details/107496954 参考: mysql官方文档: https://dev.mysql.com/doc/refman/8.0/en/replication.html
MySQL 中的复制支持不同类型的同步。
- 最初的同步类型是单向异步复制,其中一台服务器充当源,而一台或多台其他服务器充当副本。这与作为 NDB Cluster 特征的 同步复制形成对比(参见第 23 章,MySQL NDB Cluster 8.0)。
- 在 MySQL 8.0 中,除了内置的异步复制外,还支持半同步复制。对于半同步复制,在返回到执行事务的会话之前对源块执行的提交,直到至少一个副本确认它已接收并记录事务的事件;(看 第 17.4.10 节,“半同步复制”。
- MySQL 8.0 还支持延迟复制,这样一个副本故意落后于源至少指定的时间量;请参阅 第 17.4.11 节,“延迟复制”。
- 对于需要同步复制的场景 ,请使用 NDB Cluster(请参阅第 23 章,MySQL NDB Cluster 8.0)。
异步复制
以一主一从示例.
master上执行的所有的DDL/DML语句都会写到binlog日志文件里. slave会从relaylog中读sql并执行 这里slave有3个与复制相关的线程. dump thread, IO thread, SQL thread. 分别负责从master binlog取数据, 向 自己relaylog写数据, 从relaylog执行sql.
SQL thread可以增加多个线程, 并行加速复制
看下时序图:

这里在主从之间的复制是异步的. master上多个客户端执行的事务会顺序地写到binlog里, 不要求slave与master状态及时同步, 只要顺序地读binlog, slave最终会和master数据一致.
MySQL 默认的复制策略,Master处理事务过程中,将其写入Binlog就会通知Dump thread线程处理,然后完成事务的提交,不会关心是否成功发送到任意一个slave中
问题:一旦Master 崩溃,发送主从切换将会发送数据不一致性的风险。
画外音:性能最好
半同步复制
异步复制的问题是, slave上的数据可能会落后master上数据一段时间. 对于要求数据强一致的情况, 可能不大适用.
这就催生了半同步复制.

Master处理事务过程中,提交完事务后,必须等至少一个Slave将收到的binlog写入relay log返回ack才能继续执行处理用户的事务。
配置
#(什么时间点开始等ack)MySQL5.7 为了解决半同步的问题而设置的
rpl_semi_sync_master_wait_point = AFTER_COMMIT
#(最低必须收到多少个slave的ack)
rpl_semi_sync_master_wait_for_slave_count = 1
#(等待ack的超时时间)
rpl_semi_sync_master_timeout = 100
问题:
一旦Ack超时,将退化为异步复制模式,那么异步复制的问题也将发送
性能下降,增多至少一个RTT时间
数据不一致性问题,因为等待ACK的点是Commit之后,此时Master已经完成数据变更,用户已经可以看到最新数据,当Binlog还未同步到Slave时,发生主从切换,那么此时从库是没有这个最新数据的,用户又看到老数据。
增强的半同步复制
半同步复制未完全解决数据一致性问题. 催生了增强的半同步复制.

增强半同步和半同步不同是,等待ACK时间不同
#(唯一区别)
rpl_semi_sync_master_wait_point = AFTER_SYNC
半同步的问题是因为等待ACK的点是Commit之后,此时Master已经完成数据变更,用户已经可以看到最新数据,当Binlog还未同步到Slave时,发生主从切换,那么此时从库是没有这个最新数据的,用户又看到老数据。
增强半同步将等待ACK的点放在提交Commit之前,此时数据还未被提交,外界看不到数据变更,此时如果发送主从切换,新库依然还是老数据,不存在数据不一致的问题。
问题:
一旦Ack超时,将退化为异步复制模式,那么异步复制的问题也将发送
性能下降,增多至少一个RTT时间
如果超时时间设置很大,然后因为网络原来长时间收不到ACK,用户提交是被挂起的,可用性收到打击(半同步一样存在)
画外音:感觉MySQL因为直接提供增强半同步,半同步类似个过度产品
mysql高可用
参考: mysql集群简介及对比: https://juejin.cn/post/7027910561459503141
参考: 五大常见的MySQL高可用方案: https://zhuanlan.zhihu.com/p/25960208
参考: mysql官方文档: https://dev.mysql.com/doc/refman/8.0/en/group-replication.html
基于mysql组复制的高可用
一般与mysql cluster的其他组件一起使用(mysql router, mysql shell等).
组复制

MySQL在引擎层完成Prepare操作写Redo日志之后,会被MySQL的预设Hook拦截进入MGR层
MGR层将事务信息打包通过Paxos协议发送到全部节点上,只要集群中过半节点回复ACK,那么将告诉所有节点数据包同步成功,然后每个节点开始自己认证(certify)通过就开始写Binlog,提交事务或者写relay log,数据同步,如果认证不通过则rollback
什么是Certify?
在不同服务器上并发执行的事务之间可能存在冲突。这种冲突是通过检查和比较两个不同的并发事务的写入集来检测的,这个过程称为认证
在认证期间,冲突检测是在行级别执行的:如果在不同服务器上执行的两个并发事务更新了同一行,则存在冲突。
冲突解决过程指出,首先排序的事务将在所有服务器上提交,而第二次排序的事务将中止,因此将在原始服务器上回滚并被组中的其他服务器丢弃。
总结:MGR内部实现了分布式数据一致性协议,paxos通过其来保证数据一致性。
问题
性能不高
TP999升高,吞吐量降低;增大20%~30%响应时间
mysql与第三方工具实现的高可用
keepalived, HMA, zookeeper等
附录
并行加速复制
参考: https://blog.csdn.net/qq_33330687/article/details/107496954
传统的MySQL(5.6 版本之前)主从复制是单线程复制,即:1个dump thread线程,1个IO线程,1个SQL线程
想要提高复制的效率,很自然考虑多线程,虽然有3种线程可以扩展为多线程。但是MySQL只将SQL线程扩展为多线程
为什么Dump和IO线程不能多线程?
dump线程和IO线程都是负责网络传输,如果将这里扩展为多线程那么会将一份Binlog日志分割为多份,并行传输,那么在slave端将会要额外的增加代码考虑如何将多份日志还原为原来的Binlog,大大增加难度。
性能瓶颈不在IO,扩展后也没有多大效率提升。
画外音:为什么Redis 6.0使用IO多线程增强性能,MySQL这里使用IO多线程却不行?
Redis是多个Client节点一个Server节点(暂且这么看),IO线程需要处理多个不同Client来源的请求;MySQL主从复制,本质上是1个Client端一个Server端,增大IO线程也无济于事。
SQL线程并行后的难点
相同两个事务的执行顺序。假设A,B两个事务,A先执行,B后执行,都同时改同一行数据,如果主从同步过程中,因为并行执行,B先执行,A后执行,那么将导致数据不一致问题。所以需要一个机制去防止此类事情的发生。
对于这个问题,MySQL会判断当前需要复制的事务Id和与之前复制完毕的事务id进行比对,判断是否处于当前执行完毕事务之后,否则只能等待前驱事务复制完毕。(大概原理,本文不是讲解并行复制,不深入讲解)
发表回复