浅语 發表於 2025-8-9 11:16:00

MySQL 25 MySQL是怎么保证高可用的?

<p>正常情况下,只要主库执行更新生成的所有binlog,都可以被传到备库并被正确地执行,备库就能达到跟主库一致的状态,这就是最终一致性,而MySQL要提供的高可用能力,只有最终一致性是不够的。</p>
<h3 id="主备延迟">主备延迟</h3>
<p>主备切换可能是一个主动运维动作,比如软件升级、主库所在机器按计划下线等,也可能是被动操作,比如主库所在机器掉电。</p>
<p>先看主动切换的场景。首先介绍同步延迟的概念,与数据同步有关的时间点主要包括三个:</p>
<ul>
<li>
<p>主库A执行完成一个事务写入binlog,将这个时刻记为T1;</p>
</li>
<li>
<p>之后传给备库B,把备库B接收完这个binlog的时刻记为T2;</p>
</li>
<li>
<p>备库B执行完这个事务,将这个时刻记为T3。</p>
</li>
</ul>
<p>主备延迟指的是,同一个事务主备库执行完成的时间差,即T3-T1。</p>
<p>可以在备库上执行<code>show slave status</code>命令,其返回结果里会显示seconds_behind_master,这个值计算的就是T3-T1。</p>
<p>如果主备库机器的系统时间设置不一致,会不会导致主备延迟的值不准呢?答案是不会的,备库连接到主库的时候,会通过执行SELECT UXIN_TIMESTAMP()函数来获得当前主库的系统时间,如果此时发现两库系统时间不一致,备库执行seconds_behind_master计算时会扣除该差值。</p>
<p>网络正常时,T2-T1是很短的,主备延迟的主要来源是备库接收完binlog和执行完这个事务之间的时间差。所以,主备延迟最直接的表现是,备库消费中转日志(relay log)的速度,比主库生产binlog的速度要慢。</p>
<h3 id="主备延迟的来源">主备延迟的来源</h3>
<p>首先,有些部署条件下备库所在机器性能要比主库所在的机器性能差。</p>
<p>有些人部署时想着反正备库没有请求,可以用差一点的机器,但实际上更新过程也会触发大量读操作,当备库主机上的多个备库都在争抢资源时,就可能导致主备延迟。</p>
<p>现在这种部署比较少了,因为主备可能随时切换,所以主备库一般选用相同规格的机器,并且做对称部署。</p>
<p>第二,备库的压力大。</p>
<p>备库一般用来提供一些读能力,如果大量查询,备库上的查询可能耗费大量CPU资源,影响同步速度,造成主备延迟。</p>
<p>这种情况一般的处理方法:</p>
<ul>
<li>
<p>一主多从,让多个从库分担读的压力;</p>
</li>
<li>
<p>通过binlog输出到外部系统,比如Hadoop,让外部系统提供统计类查询能力。</p>
</li>
</ul>
<p>第三是大事务。</p>
<p>主库上必须等事务执行完才会写入binlog再传给备库。那么,如果一个主库上的语句执行10分钟,意味着这个事务可能会导致从库延迟10分钟。常见的大事务有一次性用delete删除大量数据、大表DDL等。</p>
<p>第四是备库的并行复制能力,这个下篇文章再介绍。</p>
<p>由于主备延迟的存在,所以在主备切换的时候,就相应的有不同的策略。</p>
<h3 id="可靠性优先策略">可靠性优先策略</h3>
<p>上篇文章提到的双M结构:</p>
<div align="center"><img src="https://img2024.cnblogs.com/blog/3389949/202508/3389949-20250802123855096-1082725267.png" width="50%"></div>
<p>双M结构下,状态1切换到状态2的详细过程:</p>
<ul>
<li>
<p>判断备库B现在的seconds_behind_master,如果小于某个值(如5秒)继续下一步,否则持续重试这一步;</p>
</li>
<li>
<p>将主库A改成只读状态;</p>
</li>
<li>
<p>判断备库B的seconds_behind_master,直到这个值变成0;</p>
</li>
<li>
<p>将备库B改成可读写状态;</p>
</li>
<li>
<p>把业务请求切换到备库B。</p>
</li>
</ul>
<p>我们暂时把这个切换流程称为可靠性优先流程。</p>
<p>可以发现,这个切换流程中,在步骤2之后,主备库都处于readonly状态,即系统处于不可写状态,直到步骤5完成后才能恢复。在这个不可用状态中,步骤3比较耗时,这也是为什么在步骤1先确保seconds_behind_master足够小,不然不可用时间可能会很长。</p>
<p>系统的不可用时间,是由数据可靠性优先的策略决定的。也可以选择可用性优先的策略,把这个不可用的时间几乎降为0。</p>
<h3 id="可用性优先策略">可用性优先策略</h3>
<p>如果强行把步骤45调整到最开始执行,即不等主备数据同步,直接把连接切到备库B且让备库B可以读写,那么系统几乎就没有不可用时间了。</p>
<p>暂时把这个切换流程称为可用性优先流程,该切换流程的代价是可能出现数据不一致的情况。</p>
<p>假设有一个表t:</p>
<pre><code class="language-sql">mysql&gt; CREATE TABLE `t` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`c` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;

