24 mysql怎么保证主备一致
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怎么保证主备一致的更多相关文章
- MySQL高可用(一)主备同步:MySQL是如何保证主备一致的
主备同步,也叫主从复制,是MySQL提供的一种高可用的解决方案,保证主备数据一致性的解决方案. 在生产环境中,会有很多不可控因素,例如数据库服务挂了.为了保证应用的高可用,数据库也必须要是高可用的. ...
- MySQL备份与主备配置
MySQL备份与主备配置 数据备份类型 全量备份:备份整个数据库 增量备份:备份自上一次备份以来(增量或完全)以来变化的数据 差异备份:备份自上一次完全备份以来变化的数据 全量备份 全量备份的方法有 ...
- 24 | MySQL是怎么保证主备一致的?
在前面的文章中,我不止一次地和你提到了binlog,大家知道binlog可以用来归档,也可以用来做主备同步,但它的内容是什么样的呢?为什么备库执行了binlog就可以跟主库保持一致了呢?今天我就正式地 ...
- 《Mysql - Mysql 是如何保证主备一致的?》
一:Mysql 主备的基本原理? - 主备切换流程(M-S 架构) - - 在状态 1 中,客户端的读写都直接访问节点 A,而节点 B 是 A 的备库,只是将 A 的更新都同步过来,到本地执行. - ...
- MySQL建立双向主备复制server配置方法
1.环境描写叙述 serverA(主) 192.85.1.175 serverB(从) 192.85.1.176 Mysql版本号:5.1.61 系统版本号:System OS:ubuntu 10.1 ...
- 【MySQL】主备复制
复制对于mysql的重要性不言而喻,mysql集群的负载均衡,读写分离和高可用都是基于复制实现.下文主要从4个方面展开,mysql的异步复制,半同步复制和并行复制,最后会简单聊下第三方复制工具.由于生 ...
- MySQL主备模式的数据一致性解决方案
根据阿里交易型业务的特点,以及在双十一这样业内罕有的需求推动下,我们在官方的MySQL基础上增加了非常多实用的功能.性能补丁.而在使用MySQL的过程中,数据一致性是绕不开的话题之一.本文主要从阿里 ...
- keepalived工作原理和配置说明 腾讯云VPC内通过keepalived搭建高可用主备集群
keepalived工作原理和配置说明 腾讯云VPC内通过keepalived搭建高可用主备集群 内网路由都用mac地址 一个mac地址绑定多个ip一个网卡只能一个mac地址,而且mac地址无法改,但 ...
- f5主备切换演练
1.准备工作: 1)保证主备机同步 2)备份主备机配置 2.切换:所有操作均在主机 方法1:shutdown主机上联的核心交换机的端口: 此方法在主备切换过程中会丢1个包 方法2:命令行下reboot ...
随机推荐
- int(3)与int(11)的区别
注意:这里的M代表的并不是存储在数据库中的具体的长度,以前总是会误以为int(3)只能存储3个长度的数字,int(11)就会存储11个长度的数字,这是大错特错的.其实当我们在选择使用int的类型的时候 ...
- Angular表达式--插值字符串($interpolate)
要在字符串模板中做插值操作,需要在你的对象中注入$interpolate服务.在下面的例子中,我们将会将它注入到一个控制器中: angular.module('myApp', []) .control ...
- WSL安装xfce4
参考:https://github.com/Microsoft/WSL/issues/637 安装组件 1. win10 上安装 Xming https://sourceforge.net/proje ...
- 将本地代码提交到gitlub
第一步:建立git仓库 cd到本地项目根路径下面,执行git命令:git init $ git init Initialized empty Git repository in D:/my_wor ...
- jfinal微信支付
private static final String appid = PropKit.get("appid"); //应用ID private static final Stri ...
- MySQL 5.7.18 在centos下安装记录
一个朋友找我如何在linux下安装mysql5.7.18,我稍微整理下了下记录,如下: 下载地址: MySQL5.7.18参数官方网址:https://dev.mysql.com/doc/refman ...
- [C#] Newtonsoft.Json 版本冲突
在web.config或者app.config里面加上一段: <runtime> <assemblyBinding xmlns="urn:schemas-microsoft ...
- Android内存优化(一)DVM和ART原理初探
相关文章 Android内存优化系列 Java虚拟机系列 前言 要学习Android的内存优化,首先要了解Java虚拟机,此前我用了多篇文章来介绍Java虚拟机的知识,就是为了这个系列做铺垫.在And ...
- Django 碎片集合
命令行创建Django项目 熟记建立django命令:django-admin startproject xx (start project) 目录介绍 manage.py 文件是用来管理文件 ...
- 洛谷P3585 [POI2015]PIE
传送门 题目大意:有个n*m的格子图,要求'x'点要被染成黑色 有个a*b的印章,'x'是可以染色的印章上的点. 要求用印章去染色格子 (1)印章不可以旋转. (2)不能把墨水印到纸外面. (3)纸上 ...