MySQL InnoDB Cluster 为MySQL 提供了完整的高可用性解决方案.通过使用 MySQL Shell 附带的 AdminAPI,您可以轻松地配置和管理一组至少三个 MySQL 服务器实例,以充当 InnoDB 集群.
每个 MySQL 服务器实例都运行MySQL Group Replication,它提供了具有内置故障转移功能的 InnoDB Clusters 中复制数据的机制,消除了直接在 InnoD B群集中使用组复制的需要.
整个集群环境如下:
准备环境 
server id 
IP 
主机名 
部署应用 
应用版本 
 
 
1 
10.71.1.31 
mysql-1 
mysql-cluster,mysql-router,mysql-shell 
8.0.21 
 
2 
10.71.1.32 
mysql-2 
mysql-cluster,mysql-router,mysql-shell 
8.0.21 
 
3 
10.71.1.33 
mysql-3 
mysql-cluster,mysql-router,mysql-shell 
8.0.21 
 
以上三台设备都下载了 mysql-cluster ,mysql-router ,mysql-shell  对应版本的安装包,解压到 /usr/local/ 对应目录下.
安装 MySQL Cluster 配置文件 mysql-cluster 配置文件如下.之后需要修改的配置包括
server_id: 集群主机的唯一标识 
loose-group_replication_local_address: 集群主机的本地 IP 地址及 replication 的端口 
report_host: 集群主机的本地 IP 地址 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 # /etc/my.cnf [client] port            = 3306 socket          = /usr/local/mysql/tmp/mysql.sock [mysql] no-auto-rehash default-character-set=utf8 socket          = /usr/local/mysql/tmp/mysql.sock [mysqld] user                            = mysql port                            = 3306 server_id                       = 1 basedir                         = /usr/local/mysql datadir                         = /usr/local/mysql/data/ tmpdir                          = /usr/local/mysql/tmp/ socket                          = /usr/local/mysql/tmp/mysql.sock slow_query_log                  = ON slow_query_log_file             = /usr/local/mysql/log/mysql-slow-queries.log long_query_time                 = 10 log_error                       = /usr/local/mysql/log/error.log log-bin                         = /usr/local/mysql/binlog/mysql-bin.log pid-file                        = /usr/local/mysql/tmp/mysql.pid character-set-server            = utf8 binlog_format                   = ROW skip_name_resolve               = on default-storage-engine          = innodb max_connections                 = 3000 explicit_defaults_for_timestamp = OFF gtid_mode                       = on enforce_gtid_consistency=on log-slave-updates=on delayed_insert_limit = 1000 delayed_insert_timeout = 3000 delayed_queue_size = 5000 bulk_insert_buffer_size =1024M concurrent_insert=2 thread_stack =  32M event_scheduler = ON lower_case_table_names=1 sort_buffer_size = 600M net_buffer_length =  1M read_rnd_buffer_size = 600M tmp_table_size = 600M max_heap_table_size = 16M read_buffer_size= 600M expire_logs_days = 5 #innodb sync_binlog=1 innodb_data_file_path = ibdata1:10M:autoextend innodb_buffer_pool_size = 1024M innodb_log_file_size = 2047M innodb_log_buffer_size = 8M innodb_flush_log_at_trx_commit = 2 innodb_lock_wait_timeout = 50 innodb_rollback_on_timeout = ON innodb_file_per_table innodb_flush_method=O_DIRECT innodb_open_files = 65536 innodb_io_capacity = 1000 innodb_read_io_threads = 8 innodb_write_io_threads  = 1 innodb_spin_wait_delay = 96 innodb_max_dirty_pages_pct = 50 innodb_sync_spin_loops = 30 #MYISAM key_buffer_size =   1G myisam_sort_buffer_size = 1G myisam_repair_threads=2 # innodb cluster transaction_write_set_extraction=XXHASH64 loose-group_replication_group_name='aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' loose-group_replication_start_on_boot=off loose-group_replication_ip_whitelist='10.71.1.0/24' loose-group_replication_local_address='10.71.1.31:33061' loose-group_replication_group_seeds='10.71.1.31:33061,10.71.1.32:33061,10.71.1.33:33061' loose-group_replication_bootstrap_group=off loose-group_replication_single_primary_mode=on loose-group_replication_enforce_update_everywhere_checks=off loose-group_replication_recovery_get_public_key=on loose-group_replication_recovery_use_ssl=off loose-group_replication_ssl_mode='DISABLED' loose-group_replication_consistency='EVENTUAL' loose-group_replication_member_expel_timeout=5 report_host='10.71.1.31' report_port=3306 plugin_load_add ='group_replication.so' auto_increment_increment=1 auto_increment_offset=1 mysqlx_port=33060 admin_port=33062 
 