insert into t(c) values(1),(2),(3);
</code></pre>
<p>初始化数据后,主备库上都是3行数据,继续插入:</p>
<pre><code class="language-sql">insert into t(c) values(4);
insert into t(c) values(5);
</code></pre>
<p>假设现在主库上其他的数据表有大量的更新,导致主备延迟达到5秒,在插入一条<code>c=4</code>的语句后,发起了主备切换。</p>
<p>当使用可用性优先策略,且<code>binlog_format=mixed</code>时切换流程如下:</p>
<div align="center"><img src="https://img2024.cnblogs.com/blog/3389949/202508/3389949-20250802123927093-497990738.png" width="50%"></div>
<p>图中的SBM,是seconds_behind_master参数的简写。</p>
<ul>
<li>
<p>step 2中,主库A执行完insert插入(4,4),之后开始进行主备切换;</p>
</li>
<li>
<p>step 3中,由于主备之间有5秒延迟,所以备库B还没来得及应用插入<code>c=4</code>中转日志,就开始接收客户端插入<code>c=5</code>的命令;</p>
</li>
<li>
<p>step 4中,备库B插入一行数据(4,5),并把这个binlog发给主库A;</p>
</li>
<li>
<p>step 5中,备库B执行插入<code>c=4</code>的日志,插入一行数据(5,4),而前面的语句传到主库A,会在主库插入(5,5)。</p>
</li>
</ul>
<p>因此最后出现主备不一致的情况。</p>
<p>当使用可用性优先策略,且<code>binlog_format=row</code>时切换流程如下:</p>
<div align="center"><img src="https://img2024.cnblogs.com/blog/3389949/202508/3389949-20250802123956791-745790803.png" width="50%"></div>
<p>由于row格式在记录binlog时会记录新插入的行的所有字段值,所以最后只会有一行不一致,且两边的主备同步的应用线程会报错duplicate key error并停止。即备库B的(5,4)和主库A的(5,5)两行数据都不会被对方执行。</p>
<p>从上面的分析中,可以看到一些结论:</p>
<ul>
<li>
<p>使用row格式的binlog时,数据不一致问题更容易被发现,而使用mixed或者statement格式的binlog,可能数据不一致而没有发现;</p>
</li>
<li>
<p>主备切换的可用性优先策略会导致数据不一致,因此大多数情况都建议<strong>使用可靠性优先策略</strong>。</p>
</li>
</ul>
<p>但<strong>也有情况数据的可用性优先级更高</strong>。比如一个库的作用是记录操作日志,这时如果数据不一致可以通过binlog来修补,短暂的不一致不会引发业务问题,而业务系统又依赖这个日志,如果这个库不可写会导致线上的业务操作无法执行。这时就需要先强行切换,事后再补数据的策略。</p>
<p>当然也能改进,比如让业务逻辑不要依赖于这类日志的写入,那就又可以使用可靠性优先策略。</p>
<p>最后总结:在满足数据可靠性的前提下,MySQL高可用系统的可用性,是依赖于主备延迟的。延迟的时间越小,在主库故障的时候,服务恢复需要的时间就越短,可用性就越高。</p><br><br>
来源:https://www.cnblogs.com/san-mu/p/19018694
頁: [1]
查看完整版本: MySQL 25 MySQL是怎么保证高可用的?