大家好,我是悟空。本文主要内容如下:一、背景为了保证高可用,之前在测试环境部署了一套MySQL双主模式。当一个主库服务出现异常时,可以将流量切换到另一个主库。相互同步数据。双主模式双主模式示意图如下:但是经常会出现数据冲突,所以我们将双主模式改为主从读写分离模式。主库作为读写库,加上从库用于I/O密集型任务(比如大量的数据统计操作)。如下图所示:另外,从库复制的方式采用location方式:指定binlog文件和binlog位置,让从库知道复制的起始位置。(下面会解释这个方法)虽然改成了主从模式,但是还是遇到了一些问题:问题1:从B库复制数据时,出现主键冲突,导致同步失败,slave库停止复制。猜测是因为主库配置的binlog日志格式混杂,导致从库同步时出现不一致。问题2:从库B停止复制后,大量数据没有同步到从库,主从之间出现大量数据不一致。问题三:如果要从B库恢复复制,必须先解决同步失败的问题才能恢复。调查是困难和耗时的。问题4:从B库恢复时,必须知道同步点,即从哪个binlog文件和binlog位置断开复制,即使找到了也不准确。问题5:从B从库同步异常停止复制到恢复复制期间,A主库自动清理了前几天的binlog日志,这些日志还没有从A库同步过来从库B,导致又一次同步失败。问题六:主从之间存在同步延迟。在本文中,我们讨论问题4和6。其中,问题4是一个比较麻烦的问题。我们一般通过查看B库当前的同步状态来获取同步点,然后设置同步点。但是重启同步后,又会出现同步异常。例如,从库B中可能会出现Duplicateentry'id_of_R'forkey'PRIMARY'错误,说明发生了主键冲突,然后停止同步。为了降低站点同步引入的复杂性,我们切换到GTID模式。对于问题6,本文也仅限于讨论如何观察延迟,如何降低延迟不在本文讨论范围之内。接下来我们展开看看站点同步的痛点。2.站点同步痛点2.1站点同步示意图为了更清楚的理解主从站点同步的原理,这里给出一张示意图:1.主库会生成多个binlog日志文件。2.从库的I/O线程请求指定文件和指定位置的binlog日志文件(location)。3、主库dump线程获取指定位置的binlog日志。4、主库根据从库发送的位置信息读取binlog,然后将binlog推送到从库。5.将从库获取的binlog写入本地中继日志(relaylog)文件。6.从库的SQL线程读取并解析中继日志文件。7.从库的SQL线程重播中继日志中的命令。当我们使用站点同步的方式时,两种场景的操作步骤都比较复杂。2.2痛点痛点一:首次开启主从复制步骤复杂。首次开启主从同步时,要求从库和主库保持一致。找到主库的binlog位置。设置从库的binlog位置。从库中启动复制线程。痛点二:恢复主从复制步骤复杂找到从库复制线程停止的点。解决复制异常的事务。如果无法解决,需要手动跳过指定类型的错误,比如设置slave_skip_errors=1032,1062。当然,这个前提是跳过这样的错误是无损的。(1062错误是插入数据时唯一键冲突;1032错误是删除数据时找不到该行)是否需要在第一次开启同步时查找并设置点,或者当恢复主从复制,设置点和忽略错误,这些步骤过于复杂和容易出错。于是MySQL5.6版本引入了GTID,彻底解决了这个难点。3.GTID方案3.1什么是GTID?GTID的全称是GlobalTransactionIdentifier,全局事务ID。当一个事务被提交时,会产生一个GTID,相当于事务的唯一标识。GTID如下所示:c5d74746-d7ec-11ec-bf8f-0242ac110002:1结构:GTID=server_uuid:gnoserver_uuid在实例首次启动时自动生成,全局唯一值;gno是一个整数,初始值为1,每次事务提交时分配给这个事务,并加1。每个MySQL实例维护一个GTID集合,用来对应“本实例执行的所有事务”。3.2GTID的优点更容易实现failover,不需要像以前那样找位置(log_file和log_pos)。更容易构建主从复制。比传统复制更安全。GTID连续无漏洞,保证数据一致性和零丢失。3.3如何启用GTID修改主从库配置文件:#GTID:gtid_mode=onenforce_gtid_cnotallow=on从库配置同步参数:CHANGEMASTERTOMASTER_HOST=$host_nameMASTER_PORT=$portMASTER_USER=$user_nameMASTER_PASSWORD=$passwordmaster_auto_positinotallow=1其中master_auto_position标识主从关系使用的GTID协议。与之前的配置相比,不再需要MASTER_LOG_FILE和MASTER_LOG_POS参数。3.4GTID同步方案GTID同步示意图。GTID方案:主库计算主库的GTID集合和从库的GTID集合的差异,主库将差异集合的binlog推送到从库。从库设置同步参数后,主库A的GTID集合记为集合x,从库B的GTID集合记为y。从库同步逻辑如下:从库B指定主库A,根据主备协议恢复连接。从库B将集合y发送给主库A,主库A计算集合x和集合y的差集,即集合x存在,集合y不存在的GTID集合。例如集合x为1~100,集合y为1~90,则相差91~100。这里会判断集合x是否包含集合y的所有GTID。如果没有,说明主库A删除了从库B需要的binlog,主库A直接返回错误。主库A从自己的binlog文件中找到第一个不在集合y中的事务GTID,即找到91。主库A从GTID=91的事务开始,后面读取binlog文件,取出binlog按顺序发送给B。从B库的I/O线程读取binlog文件生成relaylog,SQL线程解析relaylog,然后执行SQL语句。GTID同步方案和location同步方案的区别在于location同步方案是手动指定从库上的哪个location,主库会发送那个location,而不做日志完整性判断。GTID方案通过主数据库自动计算位置,无需手动设置位置,对运维人员友好。4、如何判断主从库是否有延迟。上述问题6是主从读写分离后,从库的复制存在延迟。下面我们来讨论一下如何观察主从的延时。解决方案一:判断从库的同步状态参数seconds_behind_master是否为0。(不准确)解决方案二:对比站点,保证主备之间没有延迟。解决方案三:比较GTID集,确保主备之间没有延迟。方案一:查看seconds_behind_master可以在从库上执行slowslavestatus命令,查看执行结果中seconds_behind_master参数的值。如下图,Seconds_Behind_Master等于0,Seconds_Behind_Master的单位是秒,所以精度不准确。所以,为了保证查询到的数据与主库一致,需要先判断seconds_behind_master是否等于0,如果不等于0,则必须等到该参数变为0后,再执行查询请求。方案二:对比站点可以查看从库当前同步站点,确认从库同步是否有延迟。下图是对从库执行showslavestatus\G命令的结果:Master_Log_File和Read_Master_Log_Pos这两个参数一起表示主库读取的最新位置,第一个参数代表读取了哪个文件,第二个是读取文件的位置。Relay_Master_Log_File和Exec_Master_Log_Pos,这两个参数一起表示从库执行的最新位置。如果红色框内的两个参数:Master_Log_File和Relay_Master_Log_File相等,则说明从库中读取的最新文件与主库上生成的文件相同,这里都是mysql-bin.000934。如果蓝框里的Read_Master_Log_Pos和Exec_Master_Log_Pos这两个参数相等,说明从库读取的日志文件位置和从库执行的日志文件位置相同,这里都是59521082。当以上两组参数相等,说明没有延迟。选项3:比较GTID集合选项3是比较GTID集合。首先我们在从库上执行showslavestatus\G查看GTID集合。如下图所示:Master_UUID表示当前连接的主库ID。Auto_Position:1表示master和slave使用GTID协议。Retrieved_Gtid_Set表示从库中接收到的所有日志的GTID集合。Executed_Gtid_Set表示已从库中执行的GTID集。如果Executed_Gtid_Set集合中包含Retrieved_Gtid_Set,则表示从库接收的日志已经同步。比如上图中Retrieved_Gtid_Set的值为c5d74746-d7ec-11ec-bf8f-0242ac110002:1-87323。前半部分是主库id,后半部分是1-87383是GTID范围。Executed_Gtid_Set的值有两组7083ae1f-d7ef-11ec-a329-0242ac110002:1-2,c5d74746-d7ec-11ec-bf8f-0242ac110002:1-87323第二组Executed_Gtid_Set和第一组完全一样,第一个collectionid和collectionrange是另外一个主库上次同步的记录。这说明从库已经和当前的主库同步了。方案二的对比站点和方案三的GTID对齐都比方案一的seconds_behind_master更准确。但是还是没有达到精准的程度,需要配合半同步复制来实现。总结:本文通过GTID更好的实现了主从节点的同步,以及如何观察主从同步的延迟。参考资料:www.passjava.cnhttps://time.geekbang.org/column/article/77636高性能MySQL第四版千金秘方:MySQL性能优化金字塔讲述我8年互联网开发经验,擅长微博服务、布局方式、结构设计。目前在一家大型上市公司从事基础设施和性能优化工作。InfoQ签约作者,蓝桥签约作者,阿里云专家博主,名人。