开始安装 添加用户,并授予权限 1 2 3 4 5 6 7 8 9 10 tar -xzf mysql-cluster-8.0.21-el7-x86_64.tar.gz -C /usr/local / cd  /usr/local /ln -s mysql-cluster-8.0.21-el7-x86_64 mysql mkdir mysql/{data,log ,binlog,tmp} groupadd mysql && useradd -r -g mysql -s /bin/false  mysql chown -R mysql:mysql /usr/local /mysql/ echo  'export PATH=/usr/local/mysql/bin:$PATH'  >> /etc/profile.d/mysql.shsource   /etc/profile.d/mysql.sh
 
初始化数据库 1 2 3 4 5 cd  /usr/local /mysql/bin/mysqld --defaults-file=/etc/my.cnf --user=mysql -I tail log /error.log 
 
启动数据库并连接后修改密码 1 2 3 bin/mysqld_safe --defaults-file=/etc/my.cnf --user=mysql bin/mysql --defaults-file=/etc/my.cnf -u root -h localhost -p  
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 SET  SQL_LOG_BIN=0 ;SET  global  super_read_only=OFF ;SET  global  read_only=OFF ;ALTER  USER  USER () IDENTIFIED  BY  'root' ;flush  privileges ;SET  SQL_LOG_BIN=1 ;SET  SQL_LOG_BIN=0 ;CREATE  USER  'root' @'%'  IDENTIFIED  WITH  mysql_native_password BY  'root' ;GRANT  ALL  PRIVILEGES  ON  *.* TO  'root' @'%'  WITH  GRANT  OPTION ;FLUSH  PRIVILEGES ;SET  SQL_LOG_BIN=1 ;
 
这里提供了 mysqld 服务的启动脚本,使用 systemd 管理比较方便
1 2 3 4 5 6 7 8 9 10 11 12 13 [Unit] Description=mysqld service Documentation=https://dev.mysql.com/doc/ [Service] ExecStart=/usr/local /mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf --user=mysql Restart=always RestartSec=10s [Install] WantedBy=multi-user.target 
 
确认安装组复制插件(可能已经存在) 1 2 3 INSTALL  PLUGIN  group_replication SONAME  'group_replication.so' ;SELECT  PLUGIN_NAME, PLUGIN_STATUS FROM  INFORMATION_SCHEMA.PLUGINS  WHERE  PLUGIN_NAME LIKE  '%group_replication%' ;
 
创建同步用户 1 2 3 4 5 6 7 8 9 10 11 12 13 14 SET  SQL_LOG_BIN=0 ;CREATE  USER  IF  NOT  EXISTS  `repl` @`%`  IDENTIFIED  WITH  mysql_native_password BY  'repl' ;GRANT  REPLICATION  SLAVE  ON  *.* TO  repl@'%' ;FLUSH  PRIVILEGES ;SET  SQL_LOG_BIN=1 ;SELECT  host, user , authentication_string, plugin  FROM  mysql.user;SET  SQL_LOG_BIN=0 ;CHANGE  MASTER  TO  MASTER_USER='repl' , MASTER_PASSWORD='repl'  FOR  CHANNEL 'group_replication_recovery' ;SELECT  User_name,Channel_name FROM  mysql.slave_master_info WHERE  user_name = 'repl' ;SET  global  group_replication_recovery_get_public_key=ON ;SET  SQL_LOG_BIN=1 ;
 
启动组复制 在此示例中,三个实例用于该组,这是创建组的最小实例数.可以添加更多实例将增加组的容错能力.例如,如果该组由三个成员组成,则在一个实例失败的情况下,该组可以继续.但是,如果发生另一个故障,该组将无法继续处理写事务.通过添加更多实例,在组继续处理事务时可能发生故障的服务器数量也会增加.一个组中最多可以使用 9 个实例。
一些额外配置 对于组复制,数据必须存储在InnoDB事务存储引擎中,使用其他存储引擎(包括临时 MEMORY 存储引擎)可能会导致组复制中的错误.可以设置如下 disabled_storage_engines 系统变量以防止其使用:
1 2 3 4 # /etc/my.cnf [mysqld] # ... disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY" 
 
从 MySQL 8.0.21 开始,组复制支持二进制日志中校验和的存在,并且可以使用它们来验证某些通道上事件的完整性,因此可以使用默认设置.如不使用则可以设置如下:
1 2 3 4 # /etc/my.cnf [mysqld] # ... binlog_checksum=NONE 
 
引导组 当安装好三个节点后,首次启动组的过程称为引导.您可以使用 group_replication_bootstrap_group 系统变量来引导组.引导程序只能由一台服务器(启动该组的服务器)执行一次,并且只能执行一次. 
1 2 3 4 5 6 SET  GLOBAL  group_replication_bootstrap_group=ON ;START  GROUP_REPLICATION USER ='repl' , PASSWORD ='repl' ;SET  GLOBAL  group_replication_bootstrap_group=OFF ;
 
在其他节点执行如下语句,加入组复制
1 2 START  GROUP_REPLICATION;
 
检查组复制状态 1 2 3 4 5 6 7 8 9 10 mysql> SELECT * FROM performance_schema.replication_group_members; + | CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | + | group_replication_applier | 0355f651-8e9b-11eb-93a6-e8611f128e89 | 10.71.1.31  |        3306 | ONLINE       | PRIMARY     | 8.0.21         | | group_replication_applier | 0356851b-8e9b-11eb-bbe5-e8611f1359d8 | 10.71.1.32  |        3306 | ONLINE       | SECONDARY   | 8.0.21         | | group_replication_applier | 0414ad46-8e9b-11eb-9faf-305a3a794266 | 10.71.1.33  |        3306 | ONLINE       | SECONDARY   | 8.0.21         | + 3 rows in set  (0.00  sec) 
 
至些,MGR 三节点组复制安装完毕~
可能出现的错误及解决 
1 2 mysql> START GROUP_REPLICATION USER='repl', PASSWORD='repl'; ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log. 
 
1 2021-03-27T02:19:57.240689Z 16 [ERROR] [MY-011595] [Repl] Plugin group_replication reported: 'Binlog format should be ROW for Group Replication' 
 
1 SET  GLOBAL  binlog_format=ROW ;
 
安装 MySQL Shell MySQL Shell 是 MySQL Server 的高级客户端和代码编辑器.除了提供的类似于 MySQL 的 SQL 功能外,MySQL Shell 还提供 JavaScript 和 Python 脚本功能,并包括与 MySQL 配合使用的 API.X DevAPI 使您能够使用关系数据和文档数据,AdminAPI 使您可以使用 InnoDB Cluster.
MySQL Shell 安装过程非常简单
1 2 3 4 5 6 7 8 tar -xzf mysql-shell-8.0.21-linux-glibc2.12-x86-64bit.tar.gz -C /usr/local / cd  /usr/local /ln -s mysql-shell-8.0.21-linux-glibc2.12-x86-64bit mysql-shell chown -R mysql.mysql mysql-shell echo  'export PATH=/usr/local/mysql-shell/bin:$PATH'  >> /etc/profile.d/mysql-shell.shsource   /etc/profile.d/mysql-shell.sh
 
创建 Innodb Cluster 集群 如果您已经有组复制的现有部署,并且想要使用它来创建群集,请将 adoptFromGR 参数传递给该 dba.createCluster() 函数.创建的 InnoDB 群集匹配复制组是以单主数据库还是多主数据库运行.
要采用现有的组复制组,使用 MySQL Shell 连接到组成员执行以下 SQL:
1 2 3 mysqlsh -uroot -hlocalhost -p var cluster = dba.createCluster('testCluster' , {adoptFromGR: true }); dba.getCluster("testCluster" ).status(); 
 
