Mysql主备的基本原理

在状态1中,客户端直接访问节点A,而节点B只是备库,只是将A的binlog全部同步过来并应用到本地,这样可以保持节点B和节点A的数据是相同的。

当需要切换的时候,就变成状态2,这时候客户端读取的是节点B,而A变成B的备库。

在状态1中,B节点没有被直接访问,建议设置为readonly状态。

1 有时候一些运营类的查询会放到备库去上去查询,设置为只读可以防止误操作

2 防止切换逻辑有bug,比如切换过程中出现双写,造成主备不一致

3 可以用readonly状态,来判断主备角色

设置为readonly状态,不会对复制线程有影响,因为复制的用户拥有super权限

接下来,我们看节点A到B的内部流程,用一个update语句来执行

主库接收到客户端的更新操作请求后,执行内部的更新逻辑,并写binlog。

备库B跟主库A之间维持了一个长连接,主库A内部一个dump线程,专门用于服务B备库的这个长连接,一个事务日志同步的完整过程如下:

1 在备库B上通过change master命令,指定主库A的IP,端口,用户名,密码,以及开启请求的binlog(包含文件名和偏移位置)

2 在备库B上执行start slave,这时候备库启动2个线程,io_thread和sql_thread,前者专门负责与主库的连接

3 主库A效验完用户和密码后,开始按照B库传过来的文件名和位置点,从本地读取binlog,发给B库

4 备库B拿到binlog后,写本地文件(relay log)

5 sql_thread线程读取relay log,解析出日志的命令并执行

后面引入多线程复制方案,所以sql_thread也变成个线程

Binlog的三个格式对比

In MySQL 5.6, the default binary logging format is STATEMENT

mysql> SET GLOBAL binlog_format = 'STATEMENT';

mysql> SET GLOBAL binlog_format = 'ROW';

mysql> SET GLOBAL binlog_format = 'MIXED';

==

mysql> SET GLOBAL binlog_format = 'STATEMENT';

(system@127.0.0.1:3306) [(none)]> show variables like '%bin%';

| binlog_format                           | STATEMENT

(system@127.0.0.1:3306) [(none)]> use test;

