MySQL 主备切换:主备一致、主备延迟、一主多从

一、主备一致

1、MySQL 主备切换流程

主库、备库:

建议你把节点 B(也就是备库)设置成只读(readonly)模式。这样做,有以下几个考虑:有时候一些运营类的查询语句会被放到备库上去查,设置为只读可以防止误操作;防止切换逻辑有 bug,比如切换过程中出现双写,造成主备不一致;可以用 readonly 状态,来判断节点的角色。因为 readonly 设置对超级 (super) 权限用户是无效的,而用于同步更新的线程,就拥有超级权限。

切换流程:

1.在备库 B 上通过 change master 命令,设置主库A的 IP、端口、用户名、密码,以及要从哪个位置开始请求 binlog,这个位置包含文件名和日志偏移量。2.在备库 B 上执行 start slave 命令,这时候备库会启动两个线程,就是图中的 io thread和 sql thread。其中 io thread 负责与主库建立连接。3.主库 A 校验完用户名、密码后,开始按照备库 B 传过来的位置,从本地读取 binlog发给 B。4.备库 B 拿到 binlog 后,写到本地文件,称为中转日志 (relay log)5.sgl thread 读取中转日志,解析出日志里的命令,并执行。

2、binlog 的三种格式对比

1)binlog_format=statement

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

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

当 binlog_format=statement 时,binlog 里面记录的就是 SQL 语句的原文:

第二行是一个 BEGIN,跟第四行的 commit 对应,表示中间是一个事务;第三行就是真实执行的语句了。可以看到,在真实执行的 delete 命令之前,还有一个“use ‘test’”命令。这条命令不是我们主动执行的,而是 MySQL 根据当前要操作的表所在的数据库,自行添加的。这样做可以保证日志传到备库去执行的时候,不论当前的工作线程在哪个库里,都能够正确地更新到 test 库的表 t。

delete 带 limit,很可能会出现主备数据不一致的情况,在主库执行这样 SQL 语句的时候,用的是索引 a;而在备库执行这条 SQL 语句的时候,却使用了索引 t_modified。

2)binlog_format=‘row’

与 statement 格式的 binlog 相比,前后的 BEGIN 和 COMMIT 是一样的。但是,row 格式的 binlog 里没有了 SQL 语句的原文,而是替换成了两个 event:Table_map 和 Delete_rows。Table_map event,用于说明接下来要操作的表是 test 库的表 t;Delete_rows event,用于定义删除的行为。通过上图看不到完整信息,还需要借助 mysqlbinlog 工具,用下面这个命令解析和查看 binlog 中的内容。

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

从这个图中,我们可以看到以下几个信息:server id 1,表示这个事务是在 server id=1 的这个库上执行的·每个 event 都有 CRC32 的值,这是因为我把参 binlog checksum 设置成了CRC32。Table_map event 跟在图 5 中看到的相同,显示了接下来要打开的表,map 到数字226。现在我们这条 SQL 语句只操作了一张表,如果要操作多张表呢? 每个表都有一个对应的 Table map event、都会 map 到一个单独的数字,用于区分对不同表的操作。我们在 mysglbinlog 的命令中,使用了 -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)binlog_format=‘mixed’

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

越来越多的场景要求把 MySQL 的 binlog 格式设置成 row。这么做的理由有很多,我来给你举一个可以直接看出来的好处:恢复数据。

二、主备延迟

1、主备延迟的来源

  • 首先,有些部署条件下,备库所在机器的性能要比主库所在的机器性能差;

  • 第二种常见的可能了,即备库的压力大。一般的想法是,主库既然提供了写能力,那么备库可以提供一些读能力。或者一些运营后台需要的分析语句,不能影响正常业务,所以只能在备库上跑。耗费了大量的 CPU 资源,影响了同步速度,造成主备延迟。

2、延迟的处理

  • 一主多从。除了备库外,可以多接几个从库,让这些从库来分担读的压力。

  • 通过 binlog 输出到外部系统,比如 Hadoop 这类系统,让外部系统提供统计类查询的能力。

  • 减少大事务因为主库上必须等事务执行完成才会写入 binlog,再传给备库。所以,如果一个主库上的语句执行 10 分钟,那这个事务很可能就会导致从库延迟 10 分钟。Eg:一次性地用 delete 语句删除太多数据。

  • 另一种典型的大事务场景,就是大表 DDL。这个场景,我在前面的文章中介绍过。处理方案就是,计划内的 DDL,建议使用 gh-ost 方案。

  • 备库的并行复制能力

    图中两个箭头。一个箭头代表了客户端写入主库,另一箭头代表的是备库上 sql_thread 执行中转日志(relay log)。在官方的 5.6 版本之前,MySQL 只支持单线程复制,由此在主库并发高、TPS 高时就会出现严重的主备延迟问题。

    官方 MySQL5.6 版本,支持了并行复制,只是支持的粒度是按库并行

