MySQL InnoDB Cluster高可用实践
读写分离是一种常见的数据库优化技术,通过将读操作和写操作分别路由到不同的数据库实例,可以显著提升系统的数据吞吐性能,提高数据库服务性能,避免业务系统因单点故障导致不可用。可以通过多台弹性云服务器搭建高可用数据库集群,利用代理服务实现灵活调度和读写分离。
背景介绍
在搭建MySQL服务集群时使用多个可用区的弹性云服务器,可以降低单可用区内节点故障时业务中断的风险。本文用4台弹性云服务器搭建MySQL高可用数据库集群,其中1台作为代理节点,1台作为主节点(配置读写权限),2台作为备节点(配置只读权限)。
前提条件
- 购买4台弹性云服务器(以Huawei Cloud EulerOS 2.0操作系统为例),归属于同一个VPC下,其中代理节点、主节点、备节点分属三个子网。且4台云服务器都需要绑定弹性公网IP。
- 1台MySQL主节点和2台MySQL备节点需要安装MySQL服务,且版本一致,若未安装MySQL,可参考数据库部署概述。
操作步骤
- 设置集群节点。
- 远程连接MySQL主节点、MySQL备节点,参考Linux ECS登录方式概述。
- 为三台MySQL节点创建一个用于集群通信的MySQL用户,用户名和密码应一致。
密码建议设置高强度密码,即长度大于8个字符,且包含大小写字符、数字、特殊字符。
#执行后需要输入root用户密码 sudo mysql -uroot -p \ -e "CREATE USER '<username>'@'%' IDENTIFIED BY '<password>';" \ -e "GRANT ALL PRIVILEGES ON *.* TO '<username>'@'%' WITH GRANT OPTION;" \ -e "FLUSH PRIVILEGES;"
- 在三台MySQL节点的MySQL配置文件/etc/my.cnf中添加如下内容,其中server_id的值需要注意每个节点配置一个不同的值。
#设置主机名为节点的IP地址 report_host=192.168.x.x #开启GTID强一致性 enforce_gtid_consistency=ON gtid_mode=ON #设置节点服务ID,此值需要每个节点唯一正整数 server_id=1 #设置每个节点最大连接数,需要确保每个节点值统一 max_connections=1024 #禁用InnoDB以外的存储引擎 disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
- 重启三台MySQL节点的MySQL服务,使配置生效。
sudo systemctl restart mysqld
- 创建集群。
- 远程连接代理节点,参考Linux ECS登录方式概述。
- 为代理节点安装mysql-shell、mysql-router。
#添加MySQL官方源 sudo rpm -Uvh https://repo.mysql.com/mysql84-community-release-el8-1.noarch.rpm #安装mysql-shell、mysql-router sudo dnf install -y mysql-shell mysql-router mysql-community-client
- 通过MySQL Shell连接到MySQL主节点,将username替换为MySQL的用户名,IP替换为主节点的IP地址,执行后输入密码,并询问是否需要保存密码,保存后无需再次输入密码。
mysqlsh --js <username>@<IP>:3306
- 执行以下命令,对MySQL节点进行初始化配置,<username>和<IP>分别替换为节点的MySQL用户名和IP地址,每个MySQL节点都需要执行一遍。
dba.configureInstance('<username>@<IP>:3306')
- 检查节点是否可加入cluster,<username>和<IP>分别替换为节点的MySQL用户名和IP地址。
dba.checkInstanceConfiguration('<username>@<IP>:3306')
可加入时回显如下,status提示ok。
- 创建集群,自定义集群名称替换cluster_name后执行。
var cluster = dba.createCluster('<cluster_name>')
- 为集群添加从节点,username替换为MySQL的用户名,IP替换为不同的从节点IP地址,每个从节点都需要添加一遍,recovery method默认选择Clone。
cluster.addInstance('<username>@<IP>:3306')
输出信息如下,表示添加成功。
- 查看集群状态。
cluster.status()
输出信息如下,表示集群创建完成。
- 配置完成后可以输入\q退出mysqlsh程序。
- 设置代理节点。
- 远程连接代理节点,参考Linux ECS登录方式概述。
- 执行命令初始化地理设置,将username替换为MySQL的用户名,IP替换为主节点的IP地址,执行后输入密码。
sudo mysqlrouter --bootstrap <username>@<IP>:3306 --directory /mnt/mysqlrouter \ --conf-bind-address 0.0.0.0 --user=mysqlrouter
- 编辑mysqlrouter服务文件。
/mnt/mysqlrouter是默认目录,若修改了目录,需要同步修改ExecStart和ExecStop路径。
sudo tee /usr/lib/systemd/system/mysqlrouter.service <<-'EOF' [Unit] Description=MySQL Router Service After=network.target [Service] User=mysqlrouter Group=mysqlrouter Type=forking ExecStart=/mnt/mysqlrouter/start.sh ExecStop=/mnt/mysqlrouter/stop.sh Restart=on-failure StandardOutput=journal [Install] WantedBy=multi-user.target EOF
- 执行命令启动服务。
#刷新服务文件 sudo systemctl daemon-reload #启动mysqlrouter sudo systemctl start mysqlrouter.service #设置mysqlrouter开机自启 sudo systemctl enable mysqlrouter.service #查看服务状态 sudo systemctl status mysqlrouter.service
- (可选)验证集群。
模拟MySQL主节点故障,验证集群是否能够自动切换节点提供服务。
- 远程连接代理节点,参考Linux ECS登录方式概述。
- 使用MySQL客户端连接到代理节点,<username>替换为MySQL的用户名,执行后输入MySQL密码。
mysql -h127.0.0.1 -P6450 -u<username> -p
- 执行sql语句查看集群状态,结果显示3个节点在线,其中一个是主节点。
SELECT * FROM performance_schema.replication_group_members;
- 执行SQL语句添加测试库和测试表。
-- 1. 创建数据库 CREATE DATABASE test_db; -- 2. 使用数据库 USE test_db; -- 3. 创建表:test_table CREATE TABLE test_table ( id INT AUTO_INCREMENT PRIMARY KEY, -- 自增主键 name VARCHAR(100) NOT NULL, -- 名称 age INT NOT NULL ); -- 4. 添加记录到 test_table INSERT INTO test_table (name, age) VALUES ('A', 5), ('B', 25); -- 5. 查看添加到test_table的信息(可选) select * from test_table;
- 停止MySQL主节点,模拟宕机事件。
- 等待MySQL主节点停止后,再次执行SQL语句查看集群状态,发现两个节点在线,且从节点已自动切换为主节点。
SELECT * FROM performance_schema.replication_group_members;
- 执行SQL语句查询数据查看是否有丢失数据。
select * from test_table;
- 启动MySQL主节点模拟宕机恢复。
- 执行SQL语句查看集群状态,结果显示三个节点在线,且主节点自动加入集群。
SELECT * FROM performance_schema.replication_group_members;
- (可选)集群添加节点。
在MySQL集群中,需要扩展集群或应对节点宕机时,可通过mysql-shell连接集群并使用addInstance命令添加新节点,新节点会自动同步数据。
- 远程连接代理节点,参考Linux ECS登录方式概述。
- 通过mysql-shell连接到集群中任意节点,使用MySQL客户端连接到代理节点,<username>替换为MySQL的用户名,<IP>替换为节点IP地址,执行后输入MySQL密码。
mysqlsh --js <username>@<IP>:3306
- 获取集群。
var cluster = dba.getCluster()
- 为集群添加节点,将<username>替换为MySQL用户名,<IP>替换为节点IP地址。
cluster = dba.addInstance('<username>@<IP>:3306')
通过以下命令查看cluster情况,可以观察到新扩容的节点情况。
cluster.status()
如需移出节点,可使用以下命令,根据将<username>和<IP>替换为需要移出的节点信息。
cluster.removeInstance('<username>@<IP>:3306')
回显类似如下信息。
- (可选)指定集群主节点。
在MySQL集群中,若主节点宕机,系统会自动从剩下的从节点中选举出新的主节点,如需手动指定主节点,可以通过mysql-shell连接集群,使用setPrimaryInstance命令设置主节点。
- 远程连接代理节点,参考Linux ECS登录方式概述。
- 通过mysql-shell连接到集群中任意节点,使用MySQL客户端连接到代理节点,<username>替换为MySQL的用户名,<IP>替换为节点IP地址,执行后输入MySQL密码。
mysqlsh --js <username>@<IP>:3306
- 获取集群。
var cluster = dba.getCluster()
- 为集群设置目标主节点,将<username>替换为MySQL用户名,<IP>替换为节点IP地址。
cluster.setPrimaryInstance ('<username>@<IP>:3306')
回显如下类似信息,表示设置成功。