6.1 三种集群架构
6.1.1 MMM架构
需要基础资源:
| 资源 | 数量 | 说明 |
|---|---|---|
| 主DB | 2 | 用于主备模式的主主复制 |
| 从DB | 0~N台 | 可以根据需要配置N台从服务器 |
| IP地址 | 2n+1 | N为MySQL服务器的数量 |
| 监控用户 | 1 | 用户监控数据库状态的MySQL用户(replication) |
| 代理用户 | 1 | 用于MMM代理端改变read_only状态 |
故障转移步骤:
-
Slave服务器上的操作
- 完成原主上已经复制的日志恢复
- 使用Change Master命令配置新主
-
主服务器上操作
- 设置read_only关闭
- 迁移VIP到新主服务器
优点:
- 提供了读写VIP的配置,试读写请求都可以达到高可用
- 工具包相对比较完善,不需要额外的开发脚本
- 完成故障转移之后可以对MySQL集群进行高可用监控
缺点:
- 故障简单粗暴,容易丢失事务,建议采用半同步复制方式,减少失败的概率
- 目前MMM社区已经缺少维护,不支持基于GTID的复制
适用场景:
- 读写都需要高可用的
- 基于日志点的复制方式
6.1.2 MHA架构
需要资源:
| 资源 | 数量 | 说明 |
|---|---|---|
| 主DB | 2 | 用于主备模式的主主复制 |
| 从DB | 2~N台 | 可以根据需要配置N台从服务器 |
| IP地址 | n+2 | N为MySQL服务器的数量 |
| 监控用户 | 1 | 用户监控数据库状态的MySQL用户(replication) |
| 复制用户 | 1 | 用于配置MySQL复制的用户 |
MHA采用的是从slave中选出Master,故障转移:
-
从服务器:
- 选举具有最新更新的slave
- 尝试从宕机的master中保存二进制日志
- 应用差异的中继日志到其它的slave
- 应用从master保存的二进制日志
- 提升选举的slave为master
- 配置其它的slave向新的master同步
优点:
- MHA除了支持日志点的复制还支持GTID的方式
- 同MMM相比,MHA会尝试从旧的Master中恢复旧的二进制日志,只是未必每次都能成功。如果希望更少的数据丢失场景,建议使用MHA架构。
缺点:
- MHA需要自行开发VIP转移脚本。
- MHA只监控Master的状态,未监控Slave的状态
6.1.3 MGR架构
MGR是基于现有的MySQL架构实现的复制插件,可以实现多个主对数据进行修改,使用paxos协议复制,不同于异步复制的多Master复制集群。
支持多主模式,但官方推荐单主模式:
- 多主模式下,客户端可以随机向MySQL节点写入数据
- 单主模式下,MGR集群会选出primary节点负责写请求,primary节点与其它节点都可以进行读请求处理。
// 查看MGR的组员
select * from performance_schema.replication_group_members;
// 查看MGR的状态
select * from performance_schema.replication_group_member_stats;
// 查看MGR的一些变量
show variables like 'group%';
// 查看服务器是否只读
show variables like 'read_only%';复制代码
优点:
- 基本无延迟,延迟比异步的小很多
- 支持多写模式,但是目前还不是很成熟
- 数据的强一致性,可以保证数据事务不丢失
缺点:
- 仅支持innodb
- 只能用在GTID模式下,且日志格式为row格式
适用的业务场景:
- 对主从延迟比较敏感
- 希望对对写服务提供高可用,又不想安装第三方软件
- 数据强一致的场景
6.2 主从复制
备库 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 读取中转日志,解析出日志里的命令,并执行。
6.3 主备延迟分析
6.3.1 主备延迟seconds_behind_master
与数据同步有关的时间点主要包括以下三个:
- 主库 A 执行完成一个事务,写入 binlog,我们把这个时刻记为 T1;
- 之后传给备库 B,我们把备库 B 接收完这个 binlog 的时刻记为 T2;
- 备库 B 执行完成这个事务,我们把这个时刻记为 T3。
所谓主备延迟,就是同一个事务,在备库执行完成的时间和主库执行完成的时间之间的差值,也就是 T3-T1。你可以在备库上执行 show slave status 命令,它的返回结果里面会显示 seconds_behind_master,用于表示当前备库延迟了多少秒。
6.3.2 主备延迟的来源
- 备库性能差
- 备库的压力大
- 大事务,主库上必须等事务执行完成才会写入 binlog,再传给备库
- SQL Thread主从复制都是单线程的操作,当主库的并发较高时,产生的DML数量超过slave的SQL Thread所能处理的速度,或者当slave中有大型query语句产生了锁等待那么延时就产生了
- binlog是顺序写,效率很高。Slave的SQL Thread线程将主库的DDL和DML操作事件在slave中重放时操作是随机的,处理速度慢
6.3.3 解决主备延迟方案
-
优化网络
-
升级Slave硬件配置
-
Slave调整参数,关闭binlog,修改innodb_flush_log_at_trx_commit参数值
-
升级MySQL版本到5.7,使用并行复制
6.3.4 解决主从数据丢失问题
1.半同步复制
从MySQL5.5开始,MySQL已经支持半同步复制了,半同步复制介于异步复制和同步复制之间,主库在执行完事务后不立刻返回结果给客户端,需要等待至少一个从库接收到并写到relay log中才返回结果给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一个TCP/IP往返耗时的延迟。
2.主库配置sync_binlog=1,innodb_flush_log_at_trx_commit=1
sync_binlog的默认值是0,MySQL不会将binlog同步到磁盘,其值表示每写多少binlog同步一次磁盘。
innodb_flush_log_at_trx_commit为1表示每一次事务提交或事务外的指令都需要把日志flush到磁盘。
6.4 主备切换策略
6.4.1 可靠性优先策略
双M结构切换
- 判断备库 B 现在的 seconds_behind_master,如果小于某个值(比如 5 秒)继续下一步,否则持续重试这一步;
- 把主库 A 改成只读状态,即把 readonly 设置为 true;
- 判断备库 B 的 seconds_behind_master 的值,直到这个值变成 0 为止;
- 把备库 B 改成可读写状态,也就是把 readonly 设置为 false;把业务请求切到备库 B。
6.4.2 可用性优先策略
可用性优先策略,且 binlog_format=mixed 时的切换流程
- 步骤 2 中,主库 A 执行完 insert 语句,插入了一行数据(4,4),之后开始进行主备切换。
- 步骤 3 中,由于主备之间有 5 秒的延迟,所以备库 B 还没来得及应用“插入 c=4”这个中转日志,就开始接收客户端“插入 c=5”的命令。
- 步骤 4 中,备库 B 插入了一行数据(4,5),并且把这个 binlog 发给主库 A。
- 步骤 5 中,备库 B 执行“插入 c=4”这个中转日志,插入了一行数据(5,4)。而直接在备库 B 执行的“插入 c=5”这个语句,传到主库 A,就插入了一行新数据(5,5)。
在实际的应用中,建议使用可靠性优先的策略。毕竟保证数据准确,应该是数据库服务的底线。在这个基础上,通过减少主备延迟,提升系统的可用性。
7.参考文章
极客时间-MySQL实战45讲
time.geekbang.org/column/intr…
Innodb架构
数据结构在线查看