CREATE TABLE `t23` (

`id` int(11) NOT NULL,

`a` int(11) DEFAULT NULL,

`t_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY (`id`),

KEY `a` (`a`),

KEY `t_modified`(`t_modified`)

) ENGINE=InnoDB;

insert into t23 values(1,1,'2018-11-13');

insert into t23 values(2,2,'2018-11-12');

insert into t23 values(3,3,'2018-11-11');

insert into t23 values(4,4,'2018-11-10');

insert into t23 values(5,5,'2018-11-09');

(system@127.0.0.1:3306) [test]> delete from t23 /*comment*/  where a>=4 and t_modified<='2018-11-10' limit 1;

Query OK, 1 row affected, 1 warning (0.00 sec)

(system@127.0.0.1:3306) [test]> show binlog events in 'mysql-bin.000022';

+------------------+------+-------------+------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Log_name         | Pos  | Event_type  | Server_id  | End_log_pos | Info                                                                                                                                                                                                                                       |

+------------------+------+-------------+------------+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| mysql-bin.000022 |    4 | Format_desc | 2018091901 |         120 | Server ver: 5.6.15-log, Binlog ver: 4                                                                                                                                                                                                      |

从表中删除一条记录,可以看到binlog中是怎么记录的

第一行和第三行begin和commit对应,是一个事务,中间是一个执行语句,在真实的delete语句前面,有一个use test的命令。这条命令是mysql自动添加的,保证传到备库执行的时候,能够正取的执行到test库的t23表

说明statement与row格式的区别,执行完delete命令后,有一个warnings

(system@127.0.0.1:3306) [test]> show warnings;

+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Level | Code | Message                                                                                                                                                                                                                         |

+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Note  | 1592 | Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. The statement is unsafe because it uses a LIMIT clause. This is unsafe because the set of rows included cannot be predicted. |

+-------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

原因是这个delete的binlog的格式是statement,并且语句中有limit,所以这个命令可能是unsafe的。

比如上面这个例子:

1 如果delete语句是使用的索引a,那么会根据索引a找到第一个满足条件的行,也就说删除a=4这一行

2 但如果使用的是索引t_modified,那么删除的就是t_modified='2018-11-09'这一行,也就是说是a=5的这一行

由于在statement格式下,记录到binlog里面的语句是语句原文,因此可能会出现这样一种状况,在主库执行这条sql语句,用到的是索引a,而在备库用的是索引t_modified,因此,这样写是有风险的。

如果更换为row格式的,我们看一看

mysql> SET GLOBAL binlog_format = 'ROW';

(system@127.0.0.1:3306) [test]> delete from t23 /*comment*/  where a>=4 and t_modified<='2018-11-10' limit 1;

Query OK, 1 row affected (0.00 sec)

这个时候看binlog的内容,与statement相比,前后的begin和commit是一样,但是row格式在binlog里面不是sql原文,而是替换为Table_map和Delete_rows

1 Table_map event,用于说明接下来要操作的是表是test库的表t23

2 Delete_rows event,用于定义删除的行为

要查看详细的binlog,要借助mysql自身的命令mysqlbinlog

[mysql@mysqlhq binlog]$ mysqlbinlog -vv mysql-bin.000023 --start-position=408

1 server id 2018091901,表示这个事务是server id =2018091901的库上执行的。

2 每个event都有CRC32的值,是因为把binlog_checksum 设置了CRC32

(system@127.0.0.1:3306) [test]> show variables like 'binlog_checksum';

+-----------------+-------+

| Variable_name   | Value |

+-----------------+-------+

| binlog_checksum | CRC32 |

+-----------------+-------+

3 Table_map event 显示了接下来要展开的表,map到数字table_id: 2425,现在这个sql只操作了一个表,如果多个表,每个表对应的Table_map event,每个map到一个单独的数字,用于分区不同的表

4 在mysqlbinlog命令中,使用-vv参数是为了把内容都解析出来,从结果看到各个字段的值(@1=4,@2=4,@3=1541779200)

5 binlog_row_image的默认配置是FULL,因此delete_event里面,包含了删掉的所有行的所有字段,如果把该参数设置为MININAL,则只会记录必要的信息,在这个例子中,记录的就是id=4的这个信息

(system@127.0.0.1:3306) [test]> show variables like 'binlog_row_image';

+------------------+-------+

| Variable_name    | Value |

+------------------+-------+

| binlog_row_image | FULL  |

+------------------+-------+

6 最后的Xid = 3777647 event,表示事务被正确的提交了

为什么会有mixed格式的binlog

1 因为有些statement格式的binlog可能胡导致主备不一致,所以要使用row格式

2 但row格式的缺点是很占用空间,比如一个delete语句删掉10w行数据,用statement语句的话就是一个sql语句记录到binlog中,占用比较小的空间,但是如果是row格式的binlog,就要把这10w条记录都写到binlog中,这样不仅会占用更大的空间,还会消费io资源,影响执行速度

3 所以mysql取了一个折中的方案,就是mixed格式,mysql自己会判断这条sql语句是否引起主备不一致,如果可能,就用row格式,否则就用statement格式

所以线上的binlog格式至少应该是mixed和row格式

设置为row格式的好处就是容易恢复数据--flushback之类

比如dml,insert,update,delete之类的语句,row格式的binlog在恢复的时候,可以利用binlog进行转换,比如insert转换delete,delete转换insert,目前有一些第三方工具--MariaDBD Flushback工具,美团的Myflush等。--参考https://www.cnblogs.com/yhq1314/p/10179306.html

现在看一下mixed格式的binlog

mysql> SET GLOBAL binlog_format = 'MIXED';

mysql> insert into t values(10,10, now());

看一下执行效果,还是now()变量,如果传到备库,是否会不一致呢

解析一下binlog

[mysql@mysqlhq binlog]$ mysqlbinlog -vv mysql-bin.000023 --start-position=623

从图中看到,在binlog记录的时候,多写了一个set timestamp的记录

SET TIMESTAMP=1547022196/*!*/; 约定了接下来now()函数返回的时间

在用binlog来恢复数据的标准做法,用mysqlbinlog解析出来,把整个结果集发给mysql执行

mysqlbinlog mysql-bin.000023  --start-position=2738 --stop-position=2973 | mysql -h127.0.0.1 -P13000 -u$user -p$pwd;

循环复制问题

通过上面知道在mysql中,binlog的特性确保了在备库执行相同的binlog,可以得到主库的状态

因此,我们认为正常情况下主备的数据是一致的。

Mysql在复制中

1 规定在同一复制环境中的server_id不能相同,如果相同,则不能成为主从关系

2 一个备库接到主库的binlog并在重放的过程中, 生成与原来binlog的server_id相同的binlog

3 每个库在收到从自己的主库发过来的日志后,先判断server_id,如果跟自己的相同,表示这个是自己生成的,就直接丢弃这个日志。

24 mysql怎么保证主备一致的更多相关文章

  1. MySQL高可用(一)主备同步:MySQL是如何保证主备一致的

    主备同步,也叫主从复制,是MySQL提供的一种高可用的解决方案,保证主备数据一致性的解决方案. 在生产环境中,会有很多不可控因素,例如数据库服务挂了.为了保证应用的高可用,数据库也必须要是高可用的. ...

  2. MySQL备份与主备配置

    MySQL备份与主备配置 数据备份类型 全量备份:备份整个数据库 增量备份:备份自上一次备份以来(增量或完全)以来变化的数据 差异备份:备份自上一次完全备份以来变化的数据 全量备份 全量备份的方法有 ...

  3. 24 | MySQL是怎么保证主备一致的?

    在前面的文章中,我不止一次地和你提到了binlog,大家知道binlog可以用来归档,也可以用来做主备同步,但它的内容是什么样的呢?为什么备库执行了binlog就可以跟主库保持一致了呢?今天我就正式地 ...

  4. 《Mysql - Mysql 是如何保证主备一致的?》

    一:Mysql 主备的基本原理? - 主备切换流程(M-S 架构) -  - 在状态 1 中,客户端的读写都直接访问节点 A,而节点 B 是 A 的备库,只是将 A 的更新都同步过来,到本地执行. - ...

  5. MySQL建立双向主备复制server配置方法

    1.环境描写叙述 serverA(主) 192.85.1.175 serverB(从) 192.85.1.176 Mysql版本号:5.1.61 系统版本号:System OS:ubuntu 10.1 ...

  6. 【MySQL】主备复制

    复制对于mysql的重要性不言而喻,mysql集群的负载均衡,读写分离和高可用都是基于复制实现.下文主要从4个方面展开,mysql的异步复制,半同步复制和并行复制,最后会简单聊下第三方复制工具.由于生 ...

  7. MySQL主备模式的数据一致性解决方案

     根据阿里交易型业务的特点,以及在双十一这样业内罕有的需求推动下,我们在官方的MySQL基础上增加了非常多实用的功能.性能补丁.而在使用MySQL的过程中,数据一致性是绕不开的话题之一.本文主要从阿里 ...

  8. keepalived工作原理和配置说明 腾讯云VPC内通过keepalived搭建高可用主备集群

    keepalived工作原理和配置说明 腾讯云VPC内通过keepalived搭建高可用主备集群 内网路由都用mac地址 一个mac地址绑定多个ip一个网卡只能一个mac地址,而且mac地址无法改,但 ...

  9. f5主备切换演练

    1.准备工作: 1)保证主备机同步 2)备份主备机配置 2.切换:所有操作均在主机 方法1:shutdown主机上联的核心交换机的端口: 此方法在主备切换过程中会丢1个包 方法2:命令行下reboot ...

随机推荐

  1. 阿里云 centOS7.4新装nginx 不能访问

    反复装了几遍ngxin,什么防火墙,nginx.conf改了好几次都不能访问外网的ip, 原因是阿里云这货新的服务器根本就没开通443,80端口,真是坑人啊 点击配置规则,增加端口就行了 添加安全规则 ...

  2. HTML5 ——web audio API 音乐可视化(一)

    使用Web Audio API可以对音频进行分析和操作,最终实现一个音频可视化程序. 最终效果请戳这里; 完整版代码请戳这里,如果还看得过眼,请给一个start⭐ 一.API AudioContext ...

  3. 需要记忆的几个sql语句

    链接查询: 1.查询两个表,在where中定义连接条件: select student.sno,sname,ssex,sage,sdept,cno,grade. from student,sc whe ...

  4. Coundn't load memtrack module (No such file or directory)

    Coundn't load memtrack module (No such file or directory) 去仔细看日志,是包名有问题 一.出现症状 提示找logcat logcat里面发现C ...

  5. python学习笔记(excel+unittest)

    准备先利用之前整理的python自带的unittest框架 整合excel 实现接口自动化测试功能 先看看excel表格设置: 下来是对excel获取的代码: #!/usr/bin/env pytho ...

  6. Git的add、commit、push命令

    简单的代码提交流程1.git status 查看工作区代码相对于暂存区的差别2.git add . 将当前目录下修改的所有代码从工作区添加到暂存区 . 代表当前目录3.git commit -m ‘注 ...

  7. sha1加密

    SHA-1是一种数据加密算法,该算法的思维是接纳一段明文,然后以一种不可逆的方式将它转换成一段(一般更小)密文, 也能够简略的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短.位数固定的 ...

  8. 【git】常用命令大全

    Git常用操作命令收集: 1) 远程仓库相关命令 检出仓库:$ git clone git://github.com/jquery/jquery.git   后边接仓库文件地址 查看远程仓库:$ gi ...

  9. MySQL Multi-Range Read

    MySQL 5.6版本提供了很多性能优化的特性,其中之一就是 Multi-Range Read 多范围读(MRR) , 它的作用针对基于辅助/第二索引的查询,减少随机IO,并且将随机IO转化为顺序IO ...

  10. Android 中Activity,Window和View之间的关系

    转自:http://hi.baidu.com/xiaofanqing/blog/item/8261ac114ab14f64cb80c435.html 我这里根据我个人的理解来讲讲我个人对这3个概念的理 ...