MySQL数据库高可用方案InnoDBCluster
数据库高可用方案
高可用架构
MySQL的高可用架构无论是社区还是官方,一直在技术上进行探索,这么多年提出了多种解决方案,比如 Google的MMM方案,Facebook的 MHA方案,Mysql官方团队提供的MGR 方案等。
MMM 方案
MMM(Master-Master replication manager for MySQL)是Google技术团队开发的一款比较老的高可用产品,在业内使用的并不多,社区也不活跃,Google很早就不再维护MMM的代码分支。
在2015年之前,美团公司长期使用MMM架构做数据库高可用。
MHA 方案
MHA(MySQL Master High Availability)是由Facebook工程师开发的一款MySQL高可用软件。从名字就可以看出,MHA只负责MySQL主库的高可用。主库发生故障时,MHA会选择一个数据最接近原主库的候选主节点(这里只有一个从节点,所以该从节点即为候选主节点)作为新的主节点,并补齐和之前Dead Master 差异的Binlog。数据补齐之后,即将写VIP漂移到新主库上。
Percona XtraDB Cluster
Percona XtraDB Cluster(简称PXC),是由 Percona 公司推出的mysql集群解决方案。特点是每个节点都能进行读写,且都保存全量的数据。也就是说在任何一个节点进行写入操作,都会同步给其它所有节点写入到自己的磁盘。
InnoDB Cluster
MySQL官方在2017年4月推出了一套完整的、高可用的Mysql解决方案 - MySQL InnoDB Cluster, 即一组MySQL服务器可以配置为一个MySQL集群。在默认的单主节点模式下,集群服务器具有一个读写主节点和多个只读辅节点。辅助服务器是主服务器的副本。客户端应用程序通过MySQL Router连接到主服务程序。如果主服务连接失败,则次要的节点自动提升为主节点,MySQL Router请求到新的主节点。
MySQL InnoDB Cluster 由以下几部分组成:
MySQL Group Replication
:向集群的所有成员复制数据,同时提供容错、自动故障转移和弹性。MySQL Server 5.7.17或更高的版本。MySQL Router
:确保客户端请求是负载平衡的,并在任何数据库故障时路由到正确的服务器。MySQL Shell
:通过内置的管理API创建及管理Innodb集群。

