MySQL实战45讲Day23----如何保证主备一致

一、主备的基本原理:

主备切换流程

1、原理:

  在状态1中,客户端的读写都直接访问节点A,而节点B是A的备库,只是将A的更新都同步过来,到本地执行。这样可以保持节点B和A的数据是相同的。当需要切换的时候,就切成状态2。这时候客户端读写访问的都是节点B,而节点A是B的备库。
  在状态1中,虽然节点B没有被直接访问,但依然建议把节点B(也就是备库)设置成只读(readonly)模式(因为readonly设置对超级(super)权限用户是无效的,而用于同步更新的线程,就拥有超级权限。所以即使把备库设置成只读,也能跟主库保持同步更新)。这样做,有以下几个考虑:
 ①、有时候一些运营类的查询语句会被放到备库上去查,设置为只读可以防止误操作;
 ②、防止切换逻辑有bug,比如切换过程中出现双写,造成主备不一致;
 ③、可以用readonly状态,来判断节点的角色。

2、节点A到节点B的内部流程:

主备流程图(M-S结构)

  主库接收到客户端的更新请求后,执行内部事务的更新逻辑,同时写binlog。
  备库B跟主库A之间维持了一个长连接。主库A内部有一个线程,专门用于服务备库B的这个长连接。
  事务日志同步的完整过程
 ①、在备库B上通过change master命令,设置主库A的IP、端口、用户名、密码,以及要从哪个位置开始请求binlog,这个位置包含文件名和日志偏移量。
 ②、在备库B上执行start slave命令,这时候备库会启动两个线程,就是图中的io_thread和sql_thread。其中io_thread负责与主库建立连接。
 ③、主库A校验完用户名、密码后,开始按照备库B传过来的位置,从本地读取binlog,发给B。
 ④、备库B拿到binlog后,写到本地文件,称为中转日志(relay log)。
 ⑤、sql_thread读取中转日志,解析出日志里的命令,并执行。

二、binlog的三种格式对比:

1、binlog的三种格式:

  statement、row和mixed(前两种格式的混合)。

2、对于下表:

mysql> CREATE TABLE `t` (
  `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 t values(1,1,'2018-11-13');
insert into t values(2,2,'2018-11-12');
insert into t values(3,3,'2018-11-11');
insert into t values(4,4,'2018-11-10');
insert into t values(5,5,'2018-11-09');

以删除一行数据为例:

mysql> delete from t /*comment*/  where a>=4 and t_modified<='2018-11-10' limit 1;

查询binlog内容的方法:

mysql> show binlog events in 'master.000001';

 ①、statement格式下binlog内容

 ②、statement格式下delete命令的执行效果图


 运行这条delete命令产生了一个warning,原因是当前binlog设置的是statement格式,并且语句中有limit,所以这个命令可能是unsafe的。因为delete 带limit,很可能会出现主备数据不一致的情况。比如上面这个例子:
  如果delete语句使用的是索引a,那么会根据索引a找到第一个满足条件的行,也就是说删除的是a=4这一行;
  如果使用的是索引t_modified,那么删除的就是 t_modified='2018-11-09’也就是a=5这一行。
 由于statement格式下,记录到binlog里的是语句原文,因此可能会出现这样一种情况:在主库执行这条SQL语句的时候,用的是索引a;而在备库执行这条SQL语句的时候,却使用了索引t_modified。因此,MySQL认为这样写是有风险的。

 ③、row格式下binlog内容


可以看到,与statement格式的binlog相比,前后的BEGIN和COMMIT是一样的。但row格式的binlog里没有SQL语句的原文,而是替换成了两个event:Table_map和Delete_rows。(Table_map event用于说明接下来要操作的表是test库的表t;Delete_rows event用于定义删除的行为。)
④、row格式下的delete命令是看不到详细信息的,需要借助mysqlbinlog工具,用下面这个命令解析和查看binlog中的内容。因为row格式下binlog信息显示,这个事务的binlog是从8900这个位置开始的,所以可以用start-position参数来指定从这个位置的日志开始解析。

mysqlbinlog  -vv data/master.000001 --start-position=8900;

 ②、row格式下delete命令的执行效果图


其中:
 server id 1,表示这个事务是在server_id=1的这个库上执行的。
 每个event都有CRC32的值,这是因为把参数binlog_checksum设置成了CRC32。
 Table_map event显示了接下来要打开的表,map到数字226。现在这条SQL语句只操作了一张表,如果要操作多张表,那么每个表都有一个对应的Table_map event、都会map到一个单独的数字,用于区分对不同表的操作。
 在mysqlbinlog的命令中,使用了-vv参数是为了把内容都解析出来,所以从结果里面可以看到各个字段的值(比如,@1=4、 @2=4这些值)。
 binlog_row_image的默认配置是FULL,因此Delete_event里面,包含了删掉的行的所有字段的值。如果把binlog_row_image设置为MINIMAL,则只会记录必要的信息,在这个例子里,就是只会记录id=4这个信息。
 最后的Xid event,用于表示事务被正确地提交了。

当binlog_format使用row格式的时候,binlog里面记录了真实删除行的主键id,这样binlog传到备库去的时候,就肯定会删除id=4的行,不会有主备删除不同行的问题。

3、mixed这种binlog格式的存在场景:

 ①、因为有些statement格式的binlog可能会导致主备不一致,所以要使用row格式。
 ②、但row格式的缺点是很占空间。
比如用一个delete语句删掉10万行数据,用statement的话就是一个SQL语句被记录到binlog中,占用几十个字节的空间。但如果用row格式的binlog,就要把这10万条记录都写到binlog中。这样做,不仅会占用更大的空间,同时写binlog也要耗费IO资源,影响执行速度。
 ③、所以,MySQL就取了个折中方案,也就是有了mixed格式的binlog。mixed格式的意思是MySQL自己会判断这条SQL语句是否可能引起主备不一致,如果有可能,就用row格式,否则就用statement格式。

4、binlog格式设置成row的好处:

<1>、delete:

  row格式的binlog会把被删掉的行的整行信息保存起来。所以,如果在执行完一条delete语句以后,发现删错数据了,可以直接把binlog中记录的delete语句转成insert,把被错删的数据插入回去就可以恢复了。

<2>、insert:

  row格式下,insert语句的binlog里会记录所有的字段信息,这些信息可以用来精确定位刚刚被插入的那一行。这时,直接把insert语句转成delete语句,删除掉这被误插入的一行数据就可以了。

<3>、update:

  binlog里面会记录修改前整行的数据和修改后的整行数据。所以,如果误执行了update语句的话,只需要把这个event前后的两行信息对调一下,再去数据库里面执行,就能恢复这个更新操作了。

5、循环复制问题:
主备流程图(双M结构)

 <1>、双M结构和M-S结构的区别:

  节点A和B之间总是互为主备关系。这样在切换的时候就不用再修改主备关系。

 <2>、循环复制问题:

  业务逻辑在节点A上更新了一条语句,然后再把生成的binlog 发给节点B,节点B执行完这条更新语句后也会生成binlog。(建议把参数log_slave_updates设置为on,表示备库执行relay log后生成binlog)。如果节点A同时是节点B的备库,相当于又把节点B新生成的binlog拿过来执行了一次,然后节点A和B间,会不断地循环执行这个更新语句,也就是循环复制了。这个要怎么解决呢?

 MySQL在binlog中记录了这个命令第一次执行时所在实例的server id。因此可以用下面的逻辑,来解决两个节点间的循环复制的问题:
①、规定两个库的server id必须不同,如果相同,则它们之间不能设定为主备关系;
②、一个备库接到binlog并在重放的过程中,生成与原binlog的server id相同的新的binlog;
③、每个库在收到从自己的主库发过来的日志后,先判断server id,如果跟自己的相同,表示这个日志是自己生成的,就直接丢弃这个日志。

 按照这个逻辑,如果设置了双M结构,日志的执行流就会变成这样:
①、从节点A更新的事务,binlog里面记的都是A的server id;
②、传到节点B执行一次以后,节点B生成的binlog 的server id也是A的server id;
③、再传回给节点A,A判断到这个server id与自己的相同,就不会再处理这个日志。所以,死循环在这里就断掉了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 数据备份类型 全量备份:备份整个数据库 增量备份:备份自上一次备份以来(增量或完全)以来变化的数据 差异备份:备份...
    jxtxzzw阅读 1,362评论 0 1
  • 专业考题类型管理运行工作负责人一般作业考题内容选项A选项B选项C选项D选项E选项F正确答案 变电单选GYSZ本规程...
    小白兔去钓鱼阅读 8,970评论 0 13
  • 1.A simple master-to-slave replication is currently being...
    Kevin关大大阅读 5,942评论 0 3
  • MySQL主备数据流转流程 备库B和主库A维持了一个长连接1、在备库 B 上通过 change master 命令...
    剑客kb阅读 819评论 0 0
  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,442评论 0 13