# MySQL InnoDB Cluster高可用实践
读写分离是一种常见的数据库优化技术，通过将读操作和写操作分别路由到不同的数据库实例，可以显著提升系统的数据吞吐性能，提高数据库服务性能，避免业务系统因单点故障导致不可用。可以通过多台弹性云服务器搭建高可用数据库集群，利用代理服务实现灵活调度和读写分离。
#### 背景介绍
在搭建MySQL服务集群时使用多个可用区的弹性云服务器，可以降低单可用区内节点故障时业务中断的风险。本文用4台弹性云服务器搭建MySQL高可用数据库集群，其中1台作为代理节点，1台作为主节点（配置读写权限），2台作为备节点（配置只读权限）。
#### 前提条件
- 购买4台弹性云服务器（以Huawei Cloud EulerOS 2.0操作系统为例），归属于同一个VPC下，其中代理节点、主节点、备节点分属三个子网。且4台云服务器都需要绑定弹性公网IP。
- 1台MySQL主节点和2台MySQL备节点需要安装MySQL服务，且版本一致，若未安装MySQL，可参考[数据库部署概述](https://support.huaweicloud.com/bestpractice-ecs/ecs_bp_0501.html)。
  ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444496321.png "点击放大")
  
 
#### 操作步骤
1. 设置集群节点。
   
   1. 远程连接MySQL主节点、MySQL备节点，参考[Linux ECS登录方式概述](https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0013771089.html)。
   
   2. 为三台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;"
      ```
      
   
   3. 在三台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"
      ```
      
   
   4. 重启三台MySQL节点的MySQL服务，使配置生效。
      ```
      sudo systemctl restart mysqld
      ```
      
   
   
   
   
