MySQL InnoDB Cluster 配置

1,800 阅读5分钟

说明

  • MySQL的高可用架构无论是社区还是官方,一直在技术上进行探索,这么多年提出了多种解决方案,比如MMM, MHA, NDB Cluster, Galera Cluster, InnoDB Cluster, 腾讯的PhxSQL, MySQL Fabric ,aliSQL
  • NDB:基于集群的引擎-数据被自动切分并复制到数个机器上(数据节点), 适合于那些需要极高查询性能和高可用性的应用, 原来是为爱立信的电信应用设计的。 NDB提供了高达99.999%的可靠性,在读操作多的应用中表现优异。 对于有很多并发写操作的应用, 还是推荐用InnoDB
  • 本次部署采用InnoDB Cluster. 每台服务器实例都运行MySQL Group Replication(冗余复制机制,内置failover
  • MGR有两种模式,一种是Single-Primary,一种是Multi-Primary,即单主或者多主。
  • 注意:Multi-Primary模式中,所有的节点都是主节点,都可以同时被读写,看上去这似乎更好,但是因为多主的复杂性,在功能上如果设置了多主模式,则会有一些使用的限制,比如不支持Foreign Keys with Cascading Constraints。
    image.png

配置环境

  • 系统 Ubuntu 14.04
  • MySQL 8.0
  • 服务器(至少3台):svr1, svr2, svr3

安装

  1. 安装源

deb下载页面:dev.mysql.com/downloads/r…

wget https://repo.mysql.com//mysql-apt-config_0.8.10-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.10-1_all.deb  # 选择版本mysql-8.0
sudo apt-get update
  1. 安装MySQL及组件
sudo apt-get install mysql-server mysql-shell mysql-router
  1. 添加MySQL用户和权限 运行命令: mysql -u root -p 进入MySQL shell,创建用户名和足够的权限
# user,password替换为自己的
mysql> CREATE USER 'user'@'%' IDENTIFIED BY 'password';用户名和密码
mysql> GRANT all privileges on *.* to user@'%' identified by 'password' with grant option;
mysql> flush privileges;

配置

  1. 配置文件 修改配置文件/etc/mysql/my.cnf,添加如下配置:
  • 修改不同机器的名称或IP;
  • server_id使用不同编号;
  • loose-group_replication_group_name使用UUID形式,集群中机器使用同一个UUID
  • loose-group_replication_single_primary_mode在单主模式中为ON,在多主模式中为OFF
[mysqld]
# server configuration
pid-file        = /var/run/mysqld/mysqld.pid
socket          = /var/run/mysqld/mysqld.sock
datadir         = /var/lib/mysql
log-error       = /var/log/mysql/error.log
bind-address    = 0.0.0.0
# Disabling symbolic-links is recommended to prevent assorted security risks
#symbolic-links = 0
# Replication configuration parameters
server_id = 1 #2,3
gtid_mode = ON
enforce_gtid_consistency = ON
master_info_repository = TABLE
relay_log_info_repository = TABLE
transaction_write_set_extraction = XXHASH64
binlog_checksum = NONE
log_slave_updates = ON
log_bin = binlog
binlog_format = ROW
relay-log = svr-relay-bin
#
# Group Replication configuration
loose-group_replication_group_name = a38e32fd-5fb6-11e8-ad7a-00259015d941
loose-group_replication_start_on_boot = OFF
loose-group_replication_local_address = svr1:33061
loose-group_replication_group_seeds = svr1:33061,svr2:33061,svr3:3306
loose-group_replication_bootstrap_group = OFF
loose-group_replication_allow_local_disjoint_gtids_join = ON
# Group Replication configuration multi-primary mode
loose-group_replication_single_primary_mode = OFF
loose-group_replication_enforce_update_everywhere_checks = ON
  1. 检查配置 运行命令进入mysql-js shell: sudo -i mysqlsh --uri=user@svr1:3306 对集群中的机器执行以下命令,检查配置: mysql-js> dba.checkInstanceConfiguration('user@svr1:3306') 通过下列命令查看所有服务器上group_replication配置是否一致: mysql> show variables like 'group_replication%';

  2. 创建集群 如果需要创建单主模式集群,执行第1句;如果需要创建多主模式集群,执行第二句。

mysql-js> var cluster = dba.createCluster('mysqlCluster')  # 单主模式集群
mysql-js> var cluster = dba.createCluster('mysqlCluster', {multiMaster:true})  # 多主模式集群
mysql-js> cluster.addInstance('user@svr2:3306')
mysql-js> cluster.addInstance('user@svr3:3306')
  1. 查看状态
mysql-js> var cluster = dba.getCluster()
mysql-js> cluster.status();

输出以下内容则表示集群建立起来了(当前输出为多主模式,单主模式类似):

{
    "clusterName": "mysqlCluster",
    "defaultReplicaSet": {
        "name": "default",
        "status": "OK",
        "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
        "topology": {
            "svr1:3306": {
                "address": "svr1:3306",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "svr2:3306": {
                "address": "svr2:3306",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            },
            "svr3:3306": {
                "address": "svr3:3306",
                "mode": "R/W",
                "readReplicas": {},
                "role": "HA",
                "status": "ONLINE"
            }
        }
    }
}

部署MySQL Router

客户端不能直接连接服务器,需要通过 MySQL Router 来连接。 运行命令:sudo -i mysqlrouter --bootstrap user@svr1:3306 --user mysqlrouter 生成配置文件并运行MySQLRouter(通过keepalived的虚拟IP可配置高可用性router) 配置文件路径:/etc/mysqlrouter/mysqlrouter.conf,可查看访问接口

innodb_cluster_overview.png

配置中问题记录

问题1:[ERROR] Slave SQL for channel 'group_replication_recovery': Could not execute Write_rows event on table mysql_innodb_cluster_metadata.instances; Cannot add or update a child row: a foreign key constraint fails (mysql_innodb_cluster_metadata.instances, CONSTRAINT instances_ibfk_1 FOREIGN KEY (host_id) REFERENCES hosts (host_id)), Error_code: 1452; handler error HA_ERR_NO_REFERENCED_ROW; the event's master log binlog.000001, end_log_pos 3059, Error_code: 1452 解决方式:清空表mysql_innodb_cluster_metadata.hosts; 重新建立集群

问题2:This member has more executed transactions than those present in the group 解决方式: mysql-> stop group_replication; mysql-> reset master;

问题3:用户操作系统资源的限制 [Warning] Buffered warning: Changed limits: max_open_files: 1024 (requested 5000) [Warning] Buffered warning: Changed limits: table_open_cache: 431 (requested 2000) 解决方式: $ vim /etc/security/limits.conf,添加: mysql soft nproc 2047 mysql hard nproc 16384 mysql soft nofile 1024 mysql hard nofile 65535

问题4:dba.rebootClusterFromCompleteOutage: The active session instance isn't the most updated in comparison with the ONLINE instances of the Cluster's metadata. 在集群没有起来时某些机器的数据表发生变动,导致数据不一致; 解决方式: 所有MySQL机器通过reset master命令清空binlogs mysql> reset master; mysql> show master logs; 然后再运行Dba.rebootClusterFromCompleteOutage重启集群。

问题5:service mysql restart无法重启mysql,mysql stuck,并一直输出日志'[Note] Plugin group_replication reported: '[GCS] cli_err 2'' 解决方式:唯一停止MySQL的命令为:sudo pkill -9 mysqld

问题6:如何将Multi-Primary改为Single-Primary? (1). 解散原来的集群:mysql-js> cluster.dissolve({force: true}) (2). 每台主机MySQL修改如下配置: mysql> set global group_replication_enforce_update_everywhere_checks=OFF; mysql> set global group_replication_single_primary_mode=ON; (3). 重新创建集群: mysql-js> var cluster = dba.createCluster('mysqlCluster'); mysql-js> cluster.addInstance('user@svr2:3306'); mysql-js> cluster.addInstance('user@svr3:3306');

This member has more executed transactions than those present in the group