关于后端:MySQL高可用架构探秘主从复制剖析切换策略延迟优化与架构选型

4次阅读

共计 4513 个字符,预计需要花费 12 分钟才能阅读完成。

MySQL 高可用的基石

在分布式系统中,单机节点在产生故障时无奈提供服务,这可能导致长期的服务不可用,从而影响其余节点的运作,导致的结果十分重大

为了满足服务的高可用,往往是通过节点冗余(新增雷同性能的从节点),当产生故障时进行主从切换,让从节点成为新的主节点来持续提供服务

比方:MySQL 的主从、Redis 的主从、MQ broker 的主从 … 思维大体相似的

作为高可用的基石——主从架构功不可没,本篇文章就来聊聊 MySQL 的主从的一些细节

binlog

binlog 作为逻辑上复原数据的日志,是主从数据同步、数据恢复的根底

binlog 分为三种格局:statement、row、mixed

statement:记录写操作的 SQL,语句轻量、传输快,应用该格局可能会导致数据不统一 (因为从机与主机所处的环境不同,比方从机工夫与主机不同时,应用 now() 函数)

row:记录数据的批改,数据量大、传输慢,误操作时能够复原数据(反向操作),主从同步时数据统一

mixed:联合 statement、row 的长处,主动混合选择格局

大多数状况下都是抉择格局为 row,因为数据统一并且能够复原数据

主从复制

往期文章中说过当收到写操作须要批改数据时,为了满足数据的一致性,会写 undo log(原子性)、redo log(持久性)、binlog 等日志

当主节点接管到写操作更改数据时,也须要对从节点进行数据的批改以此来达到数据统一

在主从复制数据依附的就是 binlog,大抵流程分为三个阶段:

  1. 主节点 dump 线程监听 binlog 变动告诉从节点
  2. 从节点应用 IO 线程接管 binlog 并将其写入本地 relay log(中继日志)
  3. 从节点应用 SQL 线程依据 relay log 复原数据

在单机中写完日志即可提交事务响应,而在主从中依据响应阶段的不同,主从复制的形式分为多种:

同步复制:所有从节点都响应(复原完数据)主节点才响应,性能差、数据强统一

异步复制:主节点告诉完从节点就立马响应,性能最好,存在提早有数据一致性问题

半同步复制:只有有一个从节点响应主节点就响应,一主一从下与同步复制统一,网络超时进化为异步复制

加强半同步复制:在半同步复制的根底上,主节点收到响应后才提交事务,数据一致性会比半同步好,但性能稍差

提早复制:从节点提早一段时间复原数据,这样即便产生误操作也能够进行回滚数据

主从切换

当主机产生故障时须要将从机切换为主机

不同策略

个别中间件的主从切换都只能在 CAP 实践中满足其二,即 在分区容错(P)下只能满足牢靠(C)或可用(A)

binlog 上会记录主节点写操作的工夫,从节点会保护一个 seconds_behind_master 来记录主从提早的工夫

在牢靠策略下,须要等到旧的从节点实现所有的数据恢复(即 seconds_behind_master 为 0)才成为主节点,提供写服务

在此期间只提供读服务、无奈提供写服务,因而 牢靠策略会损失肯定的可用性,取决于主从提早的工夫

在可用策略下会立刻将从节点设置为新的主节点提供读写服务,某些场景下可能导致数据不统一

假如 id 自增,记录格局为(id,name),新增数据 a,b,c

  1. 主节点曾经新增 (1,a),(2,b),(3,c) 时宕机
  2. 从节点可能只重做数据 (1,a),(2,b) 而(3,c) 还在中继日志中
  3. 此时旧的从节点成为新的主节点又持续提供写服务,须要新增 d,新增完 d 后才将中继日志的数据进行复原

如果应用的 binlog 格局为 statement 或 mixed,则会新增为 (3,d) 和(4,c)

如果格局为 row,则会主键抵触报错,新增 (3,d) 后中继日志为(3,c)