3、主备切换策略

由于主备延迟的存在,所以在主备切换的时候,就相应的有不同的策略:

1) 可靠性优先策略

这个切换流程中是有不可用时间的。因为在步骤 2 之后,主库 A 和备库 B 都处于 readonly 状态,也就是说这时系统处于不可写状态。

1.判断备库 B 现在的 seconds_behind_master,如果小于某个值 (比如 5 秒) 继续下-步,否则持续重试这一步;

2.把主库 A 改成只读状态,即把 readonly 设置为 true;

3.判断备库 B的 seconds behind master 的值,直到这个值变成 0 为止4.把备库 B 改成可读写状态,也就是把 readonly 设置为 false;5.把业务请求切到备库 B。

2)可用性优先策略

可用性优先策略,且 binlog_format=row容易导致主备数据不一致。从上面的分析中,你可以看到一些结论:1.使用 row 格式的 binlog 时,数据不一致的问题更容易被发现。而使用 mixed 或者statement 格式的 binlog 时,数据很可能悄悄地就不一致了。如果你过了很久才发现数据不一致的问题,很可能这时的数据不一致已经不可查,或者连带造成了更多的数据逻辑不一致。2.主备切换的可用性优先策略会导致数据不一致。因此,大多数情况下,我都建议你使用可靠性优先策略。毕竟对数据服务来说的话,数据的可靠性一般还是要优于可用性的。

一般现在的数据库运维系统都有备库延迟监控,其实就是在备库上执行 show slave status,采集 seconds_behind_master 的值。

三、一主多从

1、一主多从架构

一主多从基本结构

一主多从基本结构---主备切换

2、主库故障了怎么切换

1)基于位点的主备切换

当我们把节点 B 设置成节点 A’的从库的时候,需要执行一条 change master 命令

CHANGE MASTER TO
MASTER_HOST=Shost_name
MASTER_PORT-Sport
MASTER USER-Suser_name
MASTER PASSWORD-Spassword
MASTER LOG FILE=Smaster_log_name
MASTER LOG POS=Smaster_log_pos

这条命令有这么 6 个参数:

  • MASTER HOST、MASTER PORT、MASTER USER 和 MASTER PASSWORD 四个参数,分别代表了主库 A’的IP、端口、用户名和密码。

  • 最后两个参数 MASTER LOG FILE 和 MASTER LOG POS 表示,要从主库的master_log_name 文件的 master log_pos 这个位置的日志继续同步。而这个位置就是2/0020我们所说的同步位点,也就是主库对应的文件名和日志偏移量。

考虑到切换过程中不能丢数据,所以我们找位点的时候,总是要找一个“稍微往前”的,然后再通过判断跳过那些在从库 B 上已经执行过的事务。
有两种常用的方法。一种做法是,主动跳过一个事务。跳过命令的写法是:

set global sql_slave_skip_counter=1;
start slave;

另外一种方式是,通过设置 slave_skip_errors 参数,直接设置跳过指定的错误。在执行主备切换时,有这么两类错误,是经常会遇到的:1062 错误是插入数据时唯一键冲突;1032 错误是删除数据时找不到行。因此,我们可以把 slave_skip_errors 设置为 “1032,1062”,这样中间碰到这两个错误时就直接跳过。

2)GTID(全局事务 ID)

MySQL 5.6 版本引入了 GTID。GTID 的全称是 Global Transaction Identifier,也就是全局事务 ID,是一个事务在提交的时候生成的,是这个事务的唯一标识。它由两部分组成,格式是:GTID=server_uuid:gno

server_uuid 是一个实例第一次启动时自动生成的,是一个全局唯一的值;gno 是一个整数,初始值是 1,每次提交事务的时候分配给这个事务,并加 1。

基于 GTID 的主备切换 现在,我们已经理解 GTID 的概念,再一起来看看基于 GTID 的主备复制的用法
在 GTID 模式下,备库 B 要设置为新主库 A’的从库的语法如下:

CHANGE MASTER TO
MASTER HOST-Shost_name
MASTER_PORT=Sport
MASTER USER-Suser_name
MASTER_PASSWORD-Spassword
master_auto position=1

其中,master auto_position=1 就表示这个主备关系使用的是 GTID 协议。可以看到,前面让我们头疼不已的 MASTER LOG FILE 和 MASTER LOG POS 参数,已经不需要指定了。

MySQL读写分离请参看:MySQL读写分离架构

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

推荐阅读更多精彩内容