输出内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 {     "clusterName" : "testCluster" ,     "defaultReplicaSet" : {         "name" : "default" ,         "primary" : "10.71.1.31:3306" ,         "ssl" : "DISABLED" ,         "status" : "OK" ,         "statusText" : "Cluster is ONLINE and can tolerate up to ONE failure." ,         "topology" : {             "10.71.1.31:3306" : {                 "address" : "10.71.1.31:3306" ,                 "mode" : "R/O" ,                 "readReplicas" : {},                 "replicationLag" : null ,                 "role" : "HA" ,                 "status" : "ONLINE" ,                 "version" : "8.0.21"              },             "10.71.1.32:3306" : {                 "address" : "10.71.1.32:3306" ,                 "mode" : "R/O" ,                 "readReplicas" : {},                 "replicationLag" : null ,                 "role" : "HA" ,                 "status" : "ONLINE" ,                 "version" : "8.0.21"              },             "10.71.1.33:3306" : {                 "address" : "10.71.1.33:3306" ,                 "mode" : "R/W" ,                 "readReplicas" : {},                 "replicationLag" : null ,                 "role" : "HA" ,                 "status" : "ONLINE" ,                 "version" : "8.0.21"              }         },         "topologyMode" : "Single-Primary"      },     "groupInformationSourceMember" : "10.71.1.31:3306"  } 
 
关键字段如下:
1 2 3 4 "status": "OK" 表示集群状态是正常的 "topologyMode": "Single-Primary" 表示是单主模式 "mode": "R/W" 表示可读可写 "mode": "R/O" 表示只读 
 
安装 MySQL Router MySQL Router 是 InnoDB Cluster 的一部分.是轻量级的中间件,可在应用程序与后端 MySQL 服务器之间提供透明的路由.它可以用于各种用例,例如通过有效地将数据库流量路由到适当的后端MySQL服务器来提供高可用性和可伸缩性.
为了获得最佳性能,MySQL Router 通常与使用它的应用程序安装在同一主机上.可能的原因包括
允许本地 UNIX 域套接字连接到应用程序,而不是TCP/IP,减少网络延迟
 
为了允许 MySQL 路由器连接到 MySQL 而不需要路由器主机的额外帐户,对于专门为应用程序主机创建的 MySQL 帐户(例如 myapp@198.51.100.45 ),而不是像myapp @%这样的值 。
 
 
您可以在网络上运行多个 MySQL Router 实例,而无需将MySQL Router隔离到单个计算机上
解压安装 1 2 3 4 5 6 7 8 9 tar -xzf mysql-router-8.0.21-el7-x86_64.tar.gz -C /usr/local / cd  /usr/local /ln -s mysql-router-8.0.21-el7-x86_64 mysql-router mkdir mysql-router/data chown -R mysql.mysql mysql-router echo  'export PATH=/usr/local/mysql-router/bin:$PATH'  >> /etc/profile.d/mysql-router.shsource   /etc/profile.d/mysql-router.sh
 
bootstrap 引导并启动 bootstrap 引导,创建一个独立的 MySQL Router 实例
1 2 mysqlrouter --bootstrap 'root' @'10.71.1.31'  --directory /usr/local /mysql-router/data --conf-use-sockets --user=mysql --name=mysql_router_13306 --conf-bind-address=10.71.1.31 --account-host="%"  
 
输出如下,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # Bootstrapping MySQL Router instance at '/usr/local/mysql-router-8.0.21-el7-x86_64/data'... - Creating account(s) (only those that are needed, if any) - Verifying account (using it to run SQL queries that would be run by Router) - Storing account in keyring - Adjusting permissions of generated files - Creating configuration /usr/local/mysql-router-8.0.21-el7-x86_64/data/mysqlrouter.conf # MySQL Router 'mysql_router_13306' configured for the InnoDB Cluster 'testCluster' After this MySQL Router has been started with the generated configuration     $ ./mysqlrouter -c /usr/local/mysql-router-8.0.21-el7-x86_64/data/mysqlrouter.conf the cluster 'testCluster' can be reached by connecting to: ## MySQL Classic protocol - Read/Write Connections: localhost:6446, /usr/local/mysql-router-8.0.21-el7-x86_64/data/mysql.sock - Read/Only Connections:  localhost:6447, /usr/local/mysql-router-8.0.21-el7-x86_64/data/mysqlro.sock ## MySQL X protocol - Read/Write Connections: localhost:64460, /usr/local/mysql-router-8.0.21-el7-x86_64/data/mysqlx.sock - Read/Only Connections:  localhost:64470, /usr/local/mysql-router-8.0.21-el7-x86_64/data/mysqlxro.sock 
 
且在 /usr/local/mysql-router/data/ 目录下生成了如下文件,其中包含配置文件,配置 key,启动/停止脚本等.
1 2 3 4 5 6 7 8 9 10 11 12 tree /usr/local/mysql-router/data/ /usr/local/mysql-router/data/ ├── data │   ├── keyring │   └── state.json  # 其中包含集群的 metadata-servers ├── log │   └── mysqlrouter.log ├── mysqlrouter.conf # 其中包含自动生成的配置信息 ├── mysqlrouter.key ├── run ├── start.sh └── stop.sh 
 