MySQL Shell
MySQL Shell 是MySQL 官方团队打造的一个高级客户端,可以对 MySQL 执行数据操作和管理。它支持通过 JavaScript,Python,SQL 对关系型数据模式和文档型数据模式进行操作。使用它可以轻松配置管理 InnoDB Cluster。
MySQL Shell是开发人员和DBA的统一接口以及InnoDB Cluster的前端管理器。
常用操作
命令 | 别名 | 描述 |
---|---|---|
\help | \h 或 ? | 打印帮助信息 |
\quit | \q 或\exit | 推出MySQL Shell |
\ | 开启SQL模式下的多行模式 | |
\status | \s | 显示当前MySQL Shell的状态 |
\js | 切换到javascript执行模式 | |
\py | 切换到Python执行模式 | |
\sql | 切换到SQL执行模式 | |
\connect | \c | 连接MySQL实例 |
\reconnect | 重连MySQL实例 | |
\disconnect | 断开MySQL连接 | |
\use | \u | 指定要使用的Schema |
\source | . 或 source | 执行脚本文件 |
\warnings | \W | 显示语句产生的警告信息 |
\nowarnings | \w | 不显示语句产生的警告信息 |
\history | 查看和编辑历史命令 | |
\rehash | 手动更新自动名字缓存 | |
\option | 查询和更改MySQL Shell配置选项 | |
\show | 使用提供的选项和参数运行特定的报告 | |
\watch | 使用提供的选项和参数运行特定的报告,并可按照指定的间隔进行刷新结果 | |
\edit | \e | 在默认的系统编辑器中打开命令 |
\page | \P | 分页配置 |
\nopager | 不进行分页 | |
\system | ! | 运行操作系统命令 |
示例:
# 连接mysql
MySQL JS > \connect root@192.168.86.135:33061
dba.checkInstanceConfiguration('root@192.168.86.135:33061') ---检查节点配置是否正常
# 配置实例时也可以指定要创建的集群管理员账号
dba.configureInstance("root@192.168.86.131:3307",{clusterAdmin:"clusteradmin"})
dba.configureLocalInstance(); ---检查/etc/my.cnf是否正常
var cluster = dba.createCluster('myCluster'); ---创建一个名字为myCluster的集群
cluster.addInstance('root@192.168.86.135:33061'); ---集群添加节点
cluster.removeInstance('root@192.168.86.135:33061'); ---移除节点
dba.rebootClusterFromCompleteOutage(); ---重启集群
cluster.rejoinInstance('root@dkf03:3307') ---重新加入此节点到集群
var cluster = dba.getCluster(); -- -查看集群名
cluster.status(); ---查看集群状态
cluster.switch_to_single_primary_mode ---将集群调整为单主架构
cluster.switch_to_multi_primary_mode() ---将集群调整为多主架构
集群部署
# 下载镜像
docker pull mysql:8.0.32
# 启动容器
docker run -d --name mysql-33063 -p 33063:33063 \
--network=mysql-net \
-v /var/data/mysql_3/data:/var/lib/mysql \
-v /var/data/mysql_3/conf.d:/etc/mysql/conf.d \
--restart=always -e MYSQL_ROOT_PASSWORD=root mysql:8.0.32
#
docker stop mysql-33061 && docker stop mysql-33062 && docker stop mysql-33063
docker restart mysql-33061 && docker restart mysql-33062 && docker restart mysql-33063
1.MySQL Shell 连接任意一个节点,比如连接 mysql-33061 节点
# 进入容器中
docker exec -it mysql-33061 /bin/bash
# 使用mysql shell
/usr/bin/mysqlsh
# 连接容器中的msyql,也就是mysql-33061
MySQL JS > \connect root@localhost:3306
2.使用 configureInstance
将所有加入集群的节点的参数配置一遍,如果不符合加入集群的要求,MySQL Shell 会自动识别并询问是否一键修改配置参数,修改完成后重启相应的节点就生效了。
dba.configureInstance("root@192.168.86.99:33061",{clusterAdmin:"clusteradmin"})
# 所有节点都配置完成并且重启后,检查一遍,状态返回OK说明没问题
dba.checkInstanceConfiguration('root@192.168.86.135:33061') ---检查节点配置是否正常
3.三个节点都配置好符合加入集群的参数后,开始加入集群
# 创建一个集群,自动将当前连接的节点加入集群,并且默认是master节点
var cluster = dba.createCluster('myCluster');
# 接着将其他两个节点依次加入到集群中
cluster.addInstance('root@192.168.86.99:33062');
cluster.addInstance('root@192.168.86.99:33063');
注:
- 新节点加入集群后,第一件事就是同步数据,按照Shell 的指示操作就可以;
- 因为容器之间是网络互通的,所以使用容器名称就可以访问另一个容器的mysql,相当于
IP:port
。
4.查看集群状态:
MySQL localhost:3306 ssl JS > cluster.status();
{
"clusterName": "myCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "cbdeaa365467:3306",
"ssl": "REQUIRED",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"74f84ebea3d4:3306": {
"address": "74f84ebea3d4:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.0.32"
},
"cbdeaa365467:3306": {
"address": "cbdeaa365467:3306",
"memberRole": "PRIMARY",
"mode": "R/W",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.0.32"
},
"d0c473f84ec1:3306": {
"address": "d0c473f84ec1:3306",
"memberRole": "SECONDARY",
"mode": "R/O",
"readReplicas": {},
"replicationLag": "applier_queue_applied",
"role": "HA",
"status": "ONLINE",
"version": "8.0.32"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "cbdeaa365467:3306"
}
集群默认为单主模式,一个主节点,两个从节点。
宕机测试:
当我们停掉一个主节点mysql-33061 时,集群依然对完提供正常服务,此时集群的主节点发生变化。当我们重启mysql-33061 后,新加入的节点作为从节点进入集群,宕机期间产生的数据也会在节点恢复后自动同步过来。
数据同步测试:
当我们在主节点新建数据库、新增表、新增行数据、新建索引时,其他两个从库也会自动同步数据。但这些数据变动操作不可以在从库执行,从库只允许读取操作。
重启集群
当我们重启服务器之后,原先部署的集群元数据没有丢失,直接使用命令可以重启集群:
dba.rebootClusterFromCompleteOutage();
注意关闭防火墙
# 查看防火墙状态
[root@localhost ~]# firewall-cmd --state
# 关闭防火墙
[root@localhost ~]# systemctl stop firewalld.service
# 禁止防火墙开机重启
[root@localhost ~]# systemctl disable firewalld.service
# SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME='group_replication_group_name';
Admin API
可以使用MySQL Shell工具AdminAPI来检查集群的状态
MGR
MGR(MySQL Group Replication,MySQL组复制)是MySQL 5.7.17版本(2016 年 12 月)开始引入的,官方推出的高可用解决方案,以服务器插件的形式提供。MGR基于分布式 Paxos 协议,实现组复制,保证数据一致性。内置故障检测和自动选主功能,只要不是集群中的大多数节点都宕机,就可以继续正常工作。提供单主模式与多主模式,多主模式支持多点写入。
功能特性
1.MGR所有节点都有一份完整数据,发生故障时可以直接切换。
2.MGR提供了数据一致性保障,默认是最终一致性,可根据业务特征需要自行调整一致性级别。
3.支持在线添加、删除节点,节点管理更方便。
4.支持故障自动检测及自动切换,发生故障时能自动切换到新的主节点,再配合MySQL Router中间件,应用层无需干预或调整。
5.支持单主节点、多主节点两种模式,可根据架构或业务需要选择哪种方案。
两种模式
每个群组最多具有9个成员,9成员的情况下,最多允许4个成员出现故障。
单主模式
单个MySQL实例作为数据写入的主节点,其它的节点用于热备。这个模式与传统的主从模式相似,当主节点故障时,自动在从节点中选择一个作为新的主节点。
多主模式
多主模式,群组内所有的成员都可以进行数据写入、读取操作。
使用多主模式时,由于数据的写入可以在所有的成员节点上进行,当在不同成员上对同一条记录同时进行更新时,就会产生冲突,此时群组复制会根据成员提交的先后次序(严格来讲是在群组复制的一致性校验阶段,取得校验成功的先后次序)进行判断,后提交事务的执行回滚处理。
冲突检测需要使用主键。
由于多主模式需要确保数据写入的一致性,所以在使用上有如下限制:
- 仅支持innodb 存储引擎
- 表必须有主键,或者非Null 的唯一键。
- 开启Binlog,并且以行的方式记录;
集群部署
使用命令检查事,mysql shell 会逐一检查数据库的每张表是否使用InnoDB 存储引擎并且具有主键或非空唯一键。如果不符合要求,则报错。
Group Replication 要求表使用 InnoDB 并具有 PRIMARY KEY 或 PRIMARY KEY Equivalent(非空唯一键)。 不符合这些要求的表在与组复制一起使用时将可读但不可更新。 如果您的应用程序对这些表进行更新(INSERT、UPDATE 或 DELETE),请确保它们使用 InnoDB 存储引擎并具有 PRIMARY KEY 或 PRIMARY KEY Equivalent。
注:MySQL 8.0.30 新增了sql_generate_invisible_primary_key
参数,参数值设置为 on 时,创建表时如果没有显式定义主键会自动添加一个不可见主键索引。
## sql_generate_invisible_primary_key=on 建的表
mysql> SHOW CREATE TABLE auto_1\G
*************************** 1. row ***************************
Table: auto_1
Create Table: CREATE TABLE `auto_1` (
`my_row_id` bigint unsigned NOT NULL AUTO_INCREMENT /*!80023 INVISIBLE */,
`c1` varchar(50) DEFAULT NULL,
`c2` int DEFAULT NULL,
PRIMARY KEY (`my_row_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
该设计有以下特性:
- 自动创建不可见主键,关键点在于”INVISIBLE” 关键字,那么
select * from xxx
出来的结果和之前是兼容的,不会多出来my_row_id
列。 - 如果表本身有主键,那么就不会自动创建主键。
- 如果建表时没有显式指定主键,建表时请勿包含列名叫
my_row_id
的列,因为 GIPK 模式自动创建的不可见主键列固定就叫做my_row_id
,会有冲突导致创建表失败。 - GIPK 功能只在新建表时触发,如果表已经建了并且没有主键,请自行解决或重建表。
他解决了卡住很多人上车 MGR 的一个硬性要求,表必须要有主键!实际上,没有主键在主从架构甚至单机架构也是不建议的,现在 GIPK 这个特性可以让那些懒惰的开发再也无法阻拦 MGR 的崛起。
脑裂处理
使用MGR不会出现脑裂问题,MGR会检测网络分区。
发生网络分区时,如果部分成员检测到大多数成员丢失,连接到这部分成员的数据更新处理将被挡住并等待,Select可以执行。假设一个包含五个节点的集群,S1 S2与其余三个成员失去联系,对于S1 S2来说他们已经丢失了群组中的大部分成员,因此不能够在它们上面执行数据更新处理(S3 S4 S5上面可以进行数据更新,当网络故障恢复后,S1 S2可以从S3 S4 S5上获取故障期间未更新的数据)。
数据一致性
MGR是通过日志的传播和施放来进行群组内所有成员的数据同步,因此,在某一时间点各个成员上数据是会出现不一致的情况(最终会一致)。在MySQL8.0.14之后,可以通过使用变量 group_replication_consistency
精确地控制每个节点上数据的一致性。
数据恢复
当之前的故障节点恢复或者新节点加入集群时,第一件事就是进行数据恢复。
增量恢复
恢复时,可以采用增量恢复,增量恢复基于异步复制实现,只提取基于GTID 的丢失数据。
增量恢复可能会需要相当长的时间,并且当群组无法提供全部的binlog时,无法进行恢复,也就无法加入集群中。
所以当部分binlog被清理,而新节点还没有数据时,该怎么办呢,我们可以选择Clone 插件!(8.0.17开始提供)
MySQL Clone Plugin
MySQL Clone Plugin:
- 执行数据库的物理快照
- 通过网络将快照传递给服务器
- 替换服务器的全部数据
使用克隆部署解决的问题:
- 巨大的数据集
- 不完整的二进制日志
- 重新部署实例
MySQL Router
MySQL Router目前仍在成长中,如果你只需要负载均衡与主备,那么LVS性能更高,Haproxy也更成熟。
国内使用MySQL Router的案例非常少,所以MySQL Router我们还是只做了解,把精力放在比他更成熟的方案上。
MGR 保证数据库服务持续可用,但是当其中一个组成员变得不可用时,MGR 本身并不处理与客户端的容错关系,此时连接到该节点的客户端必须使用负载均衡器、路由器或某种形式的中间件。MySQL 官方团队提供 MySQL Router 来处理该问题 。
MySQL Router是一个轻量级的中间件,可以提供客户端负载均衡和应用连接的故障转移。通过使用Router 和 Shell,用户可以利用MGR实现完整的数据库层的解决方案。如果您在使用MGR,请一定配合使用Router和Shell。
- 读写分离
- 读负载均衡
- 故障自动转移
Router作为一个流量转发层,位于应用与MySQL服务器之间,其功能类似于LVS。应用不再直连MySQL Servers,而是与Router相连。根据Router的配置,将会把应用程序的读写请求转发给下游的MySQL Servers。
考虑到Router独立部署可能引入“额外的部署成本”、“性能降级”、“连接数上限”等问题,通常建议基于“Agent”方式部署,即将Router与应用程序部署在同一台机器上。
Router中间件本身不会对请求“拆包”,所以无法在Router中间件上实现比如“SQL审计”、“隔离”、“限流”、“分库分表”等功能。
MySQL Operator
MySQL Operator for Kubernetes 是一个用于管理 Kubernetes 集群内的 MySQL InnoDB 集群设置的运营商。 它通过设置和维护管理整个生命周期,包括自动升级和备份。
MySQL Operator for Kubernetes 由 Oracle 的 MySQL 团队开发。
InnoDB Cluster Set
Mysql 8.0.27 版本开始提供InnoDB Cluster Set 功能。
MySQL InnoDB ClusterSet 为 InnoDB Cluster 部署提供容灾能力。InnoDB ClusterSet 使用专用的 ClusterSet 复制通道自动管理从主集群到副本集群的复制。如果主集群由于数据中心损坏或网络连接丢失而变得无法使用,用户可以激活副本集群以恢复服务的可用性。
限制
- InnoDB ClusterSet 优先考虑可用性而不是一致性,以最大限度地提高容灾能力。如果用户不能容忍故障转移期间事务或数据的任何丢失,那么不要使用 InnoDB ClusterSet ,可以考虑使用单个 InnoDB Cluster。
- InnoDB Cluster必须使用单主模式。
- InnoDB ClusterSet 不会自动故障转移到副本集群。需要管理员确认后执行操作。
- InnoDB ClusterSet 只支持异步复制,不能使用半同步复制。
README
作者:
2023-03-04 银法王 第一次修订
参考: