MySQL是一个RDBMS(关系型数据库管理系统),由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。由于其体积小、速度快、拥有成本低,尤其是开放源码这一特点,广受各大企业欢迎,包括腾讯,阿里,百度,网易,Google,FaceBook等互联网巨头企业。

随着互联网的高速发展,互联网服务可用性变得越发重要,数据容灾也随之成为各企业的关键任务。在数据容灾中,数据库集群如何处理数据一致性也成为了各企业需要解决的问题。特别在一些新兴的金融服务中,MySQL也逐渐成为其核心数据库,如何保证金钱的准确性则尤为重要。MySQL也从一开始的异步复制,到Google开发的半同步复制,到MySQL 5.7更新的lossless半同步复制,一直在优化集群的数据一致性问题。

虽然MySQL一直在优化数据的一致性问题,但问题依然存在,使得各大企业纷纷各自设计一套MySQL补丁来保证数据一致。腾讯数平的TDSQL,腾讯微信的PhxSQL,阿里的AliSQL,网易的InnoSQL等设计都是为了保证数据一致性。MySQL5.7发布的lossless半同步,虽然宣称zero loss,解决了5.6版本中有可能出现的data lost问题,但其数据一致性仍未完全解决。

MySQL半同步复制的问题

图1 MySql半同步流程

图1描述了MySQL的Binlog半同步过程。Wait ACK是半同步的关键步骤,Master把Binlog发给Slave之后,需要等待Slave的ACK。Master直到成功收到ACK之后,才执行Engine Commit把数据持久化到Storage。具体细节可参考:http://my-replication-life.blogspot.com/2013/09/loss-less-semi-synchronous-replication.html

MySQL启动时,Wait ACK过程会被跳过,导致Engine Commit会被直接执行。具体细节请参考:https://jira.mariadb.org/browse/MDEV-162

下面对MySQL的数据在Master和Slave之间是否能保证一致进行简单分析。讨论均基于各机器数据最终是否一致来展开。下面的分析只针对半同步复制,且假设半同步失败后不会退化成异步复制。

场景1:Master正常工作

Master的数据复制到Slave,Slave与Master保持数据一致。

场景2:Master Crash且不切换Master

场景2.1

Master已经收到ACK,并执行Engine Commit。Slave与Master保持数据一致。

场景2.2

Master处于Wait ACK阶段,存在PendingBinlog(未执行Engine Commit的Binlog)。

图2 Master重启时执行EngineCommit,并把Binlog重新复制给Slave

Master重启时执行EngineCommit。Slave重新连接Master,Binlog重新开始复制,随后Slave数据和Master一致。如图2。

因此,在MySql5.7的情况下,场景2.2能保证Master和Slave之间的数据一致性。但是在MySQL5.6及之前的版本,场景2.2是不能保证数据一致性的,具体请参考:http://my-replication-life.blogspot.com/2013/09/loss-less-semi-synchronous-replication.html

场景3:Master Crash且切换Master

场景3.1

旧Master Crash时,已经收到至少一台Slave的ACK并执行Engine Commit。

数据已复制到至少一台Slave,该Slave与旧Master的数据保持一致。

场景3.2

旧Master处于Wait ACK阶段时Crash,新Master被切换到了一台拥有最新Binlog的Slave。

场景3.2中,旧Master中的PendingBinlog存在两种场景。

场景3.2.1

旧Master Crash时Binlog发送失败,未复制给任何Slave。

图3 机器A重启Commit Transaction X。机器A/B数据不一致。

图4 机器B接收到事务X的重试请求(事务X’)且复制到机器A。

机器A/B数据可能不一致。

假设机器A为旧Master,执行事务X时,复制失败并Crash。随后机器B成为新Master。机器A重启时执行Engine Commit,事务X被Commit。此时机器A和机器B的数据一致性被破坏。两台机器上数据可能不一致。如图3,图4。

数据不一致的原因是机器A在重启时对PendingBinlog执行Engine Commit。在切换了Master的情况下,只能通过回滚PendingBinlog解决。

场景3.2.2

旧Master Crash时Binlog发送成功,但还未执行Engine Commit。

图6 机器A重启马上执行Engine Commit,数据一致

假设机器A为旧Master,执行事务X时在执行Commit前Crash,但机器B收到事务X。随后机器B成为新Master。

机器A重启时对PendingBinlog执行Engine Commit,执行成功后机器A的数据是机器B的子集。此时机器A可从机器B中拉取最新的数据。另外一台Slave机器C可以从这两台机器中任意拉取。

从图6可以看出,机器A在出现故障时,由于TransactionX已经复制给其中一台Slave和重启时立刻Commit Transaction X,使得该Slave和Master的数据能保证一致。

图7 两台机器出现故障,Master切换可能会丢失数据

上述讨论都是基于拥有最新数据的Slave和Master不能一起出现故障。当这两台机器一起出现故障时,进行Master切换则会造成数据丢失。如图7。

对于较小的集群(机器数目小于或者等于3),当出现两台机器一起发生故障时,可认为集群已无法提供服务(半同步复制无法工作)。

对于较大的集群(机器数目大于3),当出现两台机器一起发生故障,且无法得知该两台机器的数据状态时,该集群也无法提供服务(无法确认拥有最新数据的Slave是否包含在故障机器中)。因此,对于较大的集群,通常增加半同步复制等待ACK的数目,使得出现上述状况时,仍能进行Master切换(非故障机器中,存在拥有最新数据的机器)。

增加等待ACK的数目,解决了数据丢失的问题,但同时给数据回滚带来了难题。

图8

如图8。假设MySQL集群有5台机器,半同步复制需要等待2台Slave的ACK。机器A为旧Master,在执行Wait ACK阶段,机器B收到Binlog后,机器A和机器B同时Crash或者被隔离,导致Binlog复制失败。根据场景3.2.1的分析,当机器C成为Master后,机器A和机器B在恢复服务前需要对其进行数据回滚。但对Slave进行数据回滚较为困难。且若回滚失败,则会出现数据不一致。

对于较小的集群,回滚PendingBinlog比较容易实现。但对于较大的集群,回滚PendingBinlog本身就是一个未解决的难题。

MySQL的Master切换问题

Master如何切换同时也是MySQL容灾中的一个难题。

一个简单的Master切换步骤:

1. Pause旧Master

2. Start新Master

3. 更换MySQLClient的Master指向IP

存在以下几个问题:

1. 当Master被隔离时,如何将其变更为Slave

解决方法:可修改MySQL的代码,使用zookeeper等外部辅助服务来自动维护Master的状态,可解决Master被隔离后不能操作的问题。

2. 如何定位拥有最新Binlog数据的MySQL

解决方法:可以通过人工,或者使用外部工具来检测集群每台MySQL的数据。但当出现故障机器无法访问时,无法定位。

3. 如何进行数据回滚

解决方法:可以通过运维进行人工操作。

4. 如何同时更换MySQLClient的Master指向IP

同时更换所有MySQLClient的Master指向IP是一件不可能的事情,因为不可能同一时刻操作所有机器。

不能同时更换所有MySQLClient的Master指向IP,导致部分Client会向旧Master发送请求,即出现多个Master同时服务。在使用半同步复制的情况下,多台MySQL不能同时知道Master的去向,使得数据可能产生不一致的情况。

图9

图10

假设机器A是旧Master,机器B是新Master,机器C还没收到Master更换的通知仍然向机器A复制Binlog。User1在Master切换前已经连上机器A并持续写入数据。User2在Master切换后开始向机器B写入数据。由于机器A能把数据复制给机器C,机器B能把数据复制给机器A,因此机器A和机器B都能成功写入。如图9。

由于机器A和机器B同时写入数据,数据一致性无法保证。如图10。

总结

从上面分析来看,MySQL的半同步复制和Master切换都存在一些不足。数据复制存在回滚难题,Master切换存在多Master难题。只有解决了这两大难题,才能保证MySQL集群的数据一致性。

MySQL半同步复制的数据一致性探讨微信后台团队实践【转】的更多相关文章

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

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

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

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

  3. MySQL半同步复制

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

  4. 安装MySQL半同步复制

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

  5. MySQL半同步复制(5.5之后引入)

    半同步复制架构在主库提交一个事务后,commit完成即反馈客户端,无需等待推送binlog完成,如图: 半同步复制在主库完成一个事务后,需等待事务信息写入binlog日志并且至少有一个从库写入rela ...

  6. mysql半同步复制实现

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

  7. MySQL半同步复制搭建

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

  8. (5.5)mysql高可用系列——MySQL半同步复制(实践)

    关键词,mysql半同步复制 [0]实验环境 操作系统:CentOS linux 7.5 数据库版本:5.7.24 数据库架构:主从复制,主库用于生产,从库用于数据容灾和主库备机,采用默认传统的异步复 ...

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

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

随机推荐

  1. C#隐藏(new)方法和重写(override)方法

    在基类调用的时候 隐藏方法还是调用基类的方法 而重写方法调用的就是子类的中的方法 同时,当子类中的方法与父类或者所实现的接口中的扩展方法冲突时,那么此时相当于一个隐藏方法 基类调用或者接口调用的时候使 ...

  2. react起步

    react是一个用于构建用户界面JAVASCRIPT库. react主要用于构建UI,是MVC中的V(视图). react特点 1.声明式设计 2.高效 3.灵活 4.JSX 5.组件 6.单项响应的 ...

  3. SVM与LR的比较

    两种方法都是常见的分类算法,从目标函数来看,区别在于逻辑回归采用的是logistical loss,svm采用的是hinge loss.这两个损失函数的目的都是增加对分类影响较大的数据点的权重,减少与 ...

  4. 印象烟大PPT大赛

    下面为获奖人员 王志恒一等奖 姜云飞.任子仪二等奖 田正相,庄棫麟,陈德昊三等奖.

  5. 《JS权威指南学习总结--第六章 对象》

    内容要点: 一.对象定义 对象是JS的基本数据类型.对象是一种复合值:它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值. 对象也可看做是属性的无序集合,每个属性都是一个名/值对. 属性 ...

  6. HDU1009FatMouse' Trade(贪心)

    Problem Description FatMouse prepared M pounds of cat food, ready to trade with the cats guarding th ...

  7. JavaScript事件响应的基础语法总结

    1.onclick是鼠标单击事件,当在网页上单击鼠标时,就会发生该事件.同时onclick事件调用的程序块就会被执行,通常与按钮一起使用 //例子 <html> <head> ...

  8. Java面向对象总复习-QuickHit

    1.创建玩家级别类Level.java package com.bdqn; /** * 1.玩家级别类 * @author pc * */ public class Level { /** * 级别号 ...

  9. (转) QImage总结

    嗯,这个QImage的问题研究好久了,有段时间没用,忘了,已经被两次问到了,突然有点解释不清楚,我汗颜,觉得有必要重新总结下了,不然无颜对自己了. 图像的数据是以字节为单位保存的,每一行的字节数必须是 ...

  10. 一步一步学EF系列1【Fluent API的方式来处理实体与数据表之间的映射关系】

    EF里面的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面,还有一个就是F ...