主从复制系列C
近日接到一个故障,主从异步方式,主 crash后,从不可用,检查发现从机Read_Master_Log_Pos与Exec_Master_Log_Pos不一致,似乎还有binlog在回放中,HA在等回放结束,一直保持这个状态。难道从机也出故障了?根本原因是什么?且看下文。
MySQL binlog简介
首先简单了解要下binlog日志,Binary Log是在MySQL3.23.14中引入的,记录MySQL数据修改记录的文件集合。
Binary Log有两个目的:
用于复制。master(主)上的binlog日志发送到slave(从)上,slave执行回放master上的修改动作,保持主从数据一致。
用于数据恢复。对binlog日志文件指定始末位置执行即恢复指定数据。
本文是针对复制流程中的一个改进,不涉及数据恢复。
基于binlog的复制简介
Master上对修改动作生成binlog,Slave机IO拉取对应的binlog到本地生成relay log,然后Slave机SQL线程回放执行。binlog的最小单位为event,master与slave之间以event为单位传输日志,一个或多个event组成一个事务,slave机上以事务为单位回放日志。事务是数据库的常见基本特性,不再介绍,这里主要介绍下binlog中的event。
事务event包含header 和data,Header包含有event的类型,时间,哪个server产生等信息。data有对应类型event的细节,如特定的数据变化。
每个binlog第一个event是描述性event,描述当前文件的格式版本,最后一个event是一个log-rotation event用来指定下一个binary log的文件名。中间的则为常规event,描述各种操作,从event类型上就能比较直观看出event内容,如:XID_EVENT、WRITE_ROWS_EVENT、UPDATE_ROWS_EVENT、DELETE_ROWS_EVENT等。
一个示例如下:
这是GTID模式下,建表和插入数据等events示例。第一个是固定的当前文件头信息,第二个Previous_gtids说明是GTID日志模式,接下来的Gtid event是GTID模式下每个事务的头信息,通过这个不重复且递增的GTID号来保证数据的连续性,一致性,然后是建表并插入数据相关event。
异步复制模式的不足
上面可以看到,binlog中非常清析的记录了所有动作,正常情况下,slave机只要按这顺序执行完成,就能保证主从数据一致。但事务当提交成功后才发日志给slave机,当master出现故障时,slave机收到的日志不一定是完整的,这时没办法完全保证主从数据完全一致,这是异步模式天生的不足,是否有好的解决办法本文不深入,本文要讨论的是当此类故障出现时如何保证外部业务可用的问题。
假如master机掉电了或crash了或操作系统崩溃了,无法恢复使用,此时怎么恢复?先看如下简图:

当master出现问题时,业务将不可用,slave机接收不到binlog,IO线程会处于连接中,HA控制中心确认状态后,会自动把应用流量切到slave机,恢复业务。但是有些情况下,HA控制中心是没办法自我恢复的。如:master在commit之后,开始给slave机传输binlog时,但又没传完,此时master 出现故障,HA需要切换流量到slave,但在切换流量之前,会先等slave机上已经读到的binlog回放完毕。问题就在这里,请看我上面第二节基于binlog的复制简介中加粗字体event为单位和事务为单位,在slave机有Exec_Master_Log_Pos记录当前已经执行完成的以事务为单位的日志位置,有Read_Master_Log_Pos记录前已经拉取过来的以event为单位日志位置,当Read_Master_Log_Pos读位置与Exec_Master_Log_Pos执行位置相等就说明slave机上日志已经回放完毕,如果IO线程拉取一个事务的部分event,此时master出现故障不能恢复,slave机会一直等待,此时Read_Master_Log_Pos读位置与Exec_Master_Log_Pos执行位置不一致,HA中心会认为还有日志没回放完,一直等待,正是这个原因造成了本文开头的HA切换不成功故障。
HA为什么要等Read_Master_Log_Pos与Exec_Master_Log_Pos一致?虽然异步模式不能完全保证数据不丢失,但要尽量减小丢失。在master并发很大的场景下,主从数据延迟可能会是几十分钟甚至更久,必须要把已经拉取日志回放完毕,减少数据丢失。当出现拉取到不完整事务时,对slave来说是正常状态,可能是网络或其它原因,尝试恢复拉取即可,如果和master通讯恢复正常,slave机是能正常拉取到完整事务的,因此不完整事务状态对slave机说是正常状态。如果master已经不可用,slave机又没拉取完全部事务,Read_Master_Log_Pos与Exec_Master_Log_Pos不一致,HA中心认为回放不完整,不能切换,一直等待。此时甚至DBA上去查看也不好确认slave机状态,如slave机正在回放一个超大事务,需要很长时间,期间master出现故障不可用,此时Read_Master_Log_Pos与Exec_Master_Log_Pos不一致,所有状态在回放过程中不发生改变,无法确定slave机真实状态。
那么当master不可用了,slave机又没拉取完整事务时怎么办?人工检查slave机状态,对比Read_Master_Log_Pos与Exec_Master_Log_Pos,等待一段时间再比较,如果多次比较Exec_Master_Log_Pos没有变化,并且与Read_Master_Log_Pos相差并不大,可以认为已经读取到的日志已经回放完毕,可以把流量切换过来。实际上这不是非常稳妥的方案,操作也需要人工持续观察来做出判断再处理,步骤繁琐,维护成本高,对于云服务厂商,十万甚至百万级别的实例,单点偶尔发小概率事件可能会变成易现大概率事件,需要有更好的处理手段。
Read_Master_Log_Pos更新时机探讨
出现Exec_Master_Log_Pos和Read_Master_Log_Pos不一致的根本原因就在于两个更新时机不一样,一个事务回放结束才更新,一个拉取到event即更新。对于slave机来说,Exec_Master_Log_Pos要等一个事务的全部event拉取过来并且被sql线程回放成功才能更新,但Read_Master_Log_Pos只要有binlog的event被IO线程拉取过来就会改变。而sql回放线程是根据event中标记事务结束或开始的状态对之前事务进行回放,Read_Master_Log_Pos 记录的是当前已经拉取过来的位置,并不影响回放线程。因此可以把Read_Master_Log_Pos更新时机调整到读到完整事务之后再更新,与Exec_Master_Log_Pos更新逻辑保持一致,这样Read_Master_Log_Pos标记的位置就是肯定可以回放的完整事务的位置,不会出现之前那样不完整事务位置造成无法判断真实状态的情况。两种更新方式对比见下图:

