简介
MySQL InnoDB Cluster(集群)为 MySQL 提供了完整的高可用性解决方案。通过使用 MySQL Shell中包含的 AdminAPI,可以轻松配置和管理一组至少三个 MySQL 服务器实例,以充当 InnoDB Cluster。
InnoDB Cluster 中的每个 MySQL 服务器实例都运行 MySQL Group Replication(组复制),它提供了在 InnoDB Cluster 内复制数据的机制,并具有内置的故障转移功能。
InnoDB Cluster概览
InnoDB Cluster建立在组复制之上,提供了自动成员管理、容错、自动故障转移等功能。InnoDB Cluster 通常以单主模式运行,具有一个主节点(读写)和多个从节点(只读)。还可以利用多主模式让其中所有节点都是主节点。甚至可以在线更改在 InnoDB Cluster 的拓扑,以确保尽可能高的可用性。
要开始使用 InnoDB Cluster,需要下载并安装MySQL Shell,同时还需要一些安装了 MySQL Server 实例的服务器。
前置工作
服务器信息
| 内网IP | HostName映射 |
|------------|---------------|
| 172.27.8.1 | mysql-node-01 |
| 172.27.8.2 | mysql-node-02 |
| 172.27.8.3 | mysql-node-03 |
| 172.27.8.4 | mysql-node-04 |
配置IP与HostName映射的绑定关系
1> 按照上面服务器信息,修改IP地址对应的HostName,登录每一个服务器,修改为对应的映射
vi /etc/hostname
2> 在每一台服务器的hosts文件夹中添加IP与HostName映射的绑定关系
vi /etc/hosts
内容如下:
172.27.8.1 mysql-node-01 mysql-node-01
172.27.8.2 mysql-node-02 mysql-node-02
172.27.8.3 mysql-node-03 mysql-node-03
172.27.8.4 mysql-node-04 mysql-node-04
安装MySQL8.0
为每一台服务器安装MySQL8.0并设置相同的root密码,在my.cnf中设置server-id,确保每台服务器的server-id不重复。
具体安装步骤可以查看《Ubutun20.04编译安装MySQL8.0.28》
InnoDB 集群要求
由于是InnoDB 集群,故数据库中的所有表都需要使用InnoDB 存储引擎。
可以通过设置系统变量disabled_storage_engines
来防止使用其他存储引擎,例如:
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
更多要求可以查看官方文档:《组复制要求》、《InnoDB 集群要求》
Innodb 集群的限制
InnoDB Cluster建立在组复制之上,组复制节点的 MySQL 服务器的最大数量是 9。也就意味着Innodb 集群最多可以容纳9台 MySQL 实例。
更多限制可以查看官方文档
安装MySQL Shell 8.0
只需要在 mysql-node-01
上安装即可。
MySQL Shell简介
MySQL Shell 是 MySQL 的客户端命令行工具。通过在该工具中执行命令可以简便的配置 InnoDB 集群,使配置工作不在那么繁琐。
添加APT存储库
首先,将 MySQL APT 存储库添加到系统的软件存储库列表中。
下载发行包:https://dev.mysql.com/downloads/repo/apt/
cd /home
wget https://repo.mysql.com//mysql-apt-config_0.8.23-1_all.deb
使用以下命令安装下载的发行包:
dpkg -i /home/mysql-apt-config_0.8.23-1_all.deb
更新包信息
apt-get update
安装
apt-get install mysql-shell
检验安装结果
mysqlsh --version
正确输出版本号则代表安装成功。
配置实例
mysqlsh
mysql-js> dba.configureInstance('root@localhost:3306')
连接后弹出提示需要开启GTID,输入y开启即可:
检查实例配置是否适合InnoDB Cluster
mysql-js> dba.checkInstanceConfiguration('root@localhost:3306')
创建 InnoDB 集群
登录MySQL实例
方法一:
mysqlsh --uri=mysql://root@localhost:3306
更多关于--uri
的用法可参考官方文档
方法二:
mysqlsh
MySQL JS > \connect root@localhost:3306
或
MySQL JS > shell.connect('root@localhost:3306')
创建 InnoDB 集群
mysql-js> var cluster = dba.createCluster('testCluster')
要检查集群是否已创建
mysql-js> cluster.status()
添加实例至 InnoDB 集群
InnoDB Cluster 中至少需要三个实例,以使其能够容忍一个实例的故障。添加更多实例会增加对 InnoDB Cluster 故障的容忍度。
修改server-id
确保要添加的实例的server-id与之前的不同。
配置实例
mysqlsh
MySQL JS > dba.configureInstance('root@172.27.8.2:3306')
连接后弹出提示需要开启GTID,输入y开启即可:
检查实例状态
cluster.checkInstanceState()用于验证实例上的现有数据不会阻止其加入集群。
mysqlsh --uri=mysql://root@localhost:3306
mysql-js> var cluster=dba.getCluster()
mysql-js> cluster.checkInstanceState('root@172.27.8.2:3306')
可以将状态为 OK 的实例添加到集群中,因为该实例上的任何数据都与集群一致。换句话说,被检查的实例没有执行任何与集群执行的 GTID 冲突的事务,并且可以恢复到与其他集群实例相同的状态。
更多状态解释可以参考官方文档
添加实例至 InnoDB 集群
mysql-js> cluster.addInstance('root@172.27.8.2:3306')
添加成功的正确提示:
如果出现如下错误信息:
则需要先在该节点服务器添加IP与HostName映射的绑定关系。
通过以上方法,将mysql-node-02
和mysql-node-03
都加入集群,留一个mysql-node-04
先不加入。
集群测试
此时通过cluster.status()
指令可以查看集群状态,其中memberRole
为PRIMARY
的为主节点,只有该节点可以写入,其余节点只能读,无法写入。
可以连接主节点进行增伤改查测试,可以发现从节点也会同步执行。
集群加入新节点测试
mysql-node-01
是主节点,可以在该节点导入一些数据用作测试,模拟当前集群(3个节点)已运行一段时间。现在需要加入一个全新的节点mysql-node-04
,新节点是新安装的mysql实例,里面没有任何业务数据。
经测试,加入mysql-node-04
节点后,该节点会自动从之前的集群中克隆数据并开启同步,不需要再手动导入备份的数据。
mysql shell 常用命令
| 操作 | 方法示例 |
|--------------|-------------------------------------------------------------------------------------|
| 连接实例 | \connect root@localhost:3306
|
| 检测实例状态 | dba.checkInstanceConfiguration('root@172.27.8.2:3306')
|
| 退出 | \quit
|
| 自动修正实例设置 | dba.configureInstance('root@172.27.8.2:3306')
|
| 删除集群元数据 | dba.dropMetadataSchema()
|
| 创建集群 | var cluster = dba.createCluster('clusterTest')
|
| 获取集群 | var cluster = dba.getCluster()
|
| 向集群中添加实例 | cluster.addInstance('root@172.27.8.2:3306')
|
| 从集群中删除实例 | cluster.removeInstance('root@172.27.8.2:3306')
|
| 从集群中删除实例(强制) | cluster.removeInstance('root@172.27.8.2:3306',{force:true})
|
| 查看集群状态 | cluster.status()
|
| 查看集群描述 | cluster.describe()
|
| 重启集群 | var cluster = dba.rebootClusterFromCompleteOutage()
|
| 解散集群 | cluster.dissolve({force:true})
|
| 指定一个新的主节点 | cluster.setPrimaryInstance('root@172.27.8.2:3306')
|
| 切换到多主模式 | cluster.switchToMultiPrimaryMode()
|
| 切换到单主模式 | cluster.switchToSinglePrimaryMode('root@172.27.8.2:3306')
|
| 更改集群设置 | cluster.setOption('clusterName','newCluster')
|
| 更改集群实例设置 | cluster.setInstanceOption('root@172.27.8.2:3306', 'exitStateAction', 'READ_ONLY')
|
常见问题
metadata exists, instance belongs to that metadata, but GR is not active {#metadata_exists_instance_belongs_to_that_metadata_but_GR_is_not_active}
执行命令var cluster = dba.getCluster()
时报:
Dba.getCluster: This function is not available through a session to a standalone instance (metadata exists, instance belongs to that metadata, but GR is not active) (MYSQLSH 51314)
此时可尝试重启集群:
dba.rebootClusterFromCompleteOutage()
若依然不能解决,则登录MySQL,然后启动该节点的group replication:
set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;
卡在Cancelling active GR auto-initialization at xxx 一直不动
当所有mysql节点都重启后,使用dba.rebootClusterFromCompleteOutage()重启集群时,会卡在Cancelling active GR auto-initialization at xxx
。
可以通过在所有节点执行pkill -9 mysqld
来模拟这种情况。然后在所有节点启动mysql服务。在其中某个节点执行dba.rebootClusterFromCompleteOutage()
时,会一直卡在Cancelling active GR auto-initialization at xxx
。
此时可以尝试重启服务器后,重新执行dba.rebootClusterFromCompleteOutage()
命令,也许可以成功重启集群。如果实现不行,就说明群集元数据已严重损坏,则可能需要删除元数据并从头开始重新创建群集。可以先在各服务器使用dba.dropMetadataSchema()
删除集群元数据,然后重新创建集群。