mysql复制简单介绍了mysql semi-sync的出现的原因,并说明了semi-sync如何保证不丢数据。这篇文章主要侧重于semi-sync的实现,结合源码将semi-sync的实现过程展现给大家。最新的semi-sync源码可以参考官方5.7版本的实现,https://github.com/mysql/mysql-server

打开semi-sync的正确姿势
     默认情况下的mysql复制都是异步复制,mysql通过参数来控制semi-sync开关。具体而言,主库上通过rpl_semi_sync_master_enabled参数控制,备库上通过rpl_semi_sync_slave_enabled参数控制,打开这两个参数后,mysql semi-sync的特性就打开了。注意对于备库而言,为了保证半同步立即生效,需要重启slave的IO线程。另外,还有一个比较重要的参数是rpl_semi_sync_master_timeout,这个参数用于控制master等待semi-slave ack报文的时间,单位是毫秒,默认是10000。master等待超时,则切换为普通的异步复制。

master:
set global rpl_semi_sync_master_enabled=1;
set global rpl_semi_sync_master_timeout=xxx; slave:
stop slave io_thread;
set global rpl_semi_sync_slave_enabled=1;
start slave io_thread;

另外需要注意的是,打开了上述两个参数只说明master-slave已经具备打开semi-sync的基本条件了,但复制是否依照半同步运行,还需要根据Rpl_semi_sync_master_status的状态值确定。因为比如slave较master有很大延迟(超过rpl_semi_sync_master_timeout),那么复制切换为普通复制。对于需要调试代码的童鞋而言,rpl_semi_sync_master_trace_level和rpl_semi_sync_slave_trace_level非常重要,通过设置level取值,可以打印日志记录半同步的详细过程,方便定位问题。

semi-sync的实现
semi-sync说到底也是一种复制,只不过是在普通的复制基础上,添加了一些步骤来实现。因此semi-sync并没有改变复制的基本框架,我们的讨论也从master,slave两方面展开。
1.master(主库)

主库上面主要包含三个部分,(1).负责与slave-io线程对接的binlog dump线程,将binlog发送到slave,(2).主库上写事务的工作线程,(3).收取semi-slave报文的ack_receiver线程。

(1).binlog dump流程
主要执行逻辑在mysql_binlog_send函数中。

1.判断slave是否是semi_slave,调用add_slave将semi-slave加入到ack_receiver线程的监听队列中。判断的逻辑是slave对应的会话上是否设置了参数rpl_semi_sync_slave。

2.根据slave的请求偏移和binlog文件,从指定位点读取binlog
3.根据文件和位点,捞binlog文件中的数据
4.调用updateSyncHeader设置数据包头semi-sync标记
根据实时semi-sync运行状态来确定是否设置(这个状态由ack_receiver线程根据是否及时收到slave-ack报文设置)
5.调用my_net_write发送binlog
6.调用net_flush确认网络包发送出去
如果当前所有产生的binlog已经处理完,需调用wait_for_update_bin_log等待binlog更新。

(2).半同步事务提交流程
mysql5.6以后提交采用组提交方式,主要分为三个阶段,每个阶段有一个队列,增加semi-sync后,又增加了一个semi-sync阶段。
1.flush阶段:
队列能保证写binlog的顺序与innodb-commit的顺序一致。通过队列,可以保证顺序写每个事务的binlog-cache,然后只进行一次write操作(flush_cache_to_file)。flush阶段后,如果sync_binlog不是1,则通知master有新binlog产生;如果sync_binlog为1,则等待sync阶段后,再通知dump线程有新binlog产生。这里我理解是因为如果不为1,则可能没有后续的sync阶段,而操作系统缓存也有binlog数据,所以可以在flush阶段后通知;而对于sync_binlog为1的情况,可以保证主库的binlog先落地,永远比备库多。但如果sync_binlog不为1,比如1000,则主机异常情况下,则可能出现备库的binlog比主库还多的情况。根据sync_binlog的设置,确认是否要跳过sync阶段。
2.sync阶段:
sync_binlog_file
3.semi_sync阶段:
call_after_sync,等待备库应答。调用cond_timewait等待条件变量&COND_binlog_send_,注意这里只是leader线程在等,将leader线程唤醒后,才会结束semi_sync阶段,进而唤醒其它的follower线程。
4.commit阶段:
innodb-commit
waitAfterCommit,等待备库应答。调用cond_timewait等待条件变量&COND_binlog_send_ 。最终我们根据semi-sync复制模式的设置(AFTER_COMMIT,AFTER_SYNC),来确定是第(3)步还是第(4)步进行等待。

(3).接收slave-ack报文流程
这个流程的工作主要在ack_receiver线程中,这个线程的主要作用是监听semi-slave的ack包,确认master-slave链路是否工作在半同步状态,并根据实际运行状态将普通复制与半同步复制进行切换。打开主库rpl_semi_sync_master_enabled参数后,该线程启动,关闭参数后,该线程消亡。
流程如下:
1.遍历semi-slave数组
2.通过select函数监听每个slave是否有网络包过来
3.调用my_net_read读取包数据
4.调用reportReplyPacket处理semi-sync复制状态
若备库已经获取了最新的binlog位点,则唤醒等待的工作线程
5.调用reportReplyBinlog唤醒等待的线程,mysql_cond_broadcast(&COND_binlog_send_);

2.slave(备库)

主要实现在(handle_slave_io)
1.启动io-thread后,调用safe_connect建立与master的连接
2.调用request_dump函数处理请求binlog逻辑
(1).执行命令SET @rpl_semi_sync_slave= 1,设置一个局部变量,通过这个参数标记slave为semi-slave
(2).发送命令COM_BINLOG_DUMP请求日志
循环从master端收取日志,处理日志
{
  1.调用read_event,从master端收取日志(如果没有网络包,会阻塞等待)
  2.调用slaveReadSyncHeader,确定网络包头是否有semi-sync标记
  3.调用queue_event将日志写入relay-log,在这个过程中会过滤自身server-id的日志
  4.如果有semi-sync标记,调用slaveReply函数,发送ack报文
}

mysql半同步(semi-sync)源码实现的更多相关文章

  1. MySQL半同步复制源码解析

    今天 DBA 同事问了一个问题,MySQL在半同步复制的场景下,当关闭从节点时使得从节点的数量 < rpl_semi_sync_master_wait_for_slave_count时,show ...

  2. Mysql半同步复制模式说明及配置示例 - 运维小结

    MySQL主从复制包括异步模式.半同步模式.GTID模式以及多源复制模式,默认是异步模式 (如之前详细介绍的mysql主从复制).所谓异步模式指的是MySQL 主服务器上I/O thread 线程将二 ...

  3. mysql半同步复制问题排查

    1.问题背景      默认情况下,线上的mysql复制都是异步复制,因此在极端情况下,主备切换时,会有一定的概率备库比主库数据少,因此切换后,我们会通过工具进行回滚回补,确保数据不丢失.半同步复制则 ...

  4. 安装MySQL半同步复制

    一.简介 从MySQL5.5开始,MySQL以插件的形式支持半同步复制.如何理解半同步呢?首先我们来看看异步,全同步的概念 异步复制(Asynchronous replication) MySQL默认 ...

  5. MySQL半同步复制搭建

    默认情况下,MySQL 5.5/5.6/5.7和MariaDB 10.0/10.1的复制是异步的,异步复制可以提供最佳性能,主库把binlog日志发送给从库,这一动作就结束了,并不会验证从库是否接收完 ...

  6. mysql半同步复制跟无损半同步区别

    mysql半同步复制跟无损半同步复制的区别: 无损复制其实就是对semi sync增加了rpl_semi_sync_master_wait_point参数,来控制半同步模式下主库在返回给会话事务成功之 ...

  7. MySQL半同步复制

    从MySQL5.5开始,MySQL以插件的形式支持半同步复制.如何理解半同步呢?首先我们来看看异步,全同步的概念 异步复制(Asynchronous replication) MySQL默认的复制即是 ...

  8. MySQL半同步安装以及参数

    MySQL半同步安装以及参数 基于MySQL5.5 官档地址: Semisynchronous Replication Administrative Interface https://dev.mys ...

  9. MySQL 半同步重要状态参数说明

    如果配置了MySQL半同步复制,可以在主库查询半同步状态,命令为: SHOW GLOBAL STATUS LIKE '%semi%'; 参数说明      Rpl_semi_sync_master_c ...

  10. mysql半同步复制实现

    mysql半同步复制和异步复制的区别如上述架构图所看到的:在mysql异步复制的情况下.Mysql Master Server将自己的Binary Log通过复制线程传输出去以后,Mysql Mast ...

随机推荐

  1. Thinking in Unity3D:渲染管线中的Rendering Path

      关于<Thinking in Unity3D> 笔者在研究和使用Unity3D的过程中,获得了一些Unity3D方面的信息,同时也感叹Unity3D设计之精妙.不得不说,笔者最近几年的 ...

  2. 如何利用 Visual Studio 自定义项目或工程模板

    在开发项目的时候,由其是商业性质的大型项目时,往往需要在每个代码文件上都加上一段关于版权.开发人员的信息,并且名称空间上都需要带有公司的标志.这个时候,是选择在开发的时候手动添加还是自动生成呢? 我们 ...

  3. Redis集群搭建与简单使用

    介绍安装环境与版本 用两台虚拟机模拟6个节点,一台机器3个节点,创建出3 master.3 salve 环境. redis 采用 redis-3.2.4 版本. 两台虚拟机都是 CentOS ,一台 ...

  4. java运行时获得泛型类型

    引言 众所周知,java泛型最重要的特征是泛型擦除,所有泛型在编译时会转换成Object所以在java中运行时无法获得泛型的类型. 但是其实以上的规则是针对方法的内部变量的,如果是其他形式的泛型其实是 ...

  5. TODO:Github的使用技巧之同步代码

    TODO:Github的使用技巧之同步代码 GitHub 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub. GitHub 于 2008 年 ...

  6. Vue.js入门

    之前一直用的是jQuery,jQuery手动操作DOM导致性能不够好,因为DOM修改导致的页面重绘.重新排版!重新排版是用户阻塞的操作,同时,如果频繁重排,CPU使用率也会猛涨! Vue.js是数据驱 ...

  7. 图片放大功能插件及jquery.extend函数理解

    前端时间,产品提出社区评论中的图片需要有放大功能.感觉可以共用,所以就想整合一个插件,过程中也借鉴了一些例子. 分析下自己的代码思路: var scaleImg = function(opts) { ...

  8. Redis系列之key操作命令与Redis中的事务详解(六)

    序言 本篇主要目的有二: 1.展示所有数据类型中key的所有操作命令,以供大家学习,查阅,更深入的挖掘redis潜力. 2.掌握redis中的事务,让你的数据完整性一致性拥有更优的保障. redis命 ...

  9. Unity3D移动平台动态读取外部文件全解析

    前言: 一直有个想法,就是把工作中遇到的坑通过自己的深挖,总结成一套相同问题的解决方案供各位同行拍砖探讨.眼瞅着2015年第一个工作日就要来到了,小匹夫也休息的差不多了,寻思着也该写点东西活动活动大脑 ...

  10. 2.ASP.NET MVC 中使用Crystal Report水晶报表

    上一篇,介绍了怎么导出Excel文件,这篇文章介绍在ASP.NET MVC中使用水晶报表. 项目源码下载:https://github.com/caofangsheng93/CrystalReport ...