在 Meta 构建和部署 MySQL Raft( 二 )


文章插图
 
MySQL Raft 复制拓扑一个 Raft 环将由不同区域的多个 MySQL 实例(图中有四个)组成 。这些区域之间的通信往返时间 (RTT) 范围为 10 到 100 毫秒 。这些 MySQL 中的一些(通常是三个)被允许成为主要的,而其余的只允许成为纯读取副本(不具备主要能力) 。Meta 的 MySQL 部署也对极低延迟提交有着长期的需求 。使用 MySQL 作为存储的服务(例如,社交图谱)需要或已经设计为如此极快的写入 。
为了满足这一要求,FlexiRaft 的配置将仅使用区域内提交(单区域动态模式) 。为了实现这一点,每个主要的有能力的区域将有两个额外的 logtailer(见证或仅日志实体) 。写入的数据法定人数为 2/3(1 个 MySQL + 2 个 logtailer 中的 2 个 ACK?) 。Raft 仍然会管理和运行跨所有实体的复制日志(1 个具有主功能的 MySQL + 2 个 logtailers)* 3 个区域 +(不具有主功能的 MySQL)* 3 个区域 = 12 个实体 。
Raft roles:leader,顾名思义,就是复制日志的一个term中的leader 。Raft 中的领导者也将是 MySQL 中的主要领导者,并且接受客户端写入 。follower 是环中的投票成员,被动接收来自 leader 的消息( AppendEntries ) 。从 MySQL 的角度来看,跟随者将是一个副本,并将事务应用于其引擎 。它不允许从用户连接直接写入(设置了 read_only=1) 。学习者将是环中的非投票成员,例如,非主要功能区域中的三个 MySQL(上图) 。从 MySQL 的角度来看,它将是一个副本 。

在 Meta 构建和部署 MySQL Raft

文章插图
 
复制日志对于复制,MySQL 历来使用二进制日志格式 。这种格式是 MySQL 复制的核心,我们决定保留它 。从 Raft 的角度来看,二进制日志变成了复制日志 。这是通过对 kuduraft 的日志抽象改进完成的 。MySQL 事务将被编码为一系列事件(例如,Update Rows 事件),每个事务都有开始和结束 。二进制日志也有适当的标题,通常以结束事件(轮换事件)结束 。
我们不得不调整 MySQL 在内部管理其日志的方式 。在主节点上,Raft 会写入二进制日志 。这与标准 MySQL 中发生的情况没有什么不同 。在副本中,Raft 还会写入二进制日志,而不是标准 MySQL 中的单独中继日志 。这为 Raft 创造了简单性,因为 Raft 只关心一个日志文件的命名空间 。如果一个追随者被提升为领导者,它可以无缝地返回到它的日志历史记录中,将交易发送给落后的成员 。副本的应用程序线程将从二进制日志中获取事务,然后将它们应用到引擎 。在此过程中,将创建一个新的日志文件,即应用日志 。此应用日志将在副本的崩溃恢复中发挥重要作用,但在其他方面是非复制日志文件 。
所以,总结一下:
在标准 MySQL 中:
  • Primary 写入 binlog 并将 binlog 发送到 replicas 。
  • 副本在中继日志中接收并将事务应用到引擎 。在应用期间,将创建一个新的仅限副本的二进制日志 。
在 MySQL 筏中:
  • Primary 通过 Raft 写入 binlog,Raft 将 binlog 发送给 followers/replicas 。
  • 副本/跟随者在二进制日志中接收并将事务应用到引擎 。在申请期间创建申请日志 。
  • Binlog 从 Raft 的角度来看就是复制的日志 。
使用 Raft 在 MySQL primary 上写入事务【在 Meta 构建和部署 MySQL Raft】事务将首先在引擎中准备好 。这将发生在用户连接的线程中 。准备交易的行为将涉及与存储引擎(例如InnoDB或MyRocks)的交互,并为交易生成内存中的二进制日志有效负载 。在提交时,写入将通过group commit /ordered_commit 流程 。将分配 GTID,然后 Raft 将分配一个 OpId (term:index) 给交易 。此时,Raft 会将事务压缩,存储在自己的 LogCache 中,并通过事务写入一个 binlog 文件 。它将异步开始将交易发送给其他追随者以获得 ACK 并达成共识 。
处于事务“提交”状态的用户线程将被阻塞,等待来自 Raft 的共识 。当 Raft 获得三分之二的区域投票时,就会达成共识提交 。Raft 还会将交易发送给所有区域外的成员,但会因为称为 FlexiRaft 的算法(如下所述)而忽略他们的投票 。在一致提交时,用户线程将被解除阻塞,事务将继续并提交给引擎 。引擎提交后,写入查询将完成并返回给客户端 。不久之后,Raft 也会异步发送一个提交标记(当前提交的 OpId)给下游的追随者,这样他们也可以将事务应用到他们的数据库中 。
在 Meta 构建和部署 MySQL Raft


推荐阅读