前言
MySQL 主从同步是 MySQL 集群方案中的一种,也是实现难度最低的一种。下面就探讨下主从同步怎么保证数据一致性问题了
1.什么是数据一致性?
数据一致性是指在一个系统中,数据在不同的部分、不同的时间点,以及不同的操作之间保持一致的状态。
数据一致性通常体现在以下几点:
数据一致性:确保数据的完整性意味着数据在存储和传输过程中没有被损坏或丢失。这包括数据的准确性、完整性和有效性。例如,在一个电商系统中,商品的库存数量应该是准确的。如果一个用户购买了一件商品,库存数量应该相应地减少。如果库存数量显示不正确,就会导致数据不一致。
事务一致性:在数据库系统中,事务是一组操作的集合,这些操作要么全部成功执行,要么全部回滚。事务一致性确保在一个事务中对数据的修改在事务提交后对所有用户都是可见的,并且如果事务失败,数据将恢复到事务开始之前的状态。例如,在一个在线预订系统中,用户预订了一个酒店房间,系统应该确保这个房间在预订期间不能被其他用户预订。如果出现多个用户同时预订同一个房间的情况,就会导致数据不一致。
多副本一致性:在分布式系统中,数据通常会存储在多个副本中,以提高系统的可用性和性能。多副本一致性确保不同副本之间的数据保持一致。例如,在一个云存储服务中,用户上传了一个文件,这个文件会被存储在多个数据中心的服务器上。如果用户对文件进行了修改,云存储服务应该确保所有副本都被更新,以保证用户在任何地方访问文件时都能看到最新的版本。
时间一致性:时间一致性要求数据在不同的时间点上保持一致,这包括数据的时效性和顺序性。例如,在一个股票交易系统中,交易订单的处理应该按照时间顺序进行。如果订单的处理顺序出现错误,就会导致交易数据不一致。
PS:我们本文主要讨论的是多副本在同一时间上的数据一致性问题。
2.主从复制
MySQL 主从复制是一种将 MySQL 主数据库的数据,同步到其他的数据库的一种机制,从而实现数据的冗余备份和负载均衡,平行扩展了数据库的查询能力。
主从数据库基本概念:
主数据库(Master) :主数据库是数据的主要来源,负责接收和处理所有的写操作(INSERT、UPDATE、DELETE 等)。主数据库将所有的写操作记录到二进制日志(Binary Log)中,这些日志记录了数据库的变更历史。
从数据库(Slave) :从数据库通过复制主数据库的二进制日志来同步数据。从数据库可以处理读操作(SELECT),从而分担主数据库的负载。
MySQL 主从复制流程如下:
它的主要执行流程如下:
主数据库接收到一个写操作(如 INSERT、UPDATE、DELETE)时,会将这个操作记录到二进制日志(Binary Log)中,将数据修改的操作按顺序记录下来。
从数据库 IO 线程会自动连接主服务,从二进制中读取同步数据,记录到中继日志(Relay Log)中。
从数据库的 SQL 线程会定期从中继日志中获取同步数据,写入到从数据库中。
3.MySQL主从同步类型
MySQL 主从同步方式有以下三种:
3.1 异步复制
异步复制默认的主从同步复制模式,在这种模式下,主服务器提交事务后立即返回客户端,无需等待从服务器确认是否成功接收并应用了事务,从服务器会在后台独立地接收并应用事务日志。
异步同步流程如下(红色部分为主要执行流程):
优点
性能:异步复制模式下,主服务器的写操作不会因为等待从服务器的确认而被阻塞,因此可以提供更高的写入吞吐量。
简单:配置和管理相对简单。
成本:不需要额外的硬件资源支持,因为不需要高速的网络连接来保证同步。
缺点
数据丢失问题:在主服务器故障的情况下,可能存在数据未完全同步到从服务器的情况,导致数据丢失或不一致。
3.2 同步复制
同步复制是一种最为严格的复制模式,它要求主服务器在提交一个事务之前,必须等待所有从服务器确认确认接收到并应用了事务之后,主服务器才会向客户端返回事务提交成功的消息。
同步复制执行流程如下:
优点
数据一致性:提供了更高的数据一致性保障,因为主服务器必须等待从服务器确认才能完成事务提交。
容错性:即使主服务器发生故障,至少有一个从服务器拥有最新的数据,从而减少了数据丢失的风险。
缺点
性能开销大:主库需要等待所有从库的响应,这会导致事务提交的延迟增加,尤其是在从库数量较多或网络状况不佳时,性能下降明显。
单点故障风险:如果一个从库出现故障,可能会导致整个系统的阻塞,因为主库需要等待所有从库的确认。
3.3 半同步复制
半同步复制是一种折衷方案,它结合了异步复制的高性能和同步复制的高可靠性。在半同步复制模式下,主服务器在提交一个事务之前,需要等待至少一个从服务器确认接收到该事务的日志,但不需要等待从服务器完成应用。
半同步执行流程如下:
优点
数据一致性较好:相比异步复制,提供了更好的数据一致性保障。
性能影响较小:相比同步复制,半同步复制的性能开销较小,因为只需要等待一个从库的确认。
灵活性较高:可以根据需要调整等待的从服务器数量,以适应不同的性能和可靠性需求。
缺点
性能波动风险:在网络延迟较高或从库负载较大的情况下,可能会导致主库等待从库确认的时间过长,从而影响性能。
配置复杂:相比异步复制,配置和管理稍微复杂一些。
4.小结
因此,想要保证数据完全一致性需要使用同步复制,但这会牺牲一定的性能;因此在生产环境我们可以使用半同步保证较好的数据一致性即可;而默认的异步方式实现最简单、性能最好,但可能存在数据不一致的风险,虽然发生的概率极低(生产环境也可以使用)。
5.如何监控mysql主从的延迟呢
我们去判断一下主从是否延迟,如果发生延迟了,就等一会,如果数据已经同步了,那就直接查询就行了。判断是否发生主从延迟,一般来说可以通过两种方式。
5.1 seconds_behind_master
seconds_behind_master
参数是一个只读变量,用于表示从服务器(slave)相对于主服务器(master)的复制延迟时间。
这个参数反映了从服务器在复制过程中落后于主服务器的时间长度(以秒为单位)。
这个参数的取值如下:
正值:表示从服务器正在追赶主服务器的复制进度。具体的数值表示从属服务器的复制进程落后于主服务器的时间长度。例如,如果此值为 60 秒,那么意味着从服务器的复制操作比主服务器晚了 60 秒。
0:表示从属服务器与主服务器的复制同步是实时的,没有延迟。这意味着从属服务器已经完成了所有可用的复制事件,且没有新的事件等待应用。
NULL:
如果从服务器刚刚启动,还没有开始复制过程,那么此值可能是 NULL。
如果从服务器与主服务器之间的连接断开,或者从属服务器正在处理非复制任务(例如,正在进行表修复),也可能显示为 NULL。
如果从服务器已经追上了主服务器,并且没有新的事件需要复制,也会显示为 NULL。
要查看 seconds_behind_master
的值,我们可以使用以下 SQL 命令:
SHOW SLAVE STATUS\G;
输出中会有一行显示 Seconds_Behind_Master
,这就是你要找的信息。
利用 seconds_behind_master
参数,我们可以监控复制延迟,管理员可以据此了解从服务器的复制进度,并确定是否存在复制延迟问题。
在 MySQL8.0 之后的版本中,
seconds_behind_master
被替换为replication_lag
,但这两个参数的功能是一样的。
5.2 GTID
GTID 是 MySQL5.6 引入的一个特性,用于跟踪事务在主服务器上的执行情况,并确保这些事务按顺序在从服务器上重现。使用 GTID 进行主从复制可以简化管理和监控,特别是在有多个从服务器或复杂的复制拓扑中。
下面松哥给大家简单演示下如何利用 GTID 判断 MySQL 主从复制是否发生延迟。
步骤 1:确认主服务器和从服务器都启用了 GTID
确保主服务器和从服务器都配置了 GTID。需要在 MySQL 的配置文件(如 my.cnf
或 my.ini
)中设置 server-id
和 gtid_mode
。
ini 代码解读 复制代码 [mysqld] server-id = 1 # 主服务器的 server-id gtid_mode = ON # 启用 GTID
[mysqld] server-id = 2 # 从服务器的 server-id gtid_mode = ON # 启用 GTID
步骤 2:检查 GTID 执行状态
可以使用 SHOW MASTER STATUS
和 SHOW SLAVE STATUS
命令来检查主服务器和从服务器的 GTID 状态。
在主服务器上
SHOW MASTER STATUS;
这里多说一句,从 MySQL8.4 开始,不再使用
SHOW MASTER STATUS;
,取而代之的是SHOW BINARY LOG STATUS
。
输出将包括当前的 GTID 执行位置,如下所示:
File: mysql-bin.000001 Position: 107 Binlog_Do_DB: Binlog_Ignore_DB: Executed_Gtid_Set: 11111111-1111-1111-1111-111111111111:1-100
这里 Executed_Gtid_Set
显示了主服务器已经执行的所有 GTID 的集合。
在从服务器上
SHOW SLAVE STATUS\G;
输出将包括从服务器的 GTID 执行位置,如下所示:
yaml ... Master_Host: master.example.com Master_User: replication Master_Port: 3306 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 107 Relay_Master_Log_File: mysql-bin.000001 ... Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 107 Auto_Position: 1 ...
其中 Auto_Position
的值为 1 表示从服务器正在使用 GTID 进行复制。
步骤 3:比较 GTID 集合
比较主服务器和从服务器的 Executed_Gtid_Set
。如果两者相同,则表示复制没有延迟;如果有差异,则表示存在延迟。
步骤 4:分析 GTID 集合差异
如果发现 GTID 集合之间存在差异,可以通过以下命令查看具体的 GTID:
SELECT @@gtid_executed;
通过比较主从上两个命令执行的结果,就可以知道是否发生了延迟。如果发生了延迟,我们就停一会再去读。