原文链接:https://zhuanlan.zhihu.com/p/669450627
一、主从同步概述
mysql主从同步,即MySQL Replication,可以实现将数据从一台数据库服务器同步到多台数据库服务器。MySQL数据库自带主
从同步功能,经过配置,可以实现基于库、表结构的多种方案的主从同步。可以对MySQL做主从架构并且进行读写分离,让主服务器(Master)处理写请求,从服务器(Slave)处理读请求,这样可以
进一步提升数据库的并发处理能力,如下图所示:
二、主从同步作用
一般来说,优先考虑优化sql及索引等,充分发挥数据库的最大性能;其次是采用缓存的策略,比如使用redis、magodb
等缓存工具,通过其高性能的优势把数据保存在内存数据库中,提升读取的效率,最后才是采取数据库主从架构,进行读写分
离(因为成本高)。
2.1 读写分离
通过主从复制的方式来同步数据,之后通过读写分离的方法提升数据库并发处理能力。简单来说就是数据放在多个数据库中,其中一
个是Master主库,其余的是Slave从库。当主数据库数据发生变化时,会自动将数据同步到从数据库中,程序可以设置去从库
读取数据,从而实现读写分离
2.2 数据备份
主从同步属于数据热备份机制,在主库正常运行下备份,不影响提供查询服务。
2.3 高可用性
数据备份其实是冗余的机制,通过冗余的方式可以换取数据库的高可用性,当服务器出现故障、宕机等无可用的情况下,可
以迅速进行故障切换,让从库当主库,保证服务正常运行。
三、主从同步原理
3.1 主从同步流程图
3.2 主从同步执行流程
1、从库不断试探主库的二进制日志文件(binlog),如果这个文件有更新则发送请求从主库获取新的内容;
2、用户向主库中写数据:包括添加、删除、修改、建库建表等操作;
3、主库将写的命令记录到二进制文件并更新二进制文件的偏移量;
4、从库试探主库二进制文件发现偏移量与从库中记录的偏移量值不一样时表示主库有更新,那么启动IO线程向主库请求从某个偏移量开始到二进制日志文件结束位置之间所有的数据;
5、主库根据从库请求,通过binlog dump线程将新偏移量推送到从库中;
6、从库获取主库的数据后,会将这些命令数据写入中继日志文件(relaylog)中,然后唤醒SQL线程同时让当前的IO线程挂起(休眠等待);
7、SQL线程根据记录的中继日志文件的偏移量读取中继日志文件中的命令;
8、SQL线程获取到命令后在本地数据库进行回放(就是从库中执行主库的SQL语句),回放完成当前SQL线程挂机(休眠等待)。
3.3 主从同步线程
msyql 的主从同步通过3个线程完成,其中1个线程在主库,2个线程在从库上。
如果一个主库连接多个从库,那么主库将会给每个处于连接状态的从库创建一个Binary log dump线程,每个从库也有自己的同步I/O以及SQL线程。
3.3.1 Binary log dump 线程
当从库连上主库时,主库会创建一个线程来发送 binlog 的内容给从库。
在数据库终端执行sql: SHOW PROCESSLIST , 可以看到 Binlog Dump 线程。
binlog dump 线程在binlog中读取要发送给从库的数据时,会对binlog加锁。一旦数据读取完成,线程将释放锁,即使数据还未发送到从库。
3.3.2 IO 线程
当在从库上执行sql: START SLAVE ,从库将创建一个I/O线程。该线程将连接主库,并请求主库发送binlog中更新的记录给从库。
主库的Binlog Dump线程,将更新的binlog发送到从库,从库的 I/O线程将这些更新入从库的relay log。
在从库中执行sql: SHOW SLAVE STATUS, 能够看到 Slave_IO_running 的状态。
3.3.3 IO 线程
从库创建同步SQL线程来读取 relay log,并执行其中的事务。
一个从库使用2个线程将从主库读取更新以及在从库执行数据更新分成独立的任务。因此,从主库读取更新的任务不会减慢,即使从库执行数据更新任务很慢。例如,如果从库停止运行一段时间后再启动从库,从库的 I/O线程能够快速获从主库取到所有的binlog,即使 SQL 线程滞后。如果从库在 SQL线程执行所有更新前停止运行, I/O 线程至少获取到了一份安全的更新binlog并保存到从库的relay log, 当下次启动从库后就可能执行数据更新。
在从库上通过设置系统变量 slave_parallel_workers 的值大于0(默认值),可以开启并行处理任务。当该变量设置了,从库设置创建设置的数量的worker 线程,以及一个协调线程来管理worker 线程。如果你在使用多从库通道,每个通道都将有这么多线程。slave_parallel_workers大于0从库一般被称为多线程从库(副本)。一旦这么设置,失败的事务将会被重试。
3.4 Relay log与从库元数据存储
从库(副本)也会记录从库(源库)的binlog的当前位置以及从库的relay log。
在同步过程中,一个从库创建多个信息库。
3.4.1 relay log
该log有 I/O线程写入,log中的事务来自主库的binlog,并且将被 SQL线程执行更新到从库。
3.4.2 从库连接元数据存储
包含了从库I/O线程连接主库需要的信息,以及从主库binlog中检索事务需要的信息。连接元数据存储被写进表mysql.slave_master_info或者一个文件中。
3.4.3 从库的应用程序元数据存储
包含了从库SQL线程从relay log读取事务以及将事务更新到从库的信息。从库的应用程序元数据存储被写进表mysql.slave_relay_log_info 或者 一个文件中。
从库连接元数据存储与从库的应用程序元数据存储被统称为从库元数据存储,可以参考更多相关说明
使从库能够灵活应对宕机: 事务性存储引擎InnoDB创建表mysql.slave_master_info 与 表mysql.slave_relay_log_info。从库的应用程序元数据存储表更新将与事务一起提交, 也就是记录在元数据存储中的从库进度信息一直与从库的更新保持一致,即使从库宕机。
四、解决主从数据一致性
4.1 全同步复制
全同步复制,就是当主库执行完一个事务之后,要求所有的从库也都执行完该事物,才可以返回处理结果给客户端;因此,虽然
全同步复制数据一致性得到保证了,但是主库完成一个事务需要等待所有从库完成,性能难免会降低。
4.2 异步复制
异步复制,就是当主库提交事物后,会通知binlog dump线程发送binlog 日志给从库,一旦binlog dump线程将binlog 日志
发送给从库之后,不需要等到从库也同步完成事物,主库就会将处理结果返回给客户端。
主库只管自己完成事物,就将处理结果返回给客户端(此时从库不一定完成同步事物),可能导致主从数据不一致问题,比如刚在
主库新增的数据,马上去从库查询就可能查询不到。而且当主库提交完事物后,如果宕机了,可能会导致binlog 日志未同步给从库,
同时为了回复故障切换主从节点的话,就会出现数据丢失问题。因此,虽然异步复制性能高,但是数据一致性是最弱的。
mysql主从复制,默认采用的就是异步复制这种复制策略。
4.3 半同步复制
mysql5.5 版本后开始支持半同步复制方式。原理就是在客户端提交commit之后不直接将结果返回客户端,而是至少等待至少有一个从
库收到binlog ,并且写到中继日志之后再返回给客户端。优点:提高数据一致性。缺点:降低主库写的效率。
mysql5.7 版本中增加了一个rpl_semi_sync_master_wait_for_slave_count参数,可以根据需要响应的从库数据库数量
设置,默认为1,也就是一个从库有了响应,就返回给客户端。如果这个参数调大,就可以提高数据一致性。
4.4 增强半同步复制
增强半同步复制,是mysql 5.7.2后的版本对半同步复制做的一个改进,原理上几乎是一样的,主要是解决幻读的问题。
主库配置了参数 rpl_semi_sync_master_wait_point = AFTER_SYNC 后,主库在存储引擎提交事务前,必须先收到从库数据
同步完成的确认信息后,才能提交事务,以此来解决幻读问题