InnoDB Cluster 基本概述
InnoDB Cluster是MySQL官方實現高可用+讀寫分離的架構方案,其中包含以下組件
MySQL Group Replication
,簡稱MGR,是MySQL的主從同步高可用方案,包括數據同步及角色選舉mysqlshell
是InnoDB Cluster的管理工具,用來創建和管理集群mysqlrouter
是業務流量入口,支持對MGR的主從角色判斷,可以配置不同的端口分別對外提供讀寫服務,實現讀寫分離
InnoDB Cluster 基礎信息
IP地址 | 端口 | 角色 | 版本 |
---|---|---|---|
10.186.63.179 | 6000/6001 | mysqlrouter/mysqlshell | MySQL Enterprise 8.0.22 |
10.186.63.65 | 3310 | MGR/mysqlshell | MySQL Enterprise 8.0.22 |
10.186.63.66 | 3310 | MGR/mysqlshell | MySQL Enterprise 8.0.22 |
10.186.63.66 | 3310 | MGR/mysqlshell | MySQL Enterprise 8.0.22 |
InnoDB Cluster 安裝配置
1. 安裝mysqlshell/mysqlrouter
mysqlshell和mysqlrouter可直接從官方網站下載對應操作系統版本軟件包即可,以RHEL7系統為例安裝
rpm -ivh mysql-router-commercial-8.0.22-1.1.el7.x86_64.rpm
rpm -ivh mysql-shell-commercial-8.0.22-1.1.el7.x86_64.rpm
2. 安裝MySQL數據庫
安裝過程省略,只需要按照配置列表初始化生成3個數據庫實例,由於默認root只允許本地登錄,為方便管理,需要額外在每個實例下創建一個擁有遠程訪問的權限用戶,如下為例:
-- 關閉會話級別binlog日志
set session sql_log_bin=off;
-- 創建遠程管理用戶並授權
create user root identified by 'root';
grant all on *.* to root with grant option;
3. InnoDB Cluster 初始化
3.1 參數及權限配置預需求檢測
mysqlsh root@10.186.63.65:3310 --js
// 檢查實例是否符合InnoDB Cluster的參數及權限配置要求
dba.checkInstanceConfiguration('root@10.186.63.65:3310')
dba.checkInstanceConfiguration('root@10.186.63.66:3310')
dba.checkInstanceConfiguration('root@10.186.63.67:3310')
如果不滿足要求則會報錯,如當權限不足時報錯並提升授予以下權限
3.2 初始化InnoDB Cluster相關配置
mysqlsh root@10.186.63.65:3310 --js
// 對實例配置InnoDB Cluster相關參數
dba.configureInstance('root@10.186.63.65:3310',{clusterAdmin: "'mgr_admin'@'%'",clusterAdminPassword:"mgr_admin"})
dba.configureInstance('root@10.186.63.66:3310',{clusterAdmin: "'mgr_admin'@'%'",clusterAdminPassword:"mgr_admin"})
dba.configureInstance('root@10.186.63.67:3310',{clusterAdmin: "'mgr_admin'@'%'",clusterAdminPassword:"mgr_admin"})
3.3 創建集群/添加節點
需使用mysqlsh連接到任意一個節點后操作
初始化會執行以下操作
- 創建一個集群管理用戶,包含Replication slave和backup admin權限
- 設置MGR相關配置
- 再次校驗MySQL配置是否符合要求
// 初始化集群(第一個節點)
mysqlsh root@10.186.63.65:3310 --js
dba.createCluster('zhenxing',{memberWeight:90})
// 查看創建的集群狀態
var cluster = dba.getCluster()
cluster.status()
// 添加第二個節點
var cluster = dba.getCluster()
// 執行命令后新節點默認采用全量克隆方式添加到集群
cluster.addInstance('10.186.63.66:3310',{memberWeight:50})
cluster.addInstance('10.186.63.67:3310',{memberWeight:25})
// 也可以明確指定用增量方式加入新節點(確保各節點數據均一致或存在binlog日志可同步)
cluster.addInstance('10.186.63.66:3310',{memberWeight:50,recoveryMethod:'incremental'})
cluster.addInstance('10.186.63.67:3310',{memberWeight:25,recoveryMethod:'incremental'})
cluster.addInstance('10.186.63.66:3310',{memberWeight:50,recoveryMethod:'clone'})
// 查看集群的參數配置(包括memberWeight優先級配置)
cluster.status()
cluster.options().defaultReplicaSet.topology
4. mysqlrouter配置
mysqlrouter 是一個輕量級的中間件,無狀態的,建議和應用部署在一塊,mysqlrouter有兩種配置方式
- 手工填寫后端 MGR 節點的地址,但是這樣就沒法感知 Primary 節點的變化,手工創建 MGR 時只能這么配置
- 引導模式自動進行配置,通過 mysql_innodb_cluster_metadata 元數據庫動態感知 Primary 節點的變化,實現對應用的透明,這也是 InnoDB Cluster 的標准配置方法。
- mysqlrouter 必須通過配置
兩個端口來實現讀寫分離
,沒有解析 SQL 的功能。
## 創建一個非root用戶來引導mysqlrouter
useradd mysql
## 初始化mysqlrouter
## 配置文件保存在/data/mysqlrouter/目錄下,包含啟停腳本
mysqlrouter --bootstrap root@10.186.63.65:3310 --directory=/data/mysqlrouter/ --conf-use-sockets --user=mysql --force
## 啟動mysqlrouter
cd /data/mysqlrouter/
./start.sh
4.1 使用mysqlrouter訪問
------ 通過讀寫端口 6446 訪問數據庫
mysqlsh root@10.186.63.179:6446
mysqlsh root@10.186.63.179:64460
-- 驗證主從角色
select @@hostname,@@port,@@server_uuid;
select * from performance_schema.replication_group_members;
-- 驗證寫入操作正常
create database demo;
use demo;
create table t1(id int primary key auto_increment);
insert into t1 select 1;
select * from t1;
------ 通過讀端口 6447 訪問數據庫
mysqlsh root@10.186.63.179:6447
mysqlsh root@10.186.63.179:64470
-- 驗證讀取操作正常
select @@hostname,@@port,@@server_uuid;
select * from performance_schema.replication_group_members;
select * from demo.t1;
-- 只讀端口無法寫入數據
MySQL 10.186.63.179:6447 ssl SQL > insert into demo.t1 select 1;
ERROR: 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
InnoDB Cluster 常用操作
1. 查看集群狀態
MySQL 10.186.63.179:6446 ssl JS > var cluster = dba.getCluster()
MySQL 10.186.63.179:6446 ssl JS > cluster.status()
{
"clusterName": "zhenxing",
"defaultReplicaSet": {
"name": "default",
"primary": "10.186.63.65:3310",
"ssl": "REQUIRED",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"10.186.63.65:3310": {
"address": "10.186.63.65:3310",
"mode": "R/W",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.22"
},
"10.186.63.66:3310": {
"address": "10.186.63.66:3310",
"mode": "R/O",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.22"
},
"10.186.63.67:3310": {
"address": "10.186.63.67:3310",
"mode": "R/O",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.22"
}
},
"topologyMode": "Single-Primary"
},
"groupInformationSourceMember": "10.186.63.65:3310"
}
2. 配置節點權重
memberWeight選項的值域為0到100之間的整數,缺省值為50。該值是故障轉移時自動選舉主節點的百分比權重,具有較高memberWeight值的實例更有可能在單主群集中被選為主節點
// 在集群創建完成后修改權重
var cluster = dba.getCluster()
cluster.setInstanceOption('10.186.63.65:3310','memberWeight',100)
cluster.setInstanceOption('10.186.63.66:3310','memberWeight',50)
cluster.setInstanceOption('10.186.63.67:3310','memberWeight',25)
// 查看集群的參數配置(包括memberWeight優先級配置)
cluster.options()
// 在集群創建時配置
dba.createCluster('zhenxing', {memberWeight:75}) // 第一個節點配置方式
var cluster = dba.getCluster()
cluster.addInstance('10.186.63.66:3310',{memberWeight:50})
cluster.addInstance('10.186.63.67:3310',{memberWeight:25})
3. 將節點重新加入集群
狀態為mssing的節點,通常是組復制關閉或中斷狀態,可以用
cluster.rejoinInstance()
重新加入集群,會重新對該節點設置MGR相關參數(持久化到mysqld-auto.conf中)
3.1 rejoinInstance
cluster.status().defaultReplicaSet.topology
{
"10.186.63.65:3310": {
"address": "10.186.63.65:3310",
"mode": "R/W",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.22"
},
"10.186.63.66:3310": {
"address": "10.186.63.66:3310",
"mode": "R/O",
"readReplicas": {},
"role": "HA",
"status": "(MISSING)" // MISSING
},
"10.186.63.67:3310": {
"address": "10.186.63.67:3310",
"mode": "R/O",
"readReplicas": {},
"replicationLag": null,
"role": "HA",
"status": "ONLINE",
"version": "8.0.22"
}
}
// 重新加入集群
cluster.rejoinInstance("root@10.186.63.66:3310")
3.2 removeInstance && addInstance
如果一些參數做了修改,如server_uuid變更,導致rejoin失敗,則需要將節點從集群中刪除后重新加入
cluster.removeInstance("root@10.186.63.66:3310",{force:true})
cluster.rescan()
cluster.addInstance("root@10.186.63.66:3310")
4. 集群多數節點異常,恢復
當集群多個節點異常,則失去了仲裁機制,剩下的一個節點
// 將集群剝離為單節點運行
JS > cluster.forceQuorumUsingPartitionOf("root@10.186.63.67:3310")
// 重新加另外2個節點加入
JS > cluster.rejoinInstance("root@10.186.63.65:3310")
JS > cluster.rejoinInstance("root@10.186.63.66:3310")
5. 完整關閉的集群如何恢復
每個節點都是正常的停止且正常的觸發stop group_replication停止的,當重新啟動時如果手工我們需要做以下操作才可拉起集群
- 判斷哪個節點的GTID最新
- 將最新的GTID節點group_replication_bootstrap_group設置為on表示以這個節點為基礎啟動組復制
- 再將其他節點的組復制啟動,集群恢復
我們也可以用mysqlsh的功能來讓其自行判斷最新數據的節點,再采用dba.rebootClusterFromCompleteOutage()
方式啟動集群
// 通過65節點觸發命令
MySQL 10.186.63.65:3310 ssl JS > dba.rebootClusterFromCompleteOutage()
Restoring the default cluster from complete outage...
// 檢測到66服務器也包含在集群中,確認添加
The instance '10.186.63.66:3310' was part of the cluster configuration.
Would you like to rejoin it to the cluster? [y/N]: y
// 檢測到67服務器也包含在集群中,確認添加
The instance '10.186.63.67:3310' was part of the cluster configuration.
Would you like to rejoin it to the cluster? [y/N]: y
// 檢測到65不是最新的節點,66才是
Dba.rebootClusterFromCompleteOutage: The active session instance (10.186.63.65:3310) isn't the most updated in comparison with the ONLINE instances of the Cluster's metadata. Please use the most up to date instance: '10.186.63.66:3310'. (RuntimeError)
// 重新連接到66上執行相同操作
MySQL 10.186.63.65:3310 ssl JS > \connect "root@10.186.63.66:3310"
MySQL 10.186.63.65:3310 ssl JS > dba.rebootClusterFromCompleteOutage()
// 完成后查看集群狀態是否正常
var cluster = dba.getCluster()
cluster.status()
6. 集群節點角色切換
在MGR的管理下提供了一下3中方式進行角色切換,mysqlsh對其進行了封裝調用
- group_replication_set_as_primary(member_uuid);
cluster.setPrimaryInstance("IP:PORT")
- group_replication_switch_to_single_primary_mode()
cluster.switchToSinglePrimaryMode("IP:PORT")
- group_replication_switch_to_multi_primary_mode()
cluster.switchToMultiPrimaryMode()
6.1 單主模式-指定主節點切換
var cluster = dba.getCluster()
cluster.setPrimaryInstance('10.186.63.66:3310')
cluster.status()
6.2 單主模式和多主模式相互切換
// 切換為多主模式
var cluster = dba.getCluster()
cluster.switchToMultiPrimaryMode()
// 指定明確的主節點將多主模式切換為單主模式
cluster.switchToSinglePrimaryMode("10.186.63.65:3310")
7. 參數配置
可以用
cluster.options()
查看當前集群的配置屬性,集群參數配置分為兩種方式
cluster.setOption()
用來設置所有節點的參數cluster.setInstanceOption()
用來對指定節點配置屬性
// 將所有節點的權重都改為50/重新加入集群重試次數改為5次
var cluster = dba.getCluster()
cluster.setOption("memberWeight",50)
cluster.setOption("autoRejoinTries",5)
// 將其中一個節點的權重改為75/重新加入集群重試次數改為10次
cluster.setInstanceOption("10.186.63.65:3310","memberWeight",75)
cluster.setInstanceOption("10.186.63.65:3310","autoRejoinTries",10)
8. 銷毀集群
刪除與群集關聯的所有元數據和配置,並禁用實例上的組復制,但不會刪除在實例之間復制的任何數據。要再次創建集群,使用,dba.createCluster()
var cluster = dba.getCluster()
cluster.dissolve()
錯誤記錄
getCluster() 報錯
// 獲取集群報錯,集群中的該節點MGR功能未啟動
MySQL 10.186.63.65:3310 ssl JS > 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) (RuntimeError)
// 可以切換到sql模式查看集群當前狀態
// 可以看到當前集群只有一個節點且處於OFFLINE狀態
MySQL 10.186.63.65:3310 ssl SQL > \sql select * from performance_schema.replication_group_members\G
*************************** 1. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 67c08e33-92c4-11eb-803d-02000aba3f41
MEMBER_HOST: 10.186.63.65
MEMBER_PORT: 3310
MEMBER_STATE: OFFLINE
MEMBER_ROLE:
MEMBER_VERSION:
1 row in set (0.0038 sec)
-- 可以將該節點作為引導節點啟動集群
set global group_replication_bootstrap_group=on;
start group_replication;
-- 啟動完畢后需關閉該參數
set global group_replication_bootstrap_group=off;
-- 再次查看可看到第一個節點恢復正常
MySQL 10.186.63.65:3310 ssl SQL > select * from performance_schema.replication_group_members\G
*************************** 1. row ***************************
CHANNEL_NAME: group_replication_applier
MEMBER_ID: 67c08e33-92c4-11eb-803d-02000aba3f41
MEMBER_HOST: 10.186.63.65
MEMBER_PORT: 3310
MEMBER_STATE: ONLINE
MEMBER_ROLE: PRIMARY
MEMBER_VERSION: 8.0.22
1 row in set (0.0016 sec)
addInstance 報錯 Unknown MySQL server host
報這個錯誤需要配置/etc/hosts將主機名和IP對應關系配置上
Cluster.addInstance: Unknown MySQL server host '10-186-63-65' (2) (MySQL Error 2005)
// cluster.status() 命令也會有如下顯示
"shellConnectError": "MySQL Error 2005 (HY000): Unknown MySQL server host '10-186-63-65' (2)",
清理殘留的mgr信息
dba.dropMetadataSchema()
Dba.checkInstanceConfiguration: Dba.checkInstanceConfiguration: This function is not available through a session to a standalone instance (metadata exists, instance belongs to that metadata, but GR is not active) (RuntimeError)
克隆插件不能設置為force_plus_permanent
在多次對同一個實例做集群初始化時,不管是全量還是增量都會對克隆插件做一次重新加載,會如果對克隆插件開啟了force_plus_permanent屬性,則無法卸載,需要
Cluster.addInstance: error uninstalling plugin 'clone': 10.186.63.67:3310: Plugin 'clone' is force_plus_permanent and can not be unloaded (RuntimeError)