运行并验证 运行 /usr/local/mysql-router/data/ 目录下生成的 start.sh 启动 mysql-router.
1 2 3 4 5 6 7 8 9 10 root     2035683       1  0 12:42 pts/1    00:00:00 sudo ROUTER_PID=/usr/local /mysql-router-8.0.21-el7-x86_64/data/mysqlrouter.pid /usr/local /mysql-router-8.0.21-el7-x86_64/bin/mysqlrouter -c /usr/local /mysql-router-8.0.21-el7-x86_64/data/mysqlrouter.conf --user=mysql mysql    2035684 2035683  1 12:42 pts/1    00:00:01 /usr/local /mysql-router-8.0.21-el7-x86_64/bin/mysqlrouter -c /usr/local /mysql-router-8.0.21-el7-x86_64/data/mysqlrouter.conf --user=mysql tcp        0      0 10.71.1.31:64460        0.0.0.0:*               LISTEN      2035684/mysqlrouter tcp        0      0 10.71.1.31:6446         0.0.0.0:*               LISTEN      2035684/mysqlrouter tcp        0      0 10.71.1.31:6447         0.0.0.0:*               LISTEN      2035684/mysqlrouter tcp        0      0 10.71.1.31:64470        0.0.0.0:*               LISTEN      2035684/mysqlrouter 
 
查看配置文件可以知道
1 2 3 4 5 6 # /usr/local/mysql-router/data/mysqlrouter.conf 片段 [routing:testCluster_rw] bind_port=6446  # 读写端口,处理读写请求 [routing:testCluster_ro] bind_port=6447  # 只读端口,处理只读请求 
 
对读写端口进行验证,发现请求到主节点
1 2 3 4 5 6 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id     | 1     | +---------------+-------+ 
 
对只读端口进行验证,发现会在两个从节点上轮询
1 2 3 4 5 6 7 8 9 10 11 12 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id     | 2     | +---------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id     | 3     | +---------------+-------+ 
 
可能出现的问题 MySQL-Router 引导时提示权限不足 
1 Error: Error creating MySQL account for router (GRANTs stage): Error executing MySQL query "GRANT  SELECT , EXECUTE  ON  mysql_innodb_cluster_metadata.* TO  'mysql_router5_ll685grbj15x' @'%' ": Access denied for user 'root'@'%' to database 'mysql_innodb_cluster_metadata' (1044)  
 
1 2 3 4 5 GRANT  ALL  PRIVILEGES  ON  `mysql_innodb_cluster_metadata` .* TO  'root' @'%'  WITH  GRANT  OPTION ;GRANT  ALL  PRIVILEGES  ON  `mysql_innodb_cluster_metadata_bkp` .* TO  'root' @'%'  WITH  GRANT  OPTION ;GRANT  ALL  PRIVILEGES  ON  `mysql_innodb_cluster_metadata_previous` .* TO  'root' @'%'  WITH  GRANT  OPTION ;FLUSH  PRIVILEGES ;
 
模拟主节点宕机 我们把 server_id=1 的 MySQL 主节点停止,使用 MySQL-Router 检测,发现读写请求会被转发到备节点上,该备节点被提升为主节点,形成一主一从的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id     | 2     | +---------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id     | 3     | +---------------+-------+ +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id     | 3     | +---------------+-------+ 
 
此时在读写端口 6446 上创建测试数据库,并在只读端口 6447 上查看.发现创建成功并完成同步.
1 2 3 4 5 6 7 8 9 10 11 12 +-------------------------------+ | Database                      | +-------------------------------+ | information_schema            | | mysql                         | | mysql_innodb_cluster_metadata | | performance_schema            | | sys                           | | test                           | +-------------------------------+ 
 
此时恢复 server_id=1 的上的 MySQL 实例,并手动启动同步.发现之前创建的数据库可以同步到本机上的 MySQL 实例.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 mysql> START GROUP_REPLICATION; mysql> SHOW DATABASES; +-------------------------------+ | Database                      | +-------------------------------+ | information_schema            | | mysql                         | | mysql_innodb_cluster_metadata | | performance_schema            | | sys                           | | test                           | +-------------------------------+ 
 
如上实现了 MySQL 集群的高可用于故障恢复后的数据同步功能.
 
参考