在可用策略下可能导致数据不统一,应用 row 会提前裸露数据不统一的问题

基于 GTID 的主从切换

GTID 全局事务 ID

格局为 server_uuid:gno

server_uuid 为节点标识

gno 为事务标识(事务提交时取得,全局自增)

在进行主从切换时,每个从节点同步数据的日志偏移量都不同,个别会找最新偏移量的从节点为新的主节点(这个偏移量是须要运维去定位的)

在 GTID 全局事务 ID 进去后,binlog 中每个事务有对应的 GTID 则能够 通过 GTID 主动定位偏移量,不必手动定位

主从提早

起源

默认状况下主从复制会应用异步复制,而在主从架构下个别会应用读写拆散,主机服务写操作,从机服务读操作

因为应用异步复制,主从之间的数据一致性会存在肯定的提早,物理上主从会放在同一机房中,网络通信忽略不计,老本最大的就是从机 SQL 线程解析日志复原数据的过程

如果复原数据是一些大事务时会导致很长的提早,比方在主机上执行批量操作耗时 5s,在从机上执行时也会耗时那么久(资源大略统一)

可能写完操作就会进行读操作,如果此时从库还未重做数据就会导致写完查不到的数据不统一状况

先来看看哪些状况可能会导致主从提早太长:

  1. 业务高峰期频繁读写(高 TPS),从机不仅要同步数据,还要解决读操作
  2. 解决大事务,大事务导致延迟时间太久
  3. 从机硬件配置低,导致跟不上主机 IO 速度
  4. 主从机器可能参数不同(缓冲池、IO 参数 …)
  5. 从机自身就是提早复制

当主从提早过长时能够思考应用计划缩短提早:

  1. 调整 redo log\bin log 刷盘策略,加强 IO
  2. canal 监听(告诉改为监听)
  3. 从机并行复制

从机并行复制借助于 redo log、bin log 两阶段提交时,redo log prepare 阶段不会有锁抵触,能够并行执行

并行复制就是基于两阶段提交中的组提交,能够调整以下两个参数拉长组提交的工夫,减慢主机写,放慢从机重做数据

binlog_group_commit_sync_delay 提早多少微秒后才调用 fsync

binlog_group_commit_sync_no_delay_count 累积多少次当前才调用 fsync

数据不统一解决方案

为了防止长时间的主从提早,从机应该和主机有雷同的参数、配置,并且要防止大事务

在业务高峰期还是可能存在主从提早导致数据不统一,须要应用一些计划进行防止:

  1. 沟通业务:期待一段时间,比方用户批改完材料后进行审核状态
  2. 强一致性的读也走主库 :这样就不存在主从提早, 使用方便,大量强一致性读操作就会导致主机压力大
  3. 期待从机没提早(三种判断形式):

    • 比拟 seconds_behind_master 是否为 0,为 0 阐明没提早
    • 比拟主从上的位点 Master_Log_File 和 Read_Master_Log_Pos(主库的最新位点)Relay_Master_Log_File 和 Exec_Master_Log_Pos(备库执行的最新位点)判断是否雷同,雷同则没提早
    • 比拟从机上 GTID 汇合 Retrieved_Gtid_Set 和 Executed_Gtid_Set(备库收到的所有日志的 GTID 汇合 和 备库所有曾经执行实现的 GTID 汇合)是否雷同,雷同则没提早

    这个计划粒度大(实际上只须要判断事务是否重做,这里是始终判断是否有提早),如果高峰期始终有提早就会始终期待判断,不应用

  4. 批改主从复制形式为同步复制:数据强一致性,性能差
  5. 批改主从复制形式为半同步复制:一主一从下与同步复制雷同,一主多从下查问不确定,须要判断该事务是否已重做

计划 5 须要做到细粒度的判断事务是否在从机上曾经重做,有两种形式且实现较为简单

判断偏移量

select master_pos_wait(file, pos,[timeout]) 用于判断以后偏移量是否曾经超过该地位

file 为 binlog 文件,pos 为 偏移量,timeout 为期待的工夫

应用半同步复制时,一个从节点曾经响应,其余从节点应该也是快要响应的状态,因而能够期待一段时间 50ms,100ms…

如果超时则能够在业务中再去查主机,要留神如果都超时就相当于又全打在主机上

通过该 SQL 可能以主库日志中偏移量的形式判断是否已执行该事务(已执行返回 0):

  1. 写操作实现时顺便获取 binlog 文件和偏移量的信息
  2. 携带这两个参数加上超时工夫应用该 SQL 判断是否已执行
  3. 如果返回 0(已执行)则查从机,否则查主机(留神限流)

判断 GTID

判断 GTID 的思路与下面类似

select wait_for_executed_gtid_set(gtid_set, [timeout])

SQL 的作用是判断是否曾经执行 GTID 汇合 返回 0,超时返回 1

流程相似:

  1. 写操作时获取 GTID 汇合
  2. 依据 GTID 汇合判断从机是否已执行事务
  3. 已执行查问,否则查主库或限流

主从架构

因为 binlog 的数据复制,主从架构能够十分丰盛,想怎么搭就怎么搭

一主一从:主负责写,从负责读,读写压力平分

一主多从:主负责写,从负责读,适宜读多于写

双主热备:两个节点互为主从,读写压力平分,但存在循环同步的问题

当 AB 节点互为主从时,A 收到写申请,要把 bin log 给 B 重做,B 重做完(相当于写申请)又会把 bin log 给 A 重做,这样就会导致循环同步数据

在同步数据时携带节点的 id(server id)解决循环同步问题

A 收到写申请,binlog 给 B 并携带本人的 id,B 重做完又把 binlog 给 A,A 发现 binlog 上 server id 是本人则不进行重做

总结

本篇文章以 MySQL 高可用为终点,聊到 MySQL 中的主从复制、切换、提早、架构等

binlog 的 statement 格局记录 SQL,数据量小、传输快,但可能导致数据不统一

binlog 的 row 格局记录批改数据,数据量大,传输慢,能够修复误操作数据

binlog 的 mixed 混用 statement、row 的长处,在可用策略的主从切换还是会导致数据不统一

主从复制时主机 dump 线程监听 binlog 变更告诉从机拉取,从机 io 线程将日志写入 realy log 中继日志,再由 sql 线程解析日志重做数据

同步复制须要所有从机响应,领有强一致性,但性能最差

默认的异步复制性能最好,但可能提早时会有数据一致性

半同步复制只须要一个从机响应,多从下性能好于同步复制,网络超时会应用异步复制

加强的半同步复制会在从机响应时才提交事务,相比于半同步复制一致性略好

提早复制能够让从机提早一段时间重做数据,误操作数据能够复原

主从切换时只能满足 CAP 中其二,满足牢靠会导致一段时间不可写,满足可用可能会呈现数据不统一

把从机参数、配置调整为主机雷同,防止应用大事务能够防止主从提早太长

当主从提早太长能够通过调整从机 IO 参数加强 IO 能力

产生主从提早的数据一致性问题时:

  1. 沟通业务,是否应用审核等中间状态,等提早过了再查看
  2. 强制走主机,留神压力可能太大
  3. 应用同步复制,性能差
  4. 应用半同步复制,一主多从下须要判断事务是否执行(偏移量 /GTID),实现艰难

罕用的主从架构有:一主一从、一主多从、双主热备(通过 server id 解决循环同步问题)…

最初(不要白嫖,一键三连求求拉 \~)

本篇文章被支出专栏 MySQL 进阶之路,感兴趣的同学能够继续关注喔

本篇文章笔记以及案例被支出 gitee-StudyJava、github-StudyJava 感兴趣的同学能够 stat 下继续关注喔 \~

有什么问题能够在评论区交换,如果感觉菜菜写的不错,能够点赞、关注、珍藏反对一下 \~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

本文由博客一文多发平台 OpenWrite 公布!

正文完
 0