当以事务为单位更新Read_Master_Log_Pos 后,无论master什么时机点crash,slave机上Exec_Master_Log_Pos最终都能追上Read_Master_Log_Pos。对于已经被slave机拉取过来的最后一个不完整事务的event,处理逻辑也原来一致,不会继续执行。但HA控制中心已经可以根据各个状态自动做出正确处理的,把流量切入从机,判断逻辑也与原来一样,Read_Master_Log_Pos 与Exec_Master_Log_Pos保持相等即可切换,因为现在任何情况下都成达成这个条件。
修改Read_Master_Log_Pos更新位置注意点
原先逻辑,slave机IO线程并不需要过多解析event,基本上只要确定长度就可,具体内容在sql线程回放时再解析。现在则要在IO线程中确定每个event类型,判断是否是事务结束的event,需要对event做一些解析工作。要修改的点并不多,注意GTID和非GTID区别,考虑row模式和statement差异,对不同情况下事务开始和结束标记理清,在queue_event函数增加处理逻辑即可。
主从复制系列C的更多相关文章
- 主从复制系列A
一.主从原理 Replication 线程 Mysql的 Replication 是一个异步的复制过程,从一个 Mysql instace(我们称之为 Master)复制到另一个 Mysql in ...
- 主从复制系列B
从服务器靠中继日志来接收从主服务器上传回来的日志.并依靠状态文件来记录已经从主服务器接收了哪些日志,已经恢复了哪些日志. 中继日志与二进制日志的格式相同,并且可以用mysqlbinlog读取.SQL线 ...
- MySQL 系列(四)主从复制、备份恢复方案生产环境实战
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- solr与.net系列课程(七)solr主从复制
solr与.net系列课程(七)solr主从复制 既然solr是解决大量数据全文索引的方案,由于高并发的问题,我们就要考虑solr的负载均衡了,solr提供非常简单的主从复制的配置方法,那么下面 ...
- Redis系列(四):Redis的复制机制(主从复制)
本篇博客是Redis系列的第4篇,主要讲解下Redis的主从复制机制. 本系列的前3篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安装 Redis系列(二):Redis的5种数据 ...
- Mongodb数据库学习系列————(一)Mongodb数据库主从复制的搭建
Mongodb数据库主从复制的搭建 Writeby:lipeng date:2014-10-22 最近项目上用到了位置查询,在网上 ...
- 【FAQ系列】关于SQL_Errno:1677导致主从复制中断的思考和实践
1.简单介绍该错误发生的背景: 1) 数据库版本:MySQL5.7.19 2) 对一个大表修改字段类型DDL(将主键id int变为bigint),为了不影响主库业务,先在从库上执行DDL操作,然后通 ...
- Redis系列八:redis主从复制和哨兵
一.Redis主从复制 主从复制:主节点负责写数据,从节点负责读数据,主节点定期把数据同步到从节点保证数据的一致性 1. 主从复制的相关操作 a,配置主从复制方式一.新增redis6380.conf, ...
- MySQL系列详解六:MySQL主从复制/半同步演示-技术流ken
前言 随着技术的发展,在实际的生产环境中,由单台MySQL数据库服务器不能满足实际的需求.此时数据库集群就很好的解决了这个问题了.采用MySQL分布式集群,能够搭建一个高并发.负载均衡的集群服务器.在 ...
随机推荐
- PSCC2019常用基础操作
一.常用设置 1.界面设置(快捷键Ctrl+K):可以对PS界面的颜色.导出格式.性能等等进行设置(这里暂存盘建议设置D盘或F盘,默认C盘). 2.常用面板整理(菜单栏->窗口) 二.常用快捷键 ...
- BZOJ 1087(SCOI 2005) 互不侵犯
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MB Submit: 5333 Solved: 3101 [Submit][ ...
- DP杂题2
1.邦邦的大合唱站队 https://www.luogu.org/problem/show?pid=3694 XY说这是道简单的签到题,然后我大概是普及组都拿不到三等的那种了.. 插入题解.写得太好了 ...
- LOJ#6437. 「PKUSC2018」PKUSC
题面 题意转化为: 判断每个点所在的圆有多长的弧度角位于多边形内部. 然后就很暴力了. 每个点P,直接找到多边形和这个圆的所有交点,按照距离P的角度排序. 找交点,直接联立二元二次方程组.... 需要 ...
- 通过apiservice反向代理访问service
第一种:NodePort类型 type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30008 第二种:ClusterIP类型 typ ...
- 深入分析Service启动、绑定过程
Service是Android中一个重要的组件,它没有用户界面,可以运行在后太做一些耗时操作.Service可以被其他组件启动,甚至当用户切换到其他应用时,它仍然可以在后台保存运行.Service 是 ...
- 如何快速合并多个TXT文本内容
工作中有时候需要合并很多文本内容,例如一些推送清单之类,一个一个打开去复制粘贴的话,少量还行,如果txt文本数据量大(10+M以上)且文件数量多(成百上千),这种方式就显得很低效了.具体要求如下: ...
- SpringCloud之Fegin学习笔记
以下部分内容来源于网络摘抄~ 1.作用 Feign 是一种声明式.模板化的 HTTP 客户端.在 Spring Cloud 中使用 Feign,可以做到使用 HTTP 请求访问远程服务,就像调用本地方 ...
- 【转载】TCP演进简述
TCP演进简述 http://www.cnblogs.com/fll/ 一.互联网概述 TCP,即传输控制协议,是目前网络上使用的最多的传输协议,我们知道,整个互联网的体系结构是以IP协议提供的无连接 ...
- thinkPHP 字段映射功能
thinkPHP的字段映射功能可以让你在表单中隐藏真正的数据表字段,而不用担心放弃自动创建表单对象的功能,假设我们的User表里面有username和email字段,我们需要映射成另外的字段,定义方式 ...