2. 创建集群。 
   1. 远程连接代理节点，参考[Linux ECS登录方式概述](https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0013771089.html)。
   
   2. 为代理节点安装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
      ```
      
   
   3. 通过MySQL Shell连接到MySQL主节点，将username替换为MySQL的用户名，IP替换为主节点的IP地址，执行后输入密码，并询问是否需要保存密码，保存后无需再次输入密码。
      ```
      mysqlsh --js <username>@<IP>:3306
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002443880589.png "点击放大")
      
   
   4. 执行以下命令，对MySQL节点进行初始化配置，\<username\>和\<IP\>分别替换为节点的MySQL用户名和IP地址，每个MySQL节点都需要执行一遍。
      ```
      dba.configureInstance('<username>@<IP>:3306')
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002410281654.png "点击放大")
      
   
   5. 检查节点是否可加入cluster，\<username\>和\<IP\>分别替换为节点的MySQL用户名和IP地址。
      ```
      dba.checkInstanceConfiguration('<username>@<IP>:3306')
      ```
      可加入时回显如下，status提示ok。
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002410897114.png "点击放大")
      
   
   6. 创建集群，自定义集群名称替换cluster_name后执行。
      ```
      var cluster = dba.createCluster('<cluster_name>')
      ```
      
   
   7. 为集群添加从节点，username替换为MySQL的用户名，IP替换为不同的从节点IP地址，每个从节点都需要添加一遍，recovery method默认选择Clone。
      ```
      cluster.addInstance('<username>@<IP>:3306')
      ```
      输出信息如下，表示添加成功。
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444184281.png "点击放大")
      
   
   8. 查看集群状态。
      ```
      cluster.status()
      ```
      输出信息如下，表示集群创建完成。
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444065881.png "点击放大")
      
   
   9. 配置完成后可以输入**\\q** 退出mysqlsh程序。
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444336393.png "点击放大")
      
   
   
   
   
3. 设置代理节点。 
   1. 远程连接代理节点，参考[Linux ECS登录方式概述](https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0013771089.html)。
   
   2. 执行命令初始化地理设置，将username替换为MySQL的用户名，IP替换为主节点的IP地址，执行后输入密码。
      ```
      sudo mysqlrouter --bootstrap <username>@<IP>:3306 --directory /mnt/mysqlrouter \
      --conf-bind-address 0.0.0.0 --user=mysqlrouter
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444067641.png "点击放大")
      
   
   3. 编辑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
      ```
      
   
   4. 执行命令启动服务。
      ```
      #刷新服务文件
      sudo systemctl daemon-reload
      #启动mysqlrouter
      sudo systemctl start mysqlrouter.service
      #设置mysqlrouter开机自启
      sudo systemctl enable mysqlrouter.service
      #查看服务状态
      sudo systemctl status mysqlrouter.service
      ```
      
   
   
   
   
4. （可选）验证集群。 
   模拟MySQL主节点故障，验证集群是否能够自动切换节点提供服务。
   1. 远程连接代理节点，参考[Linux ECS登录方式概述](https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0013771089.html)。
   
   2. 使用MySQL客户端连接到代理节点，\<username\>替换为MySQL的用户名，执行后输入MySQL密码。
      ```
      mysql -h127.0.0.1 -P6450 -u<username> -p
      ```
      
   
   3. 执行sql语句查看集群状态，结果显示3个节点在线，其中一个是主节点。
      ```
      SELECT * FROM performance_schema.replication_group_members;
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002410431642.png "点击放大")
      
   
   4. 执行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;
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444191633.png "点击放大")
      
   
   5. 停止MySQL主节点，模拟宕机事件。 ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444071805.png "点击放大")
      
   
   6. 等待MySQL主节点停止后，再次执行SQL语句查看集群状态，发现两个节点在线，且从节点已自动切换为主节点。
      ```
      SELECT * FROM performance_schema.replication_group_members;
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002410433714.png "点击放大")
      
   
   7. 执行SQL语句查询数据查看是否有丢失数据。
      ```
      select * from test_table;
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444073137.png "点击放大")
      
   
   8. 启动MySQL主节点模拟宕机恢复。
   
   9. 执行SQL语句查看集群状态，结果显示三个节点在线，且主节点自动加入集群。
      ```
      SELECT * FROM performance_schema.replication_group_members;
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002410594442.png "点击放大")
      
    
   
   
5. （可选）集群添加节点。 
   在MySQL集群中，需要扩展集群或应对节点宕机时，可通过mysql-shell连接集群并使用addInstance命令添加新节点，新节点会自动同步数据。
   ![](https://support.huaweicloud.com/bestpractice-ecs/public_sys-resources/note_3.0-zh-cn.png)
   - 集群节点宕机过半会导致集群不可用，建议节点总数为单数以确保可用性。
   
   - 待加入集群的节点在扩容前需重复[步骤1]中设置集群节点的2、3、4步。
    
   1. 远程连接代理节点，参考[Linux ECS登录方式概述](https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0013771089.html)。
   
   2. 通过mysql-shell连接到集群中任意节点，使用MySQL客户端连接到代理节点，\<username\>替换为MySQL的用户名，\<IP\>替换为节点IP地址，执行后输入MySQL密码。
      ```
      mysqlsh --js <username>@<IP>:3306
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444077165.png "点击放大")
      
   
   3. 获取集群。
      ```
      var cluster = dba.getCluster()
      ```
      
   
   4. 为集群添加节点，将\<username\>替换为MySQL用户名，\<IP\>替换为节点IP地址。
      ```
      cluster = dba.addInstance('<username>@<IP>:3306')
      ```
      通过以下命令查看cluster情况，可以观察到新扩容的节点情况。
      ```
      cluster.status()
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002410439346.png "点击放大")
      ![](https://support.huaweicloud.com/bestpractice-ecs/public_sys-resources/note_3.0-zh-cn.png)
      如需移出节点，可使用以下命令，根据将\<username\>和\<IP\>替换为需要移出的节点信息。
      ```
      cluster.removeInstance('<username>@<IP>:3306')
      ```
      回显类似如下信息。
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002410440446.png "点击放大")
      
   
   
   
   
6. （可选）指定集群主节点。 
   在MySQL集群中，若主节点宕机，系统会自动从剩下的从节点中选举出新的主节点，如需手动指定主节点，可以通过mysql-shell连接集群，使用setPrimaryInstance命令设置主节点。
   1. 远程连接代理节点，参考[Linux ECS登录方式概述](https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0013771089.html)。
   
   2. 通过mysql-shell连接到集群中任意节点，使用MySQL客户端连接到代理节点，\<username\>替换为MySQL的用户名，\<IP\>替换为节点IP地址，执行后输入MySQL密码。
      ```
      mysqlsh --js <username>@<IP>:3306
      ```
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444200581.png "点击放大")
      
   
   3. 获取集群。
      ```
      var cluster = dba.getCluster()
      ```
      
   
   4. 为集群设置目标主节点，将\<username\>替换为MySQL用户名，\<IP\>替换为节点IP地址。
      ```
      cluster.setPrimaryInstance ('<username>@<IP>:3306')
      ```
      回显如下类似信息，表示设置成功。
      ![](https://support.huaweicloud.com/bestpractice-ecs/zh-cn_image_0000002444081105.png "点击放大")
      
   
   
   
   
 
