Mysql 5.7 基於組複製(MySQL Group Replication) - 運維小結

散盡浮華發表於2019-01-12

 

之前介紹了Mysq主從同步的非同步複製(預設模式)、半同步複製基於GTID複製基於組提交和並行複製 (解決同步延遲),下面簡單說下Mysql基於組複製(MySQL Group Replication) 操作。

一、組複製 (MGR)介紹

MySQL Group Replication(簡稱MGR)是MySQL官方於2016年12月推出的一個全新的高可用與高擴充套件的解決方案。組複製是MySQL5.7版本出現的新特性,它提供了高可用、高擴充套件、高可靠的MySQL叢集服務。MySQL組複製分單主模式和多主模式,mysql 的複製技術僅解決了資料同步的問題,如果 master 當機,意味著資料庫管理員需要介入,應用系統可能需要修改資料庫連線地址或者重啟才能實現。(這裡也可以使用資料庫中介軟體產品來避免應用系統資料庫連線的問題,例如 mycat 和 atlas 等產品)。組複製在資料庫層面上做到了,只要叢集中大多數主機可用,則服務可用,也就是說3臺伺服器的叢集,允許其中1臺當機。

1.1   組複製的兩種模式

-  在單主模式下, 組複製具有自動選主功能,每次只有一個 server成員接受更新;
-  在多主模式下, 所有的 server 成員都可以同時接受更新;

1.2   組複製原理

組複製是一種可用於實現容錯系統的技術。 複製組是一個通過訊息傳遞相互互動的server叢集。通訊層提供了原子訊息(atomic message)和完全有序資訊互動等保障機制,實現了基於複製協議的多主更新複製組由多個 server成員構成,並且組中的每個server 成員可以獨立地執行事務。但所有讀寫(RW)事務只有在衝突檢測成功後才會提交。只讀(RO)事務不需要在衝突檢測,可以立即提交。句話說, 對於任何 RW 事務,提交操作並不是由始發 server 單向決定的,而是由組來決定是否提交。準確地說,在始發 server 上,當事務準備好提交時,該 server 會廣播寫入值(已改變的行)和對應的寫入集(已更新的行的唯一識別符號)。然後會為該事務建立一個全域性的順序。最終,這意味著所有 server 成員以相同的順序接收同一組事務。因此, 所有 server 成員以相同的順序應用相同的更改,以確保組內一致

基於組的複製(Group-basedReplication)是一種被使用在容錯系統中的技術。Replication-group(複製組)是由能夠相互通訊的多個伺服器(節點)組成的。在通訊層,Groupreplication實現了一系列的機制:比如原子訊息(atomicmessage delivery)和全序化訊息(totalorderingof messages)。這些原子化,抽象化的機制,為實現更先進的資料庫複製方案提供了強有力的支援。MySQL Group Replication正是基於這些技術和概念,實現了一種多主全更新的複製協議。

簡而言之,一個Replication-group就是一組節點,每個節點都可以獨立執行事務,而讀寫事務則會在於group內的其他節點進行協調之後再commit。因此,當一個事務準備提交時,會自動在group內進行原子性的廣播,告知其他節點變更了什麼內容/執行了什麼事務。
這種原子廣播的方式,使得這個事務在每一個節點上都保持著同樣順序。這意味著每一個節點都以同樣的順序,接收到了同樣的事務日誌,所以每一個節點以同樣的順序重演了這些事務日誌,最終整個group保持了完全一致的狀態。然而,不同的節點上執行的事務之間有可能存在資源爭用。這種現象容易出現在兩個不同的併發事務上。

假設在不同的節點上有兩個併發事務,更新了同一行資料,那麼就會發生資源爭用。面對這種情況,GroupReplication判定先提交的事務為有效事務,會在整個group裡面重演,後提交的事務會直接中斷,或者回滾,最後丟棄掉。因此,這也是一個無共享的複製方案,每一個節點都儲存了完整的資料副本。看下圖描述了具體的工作流程,能夠簡潔的和其他方案進行對比。這個複製方案,在某種程度上,和資料庫狀態機(DBSM)的Replication方法比較類似。

MySQL組複製協議工作流程:

需要注意:MySQL組複製是一種 share-nothing 複製方案,其中每個 server 成員都有自己的完整資料副本

1.3   組複製特點

-  高一致性
基於原生複製及 paxos 協議的組複製技術,並以外掛的方式提供,提供一致資料安全保證。確保組內資料最終一致性【重要】(通過分散式協議和分散式recovery機制保證);
-  高容錯性
確保組內高可用。只要不是大多數節點壞掉就可以繼續工作,有自動檢測機制,當不同節點產生資源爭用衝突時,不會出現錯誤,按照先到者優先原則進行處理,並且內建了自動化腦裂防護機制;
-  高擴充套件性
良好的擴充套件能力,可動態增刪節點,組成員自動管理。節點的新增和移除都是自動的,新節點加入後,會自動從其他節點上同步狀態,直到新節點和其他節點保持一致,如果某節點被移除了,其他節點自動更新組資訊,自動維護新的組資訊;
-  高靈活性
有單主模式和多主模式,單主模式下,會自動選主,所有更新操作都在主上進行;
多主模式下,所有 server 都可以同時處理更新操作。
-  多寫,寫衝突檢測;

1.4   組複製故障檢測

故障檢測是提供關於哪些 server 可能已死的資訊(猜測)的分散式服務。 某個 server 無響應時觸發猜測,組中其餘成員進行協調決定以排除給定成員。如果某個 server 與組的其餘成員隔離,則它會懷疑所有其他 server 都失敗了。由於無法與組達成協議(因為它無法確保仲裁成員數),其懷疑不會產生後果。當伺服器以此方式與組隔離時,它無法執行任何本地事務。 線上 server 列表通常稱為檢視,新成員server的加入離開,無論是自願還是被迫的離開,該組都會動態地重新規劃其配置,並觸發檢視更新。

1.5   組複製的限制 

-  儲存引擎必須為Innodb,即僅支援InnoDB表,並且每張表一定要有一個主鍵,用於做write set的衝突檢測;
-  每個表必須提供主鍵;
-  只支援ipv4,網路需求較高;
必須開啟GTID特性,二進位制日誌格式必須設定為ROW,用於選主與write set;
-  COMMIT可能會導致失敗,類似於快照事務隔離級別的失敗場景;
-  目前一個MGR叢集組最多支援9個節點;
-  不支援外來鍵於save point特性,無法做全域性間的約束檢測與部分部分回滾;
-  二進位制日誌binlog不支援Replication event checksums;
-  多主模式(也就是多寫模式) 不支援SERIALIZABLE事務隔離級別;
-  多主模式不能完全支援級聯外來鍵約束;
-  多主模式不支援在不同節點上對同一個資料庫物件併發執行DDL(在不同節點上對同一行併發進行RW事務,後發起的事務會失敗);

二、組複製技術實現

2.1   組複製與傳統複製的區別和大幅改進

傳統複製
主-從複製: 有一個主和不等數量的從。主節點執行的事務會非同步傳送給從節點,在從節點重新執行。(非同步和半同步;半同步相對非同步Master會確認Slave是否接到資料,更加安全)
並行複製: 複製->廣播->正式複製

組複製相比傳統複製的優勢在於:
- 彈性複製(高擴充套件性): server動態新增移除;
- 高可用分片(高擴充套件性): 分片實現寫擴充套件,每個分片是一個複製組;
- 替代主從複製(高擴充套件性): 整組寫入,避免單點爭用;
- 自動化系統: 自動化部署Mysql複製到已有複製協議的自動化系統;
- 故障檢測與容錯: 自動檢測,若服務faild,組內成員大多數達成認為該服務已不正常,則自動隔離;

在MySQL組複製環境中,組內成員會構成一個檢視,組內成員主動加入或離開(主動或被動),都會更新組配置,更新檢視。成員自願離開,先更新組配置,然後採用大多數成員(不包含主動脫離的成員)意見是否確認該成員離開更新檢視。如果是故障要排除,則需大多數服務確認(包括故障成員意見),然後才會更新組配置和檢視。   

特別注意:組複製最大允許即時故障數:f=(n-1)/2,多數正常則正常

2.2   組複製優點小結

1) 在master-slave之間實現了強一致性;
對於只讀事務,組間例項無需進行通訊,就可以處理事務;對於讀寫(RW)事務,組內所有節點必須經過通訊,共同決定事務提交與否。

2) 事務衝突處理
在高併發的多寫模式下,節點間事務的提交可能會產生衝突,比如,兩個不同的事務在兩個節點上操作了同一行資料,這個時候就會產生衝突。首先,Group Replication(GR)能夠識別到這個衝突,然後對此的處理是,依賴事務提交的時間先後順序,先發起提交的節點能夠正確提交,而後面的提交,會失敗

3) 故障檢測
MGR自帶故障檢測機制,可以識別組內成員是否掛掉(組內節點心跳檢測)。當一個節點失效,將由其他節點決定是否將這個失效的節點從group裡面剔除。

4) 組成員管理
MGR需要維護組內節點的狀態(ONLINE,RECOVERING,OFFLINE),對於失效的節點,由其他節點決定是否剔除。對於新加入的節點,需要維護它的檢視與其他節點的檢視保持一致。

5) 容錯能力
MGR基於分散式一致性演算法實現,一個組允許部分節點掛掉,只要保證大多數節點仍然存活並且之間的通訊是沒有問題的,那麼這個組對外仍然能夠提供服務!假設一個MGR由2n+1個節點,那麼允許n個節點失效,這個MGR仍然能夠對外提供服務。比如有3個節點組成的一個GR,可允許1個節點失效,這個GR仍然能夠提供服務。

6) 部署方便簡單。

7) 最後結論
對比之前的5.6的雙主模式,5.7的組複製模式不管從部署還是管理都要方便很多。

2.3 組複製模式介紹

MGR提供了single-primary和multi-primary兩種模式。其中,single-primary mode(單寫模式) 組內只有一個節點負責寫入,讀可以從任意一個節點讀取,組內資料保持最終一致;multi-primary mode(多寫模式),即寫會下發到組內所有節點,組內所有節點同時可讀,也是能夠保證組內資料最終一致性。尤其要注意:一個MGR的所有節點必須配置使用同一種模式,不可混用!

1) 單寫模式
單寫模式group內只有一臺節點可寫可讀,其他節點只可以讀。

對於group的部署,需要先跑起primary節點(即那個可寫可讀的節點,read_only = 0)然後再跑起其他的節點,並把這些節點一一加進group。其他的節點就會自動同步primary節點上面的變化,然後將自己設定為只讀模式(read_only = 1)。當primary節點意外當機或者下線,在滿足大多數節點存活的情況下,group內部發起選舉,選出下一個可用的讀節點,提升為primary節點。primary選舉根據group內剩下存活節點的UUID按字典序升序來選擇,即剩餘存活的節點按UUID字典序排列,然後選擇排在最前的節點作為新的primary節點。

單寫模式部署(單機多例項)
在一個節點上執行三個MySQL例項,然後把其中一個例項部署為主,其他兩個節點部署為從;主寫,從讀;這種模式適用於實驗和自己練習。

特別重要:在切換primary期間,mysql group不會處理應用重連線到新的主,這需要應用層自己或者由另外的中介軟體層(proxy or router)去保證!

2) 多寫模式
group內的所有機器都是primary節點,同時可以進行讀寫操作,並且資料是最終一致的。
該模式不好的地方在於: 非rpm包安裝,目前使用rpm方式沒有配置成功;啟動還是處於手動方式,可以編寫sys V方式啟動指令碼;效能上面沒有做壓測。

多機單寫部署
在三個節點上分別部署MySQL例項,然後把其中一個例項部署為主節點,其他兩個節點部署為從節點;主寫,從讀; 當主節點OFFLINE(下線)時,兩個從節點會選舉出一個注節點,但是在應用中的連線IP是不會隨著更換的,需要重新進行配置。這種模式在節點故障率比較高的場景不適用,會導致應用找不到資料庫。

多機多寫部署
在三個節點上分別部署MySQL例項,每個節點都接收寫請求;額外可以加入一個節點,測試節點的動態增加。

                                           三、基於GTID的組複製分散式叢集的環境部署記錄                                          

需要清楚知道:MySQL複製組能夠以一種自動優先選擇的單主模式執行,在某個時間只有一個伺服器接受更新 。但是對於更高優先順序的使用者,組能夠以多主模式部署,所有的伺服器都能夠接受更新,即使它們是同時發生的。組複製中存在著一種內建的組成員關係服務用來保持組的檢視一致,並且在任意時間對於組中的所有的伺服器都可用。MySQL伺服器能夠退出或者加入組中,而且檢視也會相應的更新。有時伺服器可能會意外的退出組(故障),在這種情況下失敗檢測機制檢測這種情況並且告知複製組檢視發生了變化,這所有的一切都是自動實現的。 

3.1   實驗環境

[root@MGR-node1 ~]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)
  
為了方便實驗,關閉所有節點的防火牆
[root@MGR-node1 ~]# systemctl stop firewalld
[root@MGR-node1 ~]# firewall-cmd --state
not running
  
[root@MGR-node1 ~]# cat /etc/sysconfig/selinux |grep "SELINUX=disabled"
SELINUX=disabled
[root@MGR-node1 ~]# setenforce 0             
setenforce: SELinux is disabled
[root@MGR-node1 ~]# getenforce               
Disabled

特別要注意一個關鍵點: 必須保證各個mysql節點的主機名不一致,並且能通過主機名找到各成員!
則必須要在每個節點的/etc/hosts裡面做主機名繫結,否則後續將節點加入group組會失敗!報錯RECOVERING!!
[root@MGR-node1 ~]# cat /etc/hosts
........
172.16.60.211    MGR-node1
172.16.60.212    MGR-node2
172.16.60.213    MGR-node3

3.2   安裝Mysql5.7

在三個mysql節點機上使用yum方式安裝Mysql5.7,參考:https://www.cnblogs.com/kevingrace/p/8340690.html
  
安裝MySQL yum資源庫
[root@MGR-node1 ~]# yum localinstall https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
  
安裝MySQL 5.7
[root@MGR-node1 ~]# yum install -y mysql-community-server
  
啟動MySQL伺服器和MySQL的自動啟動
[root@MGR-node1 ~]# systemctl start mysqld.service
[root@MGR-node1 ~]# systemctl enable mysqld.service
  
設定登入密碼
由於MySQL從5.7開始不允許首次安裝後使用空密碼進行登入!為了加強安全性,系統會隨機生成一個密碼以供管理員首次登入使用,
這個密碼記錄在/var/log/mysqld.log檔案中,使用下面的命令可以檢視此密碼:
[root@MGR-node1 ~]# cat /var/log/mysqld.log|grep 'A temporary password'
2019-01-11T05:53:17.824073Z 1 [Note] A temporary password is generated for root@localhost: TaN.k:*Qw2xs
  
使用上面檢視的密碼TaN.k:*Qw2xs 登入mysql,並重置密碼為123456
[root@MGR-node1 ~]# mysql -p                 #輸入預設的密碼:TaN.k:*Qw2xs
.............
mysql> set global validate_password_policy=0;
Query OK, 0 rows affected (0.00 sec)
  
mysql> set global validate_password_length=1;
Query OK, 0 rows affected (0.00 sec)
  
mysql> set password=password("123456");
Query OK, 0 rows affected, 1 warning (0.00 sec)
  
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
  
檢視mysql版本
[root@MGR-node1 ~]# mysql -p123456
........
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.24    |
+-----------+
1 row in set (0.00 sec)
 
=====================================================================
溫馨提示
mysql5.7通過上面預設安裝後,執行語句可能會報錯:
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
 
這個報錯與Mysql 密碼安全策略validate_password_policy的值有關,validate_password_policy可以取0、1、2三個值:
解決辦法:
set global validate_password_policy=0;
set global validate_password_length=1;

3.3   MGR組複製配置 (本案例採用MGR多寫模式)

第一個節點MGR-node1的配置

先給這組MGR起個組名,組名可以隨便起,但是不能使用主機的GTID!
通過節點的uuid作為loose-group_replication_group_name的組名,並且每個節點的這個組名必須一樣!
這裡使用MGR-node1節點mysql裡的uuid作為組名
mysql> select uuid();
+--------------------------------------+
| uuid()                               |
+--------------------------------------+
| 5db40c3c-180c-11e9-afbf-005056ac6820 |
+--------------------------------------+
1 row in set (0.00 sec)
   
[root@MGR-node1 ~]# cp /etc/my.cnf /etc/my.cnf.bak
[root@MGR-node1 ~]# >/etc/my.cnf
[root@MGR-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
      
symbolic-links = 0
      
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid
  
#GTID:
server_id = 1
gtid_mode = on
enforce_gtid_consistency = on
  
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
      
#binlog
log_bin = mysql-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
     
#relay log
skip_slave_start = 1
  
transaction_write_set_extraction=XXHASH64      #以便在server收集寫集合的同時將其記錄到二進位制日誌。寫集合基於每行的主鍵,並且是行更改後的唯一標識此標識將用於檢測衝突。
loose-group_replication_group_name="5db40c3c-180c-11e9-afbf-005056ac6820"     #組的名字可以隨便起,但不能用主機的GTID! 所有節點的這個組名必須保持一致!
loose-group_replication_start_on_boot=off    #為了避免每次啟動自動引導具有相同名稱的第二個組,所以設定為OFF。
loose-group_replication_local_address= "172.16.60.211:24901"
loose-group_replication_group_seeds= "172.16.60.211:24901,172.16.60.212:24901,172.16.60.213:24901"
loose-group_replication_bootstrap_group=off
loose-group_replication_single_primary_mode=off      #關閉單主模式的引數(本例測試時多主模式,所以關閉該項)
loose-group_replication_enforce_update_everywhere_checks=on    #開啟多主模式的引數
loose-group_replication_ip_whitelist="172.16.60.0/24,127.0.0.1/8"    # 允許加入組複製的客戶機來源的ip白名單
   
===============================================================================
特別提示:
把MGR-node1的 /etc/my.cnf  檔案配置好後,直接拷貝給另外的兩個節點MGR-node2、MGR-node3
然後再在其他兩個節點上修改server_id和loose-group_replication_local_address即可,其他都不動!
[root@MGR-node1 ~]# rsync -e "ssh -p22" -avpgolr /etc/my.cnf root@172.16.60.212:/etc/
[root@MGR-node1 ~]# rsync -e "ssh -p22" -avpgolr /etc/my.cnf root@172.16.60.213:/etc/
===============================================================================
   
配置完成後,要記得重啟mysqld服務 (重啟之前,先情況mysqld服務日誌)
[root@MGR-node1 ~]# >/var/log/mysqld.log
[root@MGR-node1 ~]# systemctl restart mysqld
   
檢視mysql日誌
[root@MGR-node1 ~]# grep password /var/log/mysqld.log
2019-01-14T15:19:02.847387Z 0 [Note] Shutting down plugin 'validate_password'
2019-01-14T15:19:04.121045Z 0 [Note] Shutting down plugin 'sha256_password'
2019-01-14T15:19:04.121048Z 0 [Note] Shutting down plugin 'mysql_native_password'
   
登入mysql進行相關設定操作
[root@MGR-node1 ~]# mysql -p123456
............
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
   
mysql> SET SQL_LOG_BIN=0;                       #即不記錄二進位制日誌
Query OK, 0 rows affected (0.00 sec)
   
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_slave@'%' IDENTIFIED BY 'slave@123';
Query OK, 0 rows affected, 1 warning (0.00 sec)
   
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
   
mysql> reset master;
Query OK, 0 rows affected (0.11 sec)
   
mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)
   
mysql> CHANGE MASTER TO MASTER_USER='rpl_slave', MASTER_PASSWORD='slave@123' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.29 sec)
   
mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';            #安裝複製組外掛
Query OK, 0 rows affected (0.04 sec)
   
mysql> SHOW PLUGINS;
+----------------------------+----------+--------------------+----------------------+---------+
| Name                       | Status   | Type               | Library              | License |
+----------------------------+----------+--------------------+----------------------+---------+
| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     |
| sha256_password            | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     |
| CSV                        | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| MRG_MYISAM                 | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL                 | GPL     |
| partition                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| ngram                      | ACTIVE   | FTPARSER           | NULL                 | GPL     |
| rpl_semi_sync_master       | ACTIVE   | REPLICATION        | semisync_master.so   | GPL     |
| validate_password          | ACTIVE   | VALIDATE PASSWORD  | validate_password.so | GPL     |
| group_replication          | ACTIVE   | GROUP REPLICATION  | group_replication.so | GPL     |
+----------------------------+----------+--------------------+----------------------+---------+
47 rows in set (0.00 sec)
   
mysql> SET GLOBAL group_replication_bootstrap_group=ON;         #只在第一個節點執行這個步驟
Query OK, 0 rows affected (0.00 sec)
   
mysql> START GROUP_REPLICATION;
ERROR 3096 (HY000): The START GROUP_REPLICATION command failed as there was an error when initializing the group communication layer.
   
如上出現如上錯誤,則需要先stop之後做才可以
mysql> STOP GROUP_REPLICATION;
Query OK, 0 rows affected (0.00 sec)
  
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)
  
mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected (2.14 sec)
  
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)
  
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 317e2aad-1565-11e9-9c2e-005056ac6820 | MGR-node1   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
1 row in set (0.00 sec)
   
比如要保證上面的group_replication_applier的狀態為"ONLINE"才對!

建立一個測試庫
mysql> CREATE DATABASE kevin CHARACTER SET utf8 COLLATE utf8_general_ci;       
Query OK, 1 row affected (0.03 sec)

mysql> use kevin;
Database changed
mysql> create table if not exists haha (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.24 sec)

mysql> insert into kevin.haha values(1,"wangshibo"),(2,"guohuihui"),(3,"yangyang"),(4,"shikui");       
Query OK, 4 rows affected (0.07 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
|  3 | yangyang  |
|  4 | shikui    |
+----+-----------+
4 rows in set (0.00 sec)

第二個節點MGR-node2的配置

配置MGR-node2節點的my.cnf檔案 
只需要修改 server_id 和 loose-group_replication_local_address的配置即可 (和MGR-node1的my.cnf檔案配置相比較)

[root@MGR-node2 ~]# cat /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
    
symbolic-links = 0
    
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid

#GTID:
server_id = 2
gtid_mode = on
enforce_gtid_consistency = on

master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
    
#binlog
log_bin = mysql-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
   
#relay log
skip_slave_start = 1

transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="5db40c3c-180c-11e9-afbf-005056ac6820"
loose-group_replication_start_on_boot=off 
loose-group_replication_local_address= "172.16.60.212:24901"
loose-group_replication_group_seeds= "172.16.60.211:24901,172.16.60.212:24901,172.16.60.213:24901"
loose-group_replication_bootstrap_group=off
loose-group_replication_single_primary_mode=off 
loose-group_replication_enforce_update_everywhere_checks=on
loose-group_replication_ip_whitelist="172.16.60.0/24,127.0.0.1/8"

配置完成後,要記得重啟mysqld服務 (重啟之前,先情況mysqld服務日誌)
[root@MGR-node2 ~]# >/var/log/mysqld.log 
[root@MGR-node2 ~]# systemctl restart mysqld

檢視mysql日誌
[root@MGR-node2 ~]# grep password /var/log/mysqld.log
2019-01-14T15:53:14.293490Z 0 [Note] Shutting down plugin 'validate_password'
2019-01-14T15:53:16.144077Z 0 [Note] Shutting down plugin 'sha256_password'
2019-01-14T15:53:16.144080Z 0 [Note] Shutting down plugin 'mysql_native_password'

登入mysql進行相關設定操作
[root@MGR-node2 ~]# mysql -p123456
.........
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_slave@'%' IDENTIFIED BY 'slave@123';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> reset master;
Query OK, 0 rows affected (0.10 sec)

mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)

mysql> CHANGE MASTER TO MASTER_USER='rpl_slave', MASTER_PASSWORD='slave@123' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.21 sec)

mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';
Query OK, 0 rows affected (0.04 sec)

mysql> SHOW PLUGINS;
+----------------------------+----------+--------------------+----------------------+---------+
| Name                       | Status   | Type               | Library              | License |
+----------------------------+----------+--------------------+----------------------+---------+
| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     |
| sha256_password            | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     |
| CSV                        | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| MRG_MYISAM                 | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL                 | GPL     |
| partition                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| ngram                      | ACTIVE   | FTPARSER           | NULL                 | GPL     |
| rpl_semi_sync_slave        | ACTIVE   | REPLICATION        | semisync_slave.so    | GPL     |
| validate_password          | ACTIVE   | VALIDATE PASSWORD  | validate_password.so | GPL     |
| group_replication          | ACTIVE   | GROUP REPLICATION  | group_replication.so | GPL     |
+----------------------------+----------+--------------------+----------------------+---------+
47 rows in set (0.00 sec)

這裡只需要執行這一步即可!
mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected (4.58 sec)

檢視組內情況,發現MGR-node2已經成功加入這個組內了。
注意:這裡一定要將三個節點的/etc/hosts檔案裡繫結主機名,否則這裡新增組的時候會一直報錯:RECOVERING  (必須要是ONLINE才行)
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 2c1efc46-1565-11e9-ab8e-00505688047c | MGR-node2   |        3306 | ONLINE       |
| group_replication_applier | 317e2aad-1565-11e9-9c2e-005056ac6820 | MGR-node1   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
2 rows in set (0.00 sec)

檢視下,發現已經將MGR-node1節點新增的資料同步過來了
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
|  3 | yangyang  |
|  4 | shikui    |
+----+-----------+
4 rows in set (0.00 sec)

第三個節點MGR-node3的配置

配置MGR-node3節點的my.cnf檔案
只需要修改 server_id 和 loose-group_replication_local_address的配置即可 (和MGR-node1的my.cnf檔案配置相比較)

[root@MGR-node3 ~]# vim /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
    
symbolic-links = 0
    
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid

#GTID:
server_id = 3
gtid_mode = on
enforce_gtid_consistency = on

master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
    
#binlog
log_bin = mysql-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1
   
#relay log
skip_slave_start = 1

transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="5db40c3c-180c-11e9-afbf-005056ac6820"
loose-group_replication_start_on_boot=off 
loose-group_replication_local_address= "172.16.60.213:24901"
loose-group_replication_group_seeds= "172.16.60.211:24901,172.16.60.212:24901,172.16.60.213:24901"
loose-group_replication_bootstrap_group=off
loose-group_replication_single_primary_mode=off 
loose-group_replication_enforce_update_everywhere_checks=on
loose-group_replication_ip_whitelist="172.16.60.0/24,127.0.0.1/8"

配置完成後,要記得重啟mysqld服務 (重啟之前,先情況mysqld服務日誌)
[root@MGR-node3 ~]# >/var/log/mysqld.log
[root@MGR-node3 ~]# systemctl restart mysqld

檢視mysql日誌
[root@MGR-node3 ~]# grep password /var/log/mysqld.log
2019-01-14T16:40:15.251663Z 0 [Note] Shutting down plugin 'validate_password'
2019-01-14T16:40:16.997360Z 0 [Note] Shutting down plugin 'sha256_password'
2019-01-14T16:40:16.997363Z 0 [Note] Shutting down plugin 'mysql_native_password'

登入mysql進行相關設定操作
[root@MGR-node3 ~]# mysql -p123456
..........
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_slave@'%' IDENTIFIED BY 'slave@123';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

mysql> reset master;
Query OK, 0 rows affected (0.12 sec)

mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)

mysql> CHANGE MASTER TO MASTER_USER='rpl_slave', MASTER_PASSWORD='slave@123' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.29 sec)

mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so';
Query OK, 0 rows affected (0.03 sec)

mysql> SHOW PLUGINS;
+----------------------------+----------+--------------------+----------------------+---------+
| Name                       | Status   | Type               | Library              | License |
+----------------------------+----------+--------------------+----------------------+---------+
| binlog                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| mysql_native_password      | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     |
| sha256_password            | ACTIVE   | AUTHENTICATION     | NULL                 | GPL     |
| CSV                        | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| MEMORY                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL                 | GPL     |
| MyISAM                     | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| MRG_MYISAM                 | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| PERFORMANCE_SCHEMA         | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL                 | GPL     |
| partition                  | ACTIVE   | STORAGE ENGINE     | NULL                 | GPL     |
| ngram                      | ACTIVE   | FTPARSER           | NULL                 | GPL     |
| rpl_semi_sync_slave        | ACTIVE   | REPLICATION        | semisync_slave.so    | GPL     |
| validate_password          | ACTIVE   | VALIDATE PASSWORD  | validate_password.so | GPL     |
| group_replication          | ACTIVE   | GROUP REPLICATION  | group_replication.so | GPL     |
+----------------------------+----------+--------------------+----------------------+---------+
47 rows in set (0.00 sec)

這裡只需要執行這一步即可!
mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected (3.45 sec)

檢視組內情況,發現MGR-node3已經成功加入這個組內了。
注意:這裡一定要將三個節點的/etc/hosts檔案裡繫結主機名,否則這裡新增組的時候會一直報錯:RECOVERING  (必須要是ONLINE才行)
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 2658b203-1565-11e9-9f8b-005056880888 | MGR-node3   |        3306 | ONLINE       |
| group_replication_applier | 2c1efc46-1565-11e9-ab8e-00505688047c | MGR-node2   |        3306 | ONLINE       |
| group_replication_applier | 317e2aad-1565-11e9-9c2e-005056ac6820 | MGR-node1   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.00 sec)

檢視下,發現已經將在其他節點上新增的資料同步過來了
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
|  3 | yangyang  |
|  4 | shikui    |
+----+-----------+
4 rows in set (0.00 sec)

組複製資料同步測試

在任意一個節點上執行
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 2658b203-1565-11e9-9f8b-005056880888 | MGR-node3   |        3306 | ONLINE       |
| group_replication_applier | 2c1efc46-1565-11e9-ab8e-00505688047c | MGR-node2   |        3306 | ONLINE       |
| group_replication_applier | 317e2aad-1565-11e9-9c2e-005056ac6820 | MGR-node1   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.00 sec)

如上,說明已經在MGR-node1、MGR-node2、MGR-node3 三個節點上成功部署了基於GTID的組複製同步環境。
現在在三個節點中的任意一個上面更新資料,那麼其他兩個節點的資料庫都會將新資料同步過去的!

1)在MGR-node1節點資料庫更新資料
mysql> delete from kevin.haha where id>2;
Query OK, 2 rows affected (0.14 sec)

接著在MGR-node2、MGR-node3節點資料庫檢視,發現更新後資料已經同步過來了!
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
+----+-----------+
2 rows in set (0.00 sec)

2)在MGR-node2節點資料庫更新資料
mysql> insert into kevin.haha values(11,"beijing"),(12,"shanghai"),(13,"anhui");
Query OK, 3 rows affected (0.06 sec)
Records: 3  Duplicates: 0  Warnings: 0

接著在MGR-node1、MGR-node3節點資料庫檢視,發現更新後資料已經同步過來了!
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
| 11 | beijing   |
| 12 | shanghai  |
| 13 | anhui     |
+----+-----------+
5 rows in set (0.00 sec)

3)在MGR-node3節點資料庫更新資料
mysql> update kevin.haha set id=100 where name="anhui";
Query OK, 1 row affected (0.16 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> delete from kevin.haha where id=12;
Query OK, 1 row affected (0.22 sec)

接著在MGR-node1、MGR-node2節點資料庫檢視,發現更新後資料已經同步過來了!
mysql> select * from kevin.haha;
+-----+-----------+
| id  | name      |
+-----+-----------+
|   1 | wangshibo |
|   2 | guohuihui |
|  11 | beijing   |
| 100 | anhui     |
+-----+-----------+
4 rows in set (0.00 sec)

組複製故障測試

當組內的某個節點發生故障時,會自動從將該節點從組內踢出,與其他節點隔離。剩餘的節點之間保持主從複製的正常同步關係。當該節點的故障恢復後,只需手動啟用組複製即可(即執行"START GROUP_REPLICATION;");

1)比如 MGR-node1的mysql發生故障,比如關閉mysql服務(或者該節點網路故障,其他節點與之通訊失敗等)
[root@MGR-node1 mysql]# systemctl stop mysqld
[root@MGR-node1 mysql]# ps -ef|grep mysql
root      4662 26047  0 01:02 pts/0    00:00:00 grep --color=auto mysql
[root@MGR-node1 mysql]#
  
在剩餘的兩個節點中的任意一個檢視
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 2658b203-1565-11e9-9f8b-005056880888 | MGR-node3   |        3306 | ONLINE       |
| group_replication_applier | 2c1efc46-1565-11e9-ab8e-00505688047c | MGR-node2   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
2 rows in set (0.00 sec)
  
如上,在MGR-node1節點的mysql發生故障後,會自動從這個組內踢出,剩餘的兩個節點的組複製同步關係正常!
  
在MGR-node3節點更新資料
mysql> update kevin.haha set id=3 where name="anhui"; 
Query OK, 1 row affected (0.11 sec)
Rows matched: 1  Changed: 1  Warnings: 0
  
接在在另一個節點MGR-node2上檢視,發現更新資料已同步過來
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
|  3 | anhui     |
| 11 | beijing   |
+----+-----------+
4 rows in set (0.00 sec)
  
2)當MGR-node1節點的mysql服務恢復後,是什麼情況呢?
[root@MGR-node1 mysql]# systemctl start mysqld
[root@MGR-node1 mysql]# ps -ef|grep mysqld
mysql     4846     1  0 01:04 ?        00:00:00 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
root      4965 26047  0 01:05 pts/0    00:00:00 grep --color=auto mysqld
  
在剩餘的兩個節點中的任意一個檢視
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 2658b203-1565-11e9-9f8b-005056880888 | MGR-node3   |        3306 | ONLINE       |
| group_replication_applier | 2c1efc46-1565-11e9-ab8e-00505688047c | MGR-node2   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
2 rows in set (0.00 sec)
  
如上發現,MGR-node1節點恢復後,不會自動新增到組內,需要手動啟用下該節點的組複製功能
[root@MGR-node1 mysql]# mysql -p123456
...........
mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected (2.89 sec)
  
再次檢視,就會發現MGR-node1節點已經重新新增到組內了
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 2658b203-1565-11e9-9f8b-005056880888 | MGR-node3   |        3306 | ONLINE       |
| group_replication_applier | 2c1efc46-1565-11e9-ab8e-00505688047c | MGR-node2   |        3306 | ONLINE       |
| group_replication_applier | 317e2aad-1565-11e9-9c2e-005056ac6820 | MGR-node1   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.01 sec)
  
MGR-node1節點恢復後,並重新新增到組內後,其他節點更新的資料也會及時同步過來!
mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
|  3 | anhui     |
| 11 | beijing   |
+----+-----------+
4 rows in set (0.00 sec)
 
===========================================================================
要是三個節點都發生故障的話,在節點的故障都恢復後,需要手動重新做組複製,操作流程如下:
 
第一個節點
mysql> reset master;
mysql> SET SQL_LOG_BIN=1;
mysql> CHANGE MASTER TO MASTER_USER='rpl_slave', MASTER_PASSWORD='slave@123' FOR CHANNEL 'group_replication_recovery';
mysql> STOP GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
mysql> START GROUP_REPLICATION;
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
mysql> SELECT * FROM performance_schema.replication_group_members;
 
第二個節點
mysql> reset master;
mysql> SET SQL_LOG_BIN=1;
mysql> CHANGE MASTER TO MASTER_USER='rpl_slave', MASTER_PASSWORD='slave@123' FOR CHANNEL 'group_replication_recovery';
mysql> START GROUP_REPLICATION;
mysql> SELECT * FROM performance_schema.replication_group_members;
 
第三個節點
mysql> reset master;
mysql> SET SQL_LOG_BIN=1;
mysql> CHANGE MASTER TO MASTER_USER='rpl_slave', MASTER_PASSWORD='slave@123' FOR CHANNEL 'group_replication_recovery';
mysql> START GROUP_REPLICATION;
mysql> SELECT * FROM performance_schema.replication_group_members;

                                                             MGR節點由於網路出現異常導致的錯誤解決方法                                                                

MGR組內本來有三個節點,但是MGR-node3節點突然從複製組內踢出去了。
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 3fee1651-1eeb-11e9-a2f2-00505688047c | MGR-node2   |        3306 | ONLINE       |
| group_replication_applier | 40ecddaf-1eeb-11e9-94bf-005056ac6820 | MGR-node1   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.00 sec)

檢視MGR-node3節點日誌發現:
[root@MGR-node3 ~]# tail -f /var/log/mysqld.log
.........
2019-01-11T11:17:09.890375Z 0 [ERROR] Plugin group_replication reported: 'Member was expelled from the group due to network failures, changing member status to ERROR.'

錯誤日誌寫了是由於網路出現異常導致節點被踢出的組複製,試著重新加入群組:
mysql> start group_replication;
ERROR 3093 (HY000): The START GROUP_REPLICATION command failed since the group is already running.

解決辦法:先停掉這個MGR-node3節點的複製重新開啟試下
mysql> stop group_replication;
Query OK, 0 rows affected (7.18 sec)
 
mysql> start group_replication;
Query OK, 0 rows affected (3.32 sec)

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 340ed31a-1eeb-11e9-8221-005056880888 | MGR-node3   |        3306 | ONLINE       |
| group_replication_applier | 3fee1651-1eeb-11e9-a2f2-00505688047c | MGR-node2   |        3306 | ONLINE       |
| group_replication_applier | 40ecddaf-1eeb-11e9-94bf-005056ac6820 | MGR-node1   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.00 sec)

MGR-node3節點重新恢復到複製組內,檢視該節點的資料,發現資料也會同步過來的。
如果是多個節點是因為這個原因被踢出複製組,則採用上面方法進行恢復,至此所有節點都恢復正常!

MGR可以使用ProxySQL代理外掛,比如三個MGR寫節點,一個為當前寫節點,另外兩個為備份寫節點。當前寫節點發生故障後,會自會切換到其他正常的備份寫節點上。

                                                                                                                                                                                                                     

ProxySQL在MySQL的代理和負載均衡中一直處於領先地位,對MGR提供了很好的原生支援,其中包含了諸如快取查詢,多路複用,流量映象,讀寫分離,路由等等的強力功能。在最新的功能性增強中,包含了對MGR的原生支援,不在需要使用第三方指令碼進行適配。

最新的增強中,提供了對單寫和多寫叢集組的支援,甚至可以在多寫組上指定只由某個成員進行寫入操作。

在新版本的ProxySQL中,比如在一個七個節點的多寫叢集中,指定2組寫節點,2組備用寫節點,3個只讀節點的操作。即ProxySQL雖然識別出來所有的節點皆為寫節點,但只路由寫操作到選定的兩個寫節點(通過Hostgroup的方式),同時將另外兩個寫節點新增到備用寫節點組中,最後三個讀節點加入讀組。(本案例中的組皆為ProxySQL中的hostgroup含義)。除此之外,ProxySQL還可以限制連線訪問叢集中超出最大設定落後事務值的慢節點(應該是通過mysql_servers.max_replication_lag來控制)

基於以上部署的MGR節點環境 (即 3 個master節點的多寫叢集),以下記錄ProxySQL + MGR (多寫模式) 配置過程:

在172.16.60.211/212/213  三個節點中的任意一個節點的mysql上執行:

mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | a2078290-1f25-11e9-b50e-00505688047c | MGR-node2   |        3306 | ONLINE       |
| group_replication_applier | aaf67b46-1f25-11e9-a9a1-005056ac6820 | MGR-node1   |        3306 | ONLINE       |
| group_replication_applier | b5df6e60-1f25-11e9-b1bd-005056880888 | MGR-node3   |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.00 sec)

mysql> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
| 11 | beijing   |
| 12 | shanghai  |
+----+-----------+
4 rows in set (0.00 sec)

可以看出,基於上述部署的MGR環境,3個master節點的多寫模式,現在MGR組複製內的三個節點都是ONLINE線上同步狀態。

現在追加一臺節點172.16.60.220作為ProxySQL代理節點,操作記錄如下:

1) 準備工作

[root@mysql-proxy ~]# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core) 

[root@mysql-proxy ~]# hostnamectl set-hostname mysql-proxy 
[root@mysql-proxy ~]# hostname
mysql-proxy

[root@mysql-proxy ~]# systemctl stop firewalld
[root@mysql-proxy ~]# firewall-cmd --state
not running

[root@mysql-proxy ~]# setenforce 0
[root@mysql-proxy ~]# cat /etc/sysconfig/selinux |grep "SELINUX=disabled"
SELINUX=disabled

[root@mysql-proxy ~]# hostname -I
172.16.60.220

-  安裝mysql客戶端,用於在本機連線到ProxySQL的管理介面

[root@mysql-proxy ~]# vim /etc/yum.repos.d/mariadb.repo
[mariadb] 
name = MariaDB
baseurl = http://yum.mariadb.org/10.3.5/centos6-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
  
安裝mysql-clinet客戶端
[root@mysql-proxy ~]# yum install -y MariaDB-client
 
============================================================================
如果遇到報錯:
Error: MariaDB-compat conflicts with 1:mariadb-libs-5.5.60-1.el7_5.x86_64
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest
  
解決辦法:
[root@mysql-proxy ~]# rpm -qa|grep mariadb
mariadb-libs-5.5.60-1.el7_5.x86_64

[root@mysql-proxy ~]# rpm -e mariadb-libs-5.5.60-1.el7_5.x86_64 --nodeps
[root@mysql-proxy ~]# yum install -y MariaDB-client

-  安裝proxysql

proxysql的rpm包下載地址: https://pan.baidu.com/s/1S1_b5DKVCpZSOUNmtCXrrg
提取密碼: 5t1c
 
[root@mysql-proxy ~]# yum install -y perl-DBI perl-DBD-MySQL
[root@mysql-proxy ~]# rpm -ivh proxysql-1.4.8-1-centos7.x86_64.rpm --force
 
配置檔案詳解
[root@mysql-proxy ~]# egrep -v "^#|^$" /etc/proxysql.cnf
datadir="/var/lib/proxysql"                                   #資料目錄
admin_variables=
{
        admin_credentials="admin:admin"                       #連線管理端的使用者名稱與密碼
        mysql_ifaces="0.0.0.0:6032"                           #管理埠,用來連線proxysql的管理資料庫!
}
mysql_variables=
{
        threads=4                                             #指定轉發埠開啟的執行緒數量
        max_connections=2048
        default_query_delay=0
        default_query_timeout=36000000
        have_compress=true
        poll_timeout=2000
        interfaces="0.0.0.0:6033"                             #指定轉發埠,用於連線後端真實mysql資料庫的,相當於代理作用!
        default_schema="information_schema"
        stacksize=1048576
        server_version="5.5.30"                               #指定後端mysql的版本
        connect_timeout_server=3000
        monitor_username="monitor"
        monitor_password="monitor"
        monitor_history=600000
        monitor_connect_interval=60000
        monitor_ping_interval=10000
        monitor_read_only_interval=1500
        monitor_read_only_timeout=500
        ping_interval_server_msec=120000
        ping_timeout_server=500
        commands_stats=true
        sessions_sort=true
        connect_retries_on_failure=10
}
mysql_servers =
(
)
mysql_users:
(
)
mysql_query_rules:
(
)
scheduler=
(
)
mysql_replication_hostgroups=
(
)
 
# 在部署過程中,最好使用官方推薦的方式來配置proxy sql

-  啟動服務並檢視

[root@mysql-proxy ~]# /etc/init.d/proxysql start
Starting ProxySQL: DONE!
 
[root@mysql-proxy ~]# ss -lntup|grep proxy
tcp    LISTEN     0      128       *:6032                  *:*                   users:(("proxysql",pid=2943,fd=24))
tcp    LISTEN     0      128       *:6033                  *:*                   users:(("proxysql",pid=2943,fd=22))
tcp    LISTEN     0      128       *:6033                  *:*                   users:(("proxysql",pid=2943,fd=21))
tcp    LISTEN     0      128       *:6033                  *:*                   users:(("proxysql",pid=2943,fd=20))
tcp    LISTEN     0      128       *:6033                  *:*                   users:(("proxysql",pid=2943,fd=19))

-  先初始化Proxysql,將之前的proxysql資料都刪除

[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032                          
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.30 (ProxySQL Admin Module)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> show tables;
+--------------------------------------------+
| tables                                     |
+--------------------------------------------+
| global_variables                           |
| mysql_collations                           |
| mysql_group_replication_hostgroups         |
| mysql_query_rules                          |
| mysql_query_rules_fast_routing             |
| mysql_replication_hostgroups               |
| mysql_servers                              |
| mysql_users                                |
| proxysql_servers                           |
| runtime_checksums_values                   |
| runtime_global_variables                   |
| runtime_mysql_group_replication_hostgroups |
| runtime_mysql_query_rules                  |
| runtime_mysql_query_rules_fast_routing     |
| runtime_mysql_replication_hostgroups       |
| runtime_mysql_servers                      |
| runtime_mysql_users                        |
| runtime_proxysql_servers                   |
| runtime_scheduler                          |
| scheduler                                  |
+--------------------------------------------+
20 rows in set (0.001 sec)

MySQL [(none)]> delete from scheduler ;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> delete from mysql_servers;
Query OK, 3 rows affected (0.000 sec)

MySQL [(none)]> delete from mysql_users;
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> delete from mysql_query_rules;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> delete from mysql_group_replication_hostgroups ;
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> LOAD MYSQL VARIABLES TO RUNTIME;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> SAVE MYSQL VARIABLES TO DISK;
Query OK, 94 rows affected (0.175 sec)

MySQL [(none)]> LOAD MYSQL SERVERS TO RUNTIME;
Query OK, 0 rows affected (0.003 sec)

MySQL [(none)]> SAVE MYSQL SERVERS TO DISK;
Query OK, 0 rows affected (0.140 sec)

MySQL [(none)]> LOAD MYSQL USERS TO RUNTIME;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> SAVE MYSQL USERS TO DISK;
Query OK, 0 rows affected (0.050 sec)

MySQL [(none)]> LOAD SCHEDULER TO RUNTIME;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> SAVE SCHEDULER TO DISK;
Query OK, 0 rows affected (0.096 sec)

MySQL [(none)]> LOAD MYSQL QUERY RULES TO RUNTIME;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> SAVE MYSQL QUERY RULES TO DISK;
Query OK, 0 rows affected (0.156 sec)

MySQL [(none)]> 

-  增加proxysql所需要的檢視以及儲存過程,建立系統檢視 (sys.gr_member_routing_candidate_status)

在MGR-node1節點上,建立系統檢視sys.gr_member_routing_candidate_status,該檢視將為ProxySQL提供組複製相關的監控狀態指標。
下載addition_to_sys.sql指令碼,在MGR-node1節點執行如下語句匯入MySQL即可 (在mgr-node1節點的mysql執行後,會同步到其他兩個節點上)。

下載地址: https://pan.baidu.com/s/1bNYHtExy2fmqwvEyQS3sWg
提取密碼:wst7

[root@MGR-node1 ~]# ll /root/addition_to_sys.sql 
-rwxr-xr-x 1 root root 2647 Jan 24 17:14 /root/addition_to_sys.sql

匯入sql檔案
[root@MGR-node1 ~]# mysql -p123456 < /root/addition_to_sys.sql
mysql: [Warning] Using a password on the command line interface can be insecure.

在三個mysql節點上可以檢視該檢視:
mysql> select * from sys.gr_member_routing_candidate_status;
+------------------+-----------+---------------------+----------------------+
| viable_candidate | read_only | transactions_behind | transactions_to_cert |
+------------------+-----------+---------------------+----------------------+
| YES              | NO        |                   0 |                    0 |
+------------------+-----------+---------------------+----------------------+
1 row in set (0.01 sec)

-  在mysql-master主資料庫節點上執行:(只需master執行即可,會複製給slave從資料庫)  (即建立代理埠連線後端真實資料庫的使用者名稱和密碼)

mysql> GRANT ALL ON *.* TO 'proxysql'@'172.16.60.%' IDENTIFIED BY 'proxysql';        
Query OK, 0 rows affected, 1 warning (0.03 sec)
 
mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)

-  proxysql增加帳號

MySQL [(none)]> INSERT INTO MySQL_users(username,password,default_hostgroup) VALUES ('proxysql','proxysql',2);
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> UPDATE global_variables SET variable_value='proxysql' where variable_name='mysql-monitor_username';
Query OK, 1 row affected (0.002 sec)

MySQL [(none)]> UPDATE global_variables SET variable_value='proxysql' where variable_name='mysql-monitor_password';  
Query OK, 1 row affected (0.002 sec)

-  mysql_servers插入資料 (下面插入命令中的ip也可以換成各個節點的主機名,其他是可自都做了hosts主機名繫結)

MySQL [(none)]> insert into mysql_servers (hostgroup_id, hostname, port) values(2,'172.16.60.211',3306);
Query OK, 1 row affected (0.001 sec)

MySQL [(none)]> insert into mysql_servers (hostgroup_id, hostname, port) values(2,'172.16.60.212',3306);
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> insert into mysql_servers (hostgroup_id, hostname, port) values(2,'172.16.60.213',3306);
Query OK, 1 row affected (0.000 sec)

MySQL [(none)]> select * from mysql_servers;
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| hostgroup_id | hostname      | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
| 2            | 172.16.60.211 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.16.60.212 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
| 2            | 172.16.60.213 | 3306 | ONLINE | 1      | 0           | 1000            | 0                   | 0       | 0              |         |
+--------------+---------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+---------+
3 rows in set (0.000 sec)

-  將MGR叢集的分組定義和關鍵引數寫入mysql_group_replication_hostgroups

如下,執行插入命令 "insert into mysql_group_replication_hostgroups (writer_hostgroup,backup_writer_hostgroup,reader_hostgroup, offline_hostgroup,active,max_writers,writer_is_also_reader,max_transactions_behind) values (2,4,3,1,1,1,0,100);"

MySQL [(none)]> insert into mysql_group_replication_hostgroups (writer_hostgroup,backup_writer_hostgroup,reader_hostgroup, offline_hostgroup,active,max_writers,writer_is_also_reader,max_transactions_behind) values (2,4,3,1,1,1,0,100);
Query OK, 1 row affected (0.000 sec)

-  將上面對proxysql所有的變更都載入到環境中

MySQL [(none)]> LOAD MYSQL VARIABLES TO RUNTIME;
Query OK, 0 rows affected (0.001 sec)

MySQL [(none)]> SAVE MYSQL VARIABLES TO DISK;
Query OK, 94 rows affected (0.071 sec)

MySQL [(none)]> LOAD MYSQL SERVERS TO RUNTIME;
LOAD MYSQL USERS TO RUNTIME;
Query OK, 0 rows affected (0.005 sec)

MySQL [(none)]> SAVE MYSQL SERVERS TO DISK;
SAVE MYSQL USERS TO DISK;
Query OK, 0 rows affected (0.260 sec)

MySQL [(none)]> LOAD MYSQL USERS TO RUNTIME;
Query OK, 0 rows affected (0.000 sec)

MySQL [(none)]> SAVE MYSQL USERS TO DISK;
Query OK, 0 rows affected (0.101 sec)

-  接下來檢查下ProxySQL是如何將MGR節點分發到ProxySQL各個組中
表名前面多了一個runtime字首,group2為writer groupgroup4為backup_writer_group, 如下說明172.16.60.213為當前Proxysql連線的節點,其它兩個為備用寫節點:

MySQL [(none)]> select hostgroup_id, hostname, status from runtime_mysql_servers;
+--------------+---------------+--------+
| hostgroup_id | hostname      | status |
+--------------+---------------+--------+
| 2            | 172.16.60.213 | ONLINE |
| 4            | 172.16.60.212 | ONLINE |
| 4            | 172.16.60.211 | ONLINE |
+--------------+---------------+--------+
3 rows in set (0.003 sec)

-  如果當前Proxysql連線的節點172.16.60.213出現故障,測試看能否切換到其它節點

如果當前Proxysql連線的節點172.16.60.213出現故障,測試看能否切換到其它節點; 然後再看下172.16.60.213節點的故障恢復後的情況:

將172.16.60.213節點設為read only
[root@MGR-node3 ~]# mysql -p123456
..........
mysql> set global read_only=1;
Query OK, 0 rows affected (0.00 sec)

再看一下runtime_mysql_servers的狀態
[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
..........
MySQL [(none)]> select hostgroup_id, hostname, status from runtime_mysql_servers;
+--------------+---------------+--------+
| hostgroup_id | hostname      | status |
+--------------+---------------+--------+
| 2            | 172.16.60.212 | ONLINE |
| 3            | 172.16.60.213 | ONLINE |
| 4            | 172.16.60.211 | ONLINE |
+--------------+---------------+--------+
3 rows in set (0.003 sec)

發現已經將172.16.60.213節點設為group3了,group3為reader_group。
現在可寫的節點即當前Proxysql連線的節點改成了172.16.60.212了。

將172.16.60.213節點恢復為可寫模式
[root@MGR-node3 ~]# mysql -p123456
..........
mysql> set global read_only=0;
Query OK, 0 rows affected (0.00 sec)

發現runtime_mysql_servers也恢復了過來,即172.16.60.213節點又恢復到了寫節點,其他兩個都是備寫節點
[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032
..........
MySQL [(none)]> select hostgroup_id, hostname, status from runtime_mysql_servers;
+--------------+---------------+--------+
| hostgroup_id | hostname      | status |
+--------------+---------------+--------+
| 2            | 172.16.60.213 | ONLINE |
| 4            | 172.16.60.212 | ONLINE |
| 4            | 172.16.60.211 | ONLINE |
+--------------+---------------+--------+
3 rows in set (0.003 sec)

-  資料讀寫操作的分配情況

登入proxysql的代理埠,連線到代理後端的真實資料庫上進行資料更新操作
[root@mysql-proxy ~]# mysql -uproxysql -pproxysql -h 127.0.0.1 -P 6033
...........
...........
MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.001 sec)

MySQL [(none)]> select * from kevin.haha;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
|  2 | guohuihui |
| 11 | beijing   |
| 12 | shanghai  |
+----+-----------+
4 rows in set (0.001 sec)

MySQL [(none)]> delete from kevin.haha where id>11;
Query OK, 1 row affected (0.086 sec)

MySQL [(none)]> update kevin.haha set id=100 where name="beijing";
Query OK, 1 row affected (0.072 sec)
Rows matched: 1  Changed: 1  Warnings: 0

MySQL [(none)]> select * from kevin.haha;                         
+-----+-----------+
| id  | name      |
+-----+-----------+
|   1 | wangshibo |
|   2 | guohuihui |
| 100 | beijing   |
+-----+-----------+
3 rows in set (0.001 sec)

登入proxysql的管理埠,檢視資料讀寫分配情況
[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032        
..........
..........
MySQL [(none)]> select * from stats_mysql_query_digest;
+-----------+--------------------+----------+--------------------+------------------------------------------------------------------+------------+------------+------------+----------+----------+----------+
| hostgroup | schemaname         | username | digest             | digest_text                                                      | count_star | first_seen | last_seen  | sum_time | min_time | max_time |
+-----------+--------------------+----------+--------------------+------------------------------------------------------------------+------------+------------+------------+----------+----------+----------+
| 2         | information_schema | proxysql | 0x95C1EAD704156371 | delete from kevin.haha where id>?                                | 2          | 1548400603 | 1548644794 | 262487   | 85409    | 177078   |
| 2         | information_schema | proxysql | 0xA307FE1E53D63E71 | select hostgroup_id, hostname, status from runtime_mysql_servers | 2          | 1548400698 | 1548644762 | 1222     | 508      | 714      |
| 2         | information_schema | proxysql | 0x8E490D39ED5CA9E2 | delete from kevin.haha id>?                                      | 2          | 1548400598 | 1548644787 | 626      | 299      | 327      |
| 2         | information_schema | proxysql | 0xB23E08156F2F7F49 | SELECT * FROM performance_schema.replication_group_members       | 2          | 1548399582 | 1548399585 | 8102940  | 1037     | 8101903  |
| 2         | information_schema | proxysql | 0xDFD4E74AA19CD894 | update kevin.haha set id=? where name=?                          | 3          | 1548399161 | 1548644931 | 251211   | 62493    | 116731   |
| 2         | information_schema | proxysql | 0xF6FA5DFBB674D5FF | delete from kevin.haha where id > ?                              | 1          | 1548399125 | 1548399125 | 116382   | 116382   | 116382   |
| 2         | information_schema | proxysql | 0xD8AAAE77FA99AC44 | select * from kevin.haha                                         | 10         | 1548399099 | 1548644933 | 4984     | 323      | 948      |
| 2         | information_schema | proxysql | 0x9316817E8C74BCB2 | insert into kevin.haha values(?,?),(?,?),(?,?)                   | 1          | 1548399128 | 1548399128 | 73118    | 73118    | 73118    |
| 2         | information_schema | proxysql | 0x02033E45904D3DF0 | show databases                                                   | 4          | 1548398871 | 1548644766 | 4122     | 566      | 2132     |
| 2         | information_schema | proxysql | 0x226CD90D52A2BA0B | select @@version_comment limit ?                                 | 10         | 1548398868 | 1548644760 | 0        | 0        | 0        |
+-----------+--------------------+----------+--------------------+------------------------------------------------------------------+------------+------------+------------+----------+----------+----------+
10 rows in set (0.002 sec)

發現資料的讀寫操作都被分配到group2組內,即讀寫操作走的都是group2組內的172.16.60.213節點。

=============================================================
現在將172.16.60.213模擬為故障狀態
[root@MGR-node3 ~]# mysql -p123456
...........
mysql> set global read_only=1;
Query OK, 0 rows affected (0.00 sec)

登入proxysql的管理埠
[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032             
...........
MySQL [(none)]> select hostgroup_id, hostname, status from runtime_mysql_servers;
+--------------+---------------+--------+
| hostgroup_id | hostname      | status |
+--------------+---------------+--------+
| 2            | 172.16.60.212 | ONLINE |
| 3            | 172.16.60.213 | ONLINE |
| 4            | 172.16.60.211 | ONLINE |
+--------------+---------------+--------+
3 rows in set (0.001 sec)

發現此時的寫節點更換為172.16.60.212了,172.16.60.213節點分配到group3 (只讀組)

登入proxysql的代理埠,連線到代理後端的真實資料庫上進行資料更新操作
[root@mysql-proxy ~]# mysql -uproxysql -pproxysql -h 127.0.0.1 -P 6033
............
............
MySQL [(none)]> create database shibo;
Query OK, 1 row affected (0.036 sec)

MySQL [(none)]> drop database shibo;
Query OK, 0 rows affected (0.031 sec)

MySQL [information_schema]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| kevin              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.001 sec)

MySQL [information_schema]> delete from kevin.haha where id>1;
Query OK, 5 rows affected (0.098 sec)

MySQL [information_schema]> select * from kevin.haha;         
+----+-----------+
| id | name      |
+----+-----------+
|  1 | wangshibo |
+----+-----------+
1 row in set (0.001 sec)

登入proxysql的管理埠,檢視資料讀寫分配情況
MySQL [(none)]> select * from stats_mysql_query_digest;
+-----------+--------------------+----------+--------------------+------------------------------------------------------------------+------------+------------+------------+----------+----------+----------+
| hostgroup | schemaname         | username | digest             | digest_text                                                      | count_star | first_seen | last_seen  | sum_time | min_time | max_time |
+-----------+--------------------+----------+--------------------+------------------------------------------------------------------+------------+------------+------------+----------+----------+----------+
| 2         | information_schema | proxysql | 0x58710084C1F7DFA7 | drop database shibo                                              | 1          | 1548645734 | 1548645734 | 31097    | 31097    | 31097    |
| 2         | information_schema | proxysql | 0xD880C8B266964B45 | create database shibo                                            | 1          | 1548645692 | 1548645692 | 36262    | 36262    | 36262    |
| 2         | information_schema | proxysql | 0x3EA85877510AC608 | select * from stats_mysql_query_digest                           | 1          | 1548645635 | 1548645635 | 380      | 380      | 380      |
| 2         | information_schema | proxysql | 0x226CD90D52A2BA0B | select @@version_comment limit ?                                 | 13         | 1548398867 | 1548645681 | 0        | 0        | 0        |
| 2         | information_schema | proxysql | 0x02033E45904D3DF0 | show databases                                                   | 5          | 1548398870 | 1548645741 | 4729     | 566      | 2132     |
| 2         | information_schema | proxysql | 0x9316817E8C74BCB2 | insert into kevin.haha values(?,?),(?,?),(?,?)                   | 2          | 1548399127 | 1548645427 | 182202   | 73118    | 109084   |
| 2         | information_schema | proxysql | 0xD8AAAE77FA99AC44 | select * from kevin.haha                                         | 15         | 1548399098 | 1548645796 | 7915     | 323      | 1200     |
| 2         | information_schema | proxysql | 0xF6FA5DFBB674D5FF | delete from kevin.haha where id > ?                              | 1          | 1548399124 | 1548399124 | 116382   | 116382   | 116382   |
| 2         | information_schema | proxysql | 0x620B328FE9D6D71A | SELECT DATABASE()                                                | 1          | 1548645734 | 1548645734 | 288      | 288      | 288      |
| 2         | information_schema | proxysql | 0xDFD4E74AA19CD894 | update kevin.haha set id=? where name=?                          | 3          | 1548399160 | 1548644930 | 251211   | 62493    | 116731   |
| 2         | information_schema | proxysql | 0xB23E08156F2F7F49 | SELECT * FROM performance_schema.replication_group_members       | 2          | 1548399581 | 1548399584 | 8102940  | 1037     | 8101903  |
| 2         | information_schema | proxysql | 0xA307FE1E53D63E71 | select hostgroup_id, hostname, status from runtime_mysql_servers | 2          | 1548400697 | 1548644761 | 1222     | 508      | 714      |
| 2         | information_schema | proxysql | 0x8E490D39ED5CA9E2 | delete from kevin.haha id>?                                      | 2          | 1548400597 | 1548644786 | 626      | 299      | 327      |
| 2         | information_schema | proxysql | 0x95C1EAD704156371 | delete from kevin.haha where id>?                                | 3          | 1548400602 | 1548645795 | 360087   | 85409    | 177078   |
+-----------+--------------------+----------+--------------------+------------------------------------------------------------------+------------+------------+------------+----------+----------+----------+
14 rows in set (0.001 sec)

恢復172.16.60.213的寫
mysql> set global read_only=0;
Query OK, 0 rows affected (0.00 s屬性ec)

登入proxysql的管理埠
[root@mysql-proxy ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032 
.........
MySQL [(none)]> select hostgroup_id, hostname, status from runtime_mysql_servers;
+--------------+---------------+--------+
| hostgroup_id | hostname      | status |
+--------------+---------------+--------+
| 2            | 172.16.60.213 | ONLINE |
| 4            | 172.16.60.212 | ONLINE |
| 4            | 172.16.60.211 | ONLINE |
+--------------+---------------+--------+
3 rows in set (0.003 sec)

這裡說明幾點
-  MGR多寫模式下如上配置後,讀寫操作始終是寫到當前的group2寫組內的節點。
-  即使是某一個節點設定為read only (分配到group3內),mysql讀寫操作也只會通過proxysql始終代理到group2組內的節點上。
-  本案例只是可以實現MGR組複製的高可用,資料並沒有進行讀寫分離。要想實現讀寫分離,需另行配置路由轉發規則。
-  本案例實現了proxysql代理後的MGR的高可用,但是proxysql代理層存在單點。線上環境,建議部署proxysql高可用環境。

                                                                                MGR無感知切換的高可用方案實現方式思考                                                                            

ProxySQL+MGR部署的兩種模型:
1) 靠近應用端
方式: 在應用伺服器上直接部署

優點:
-  每個應用伺服器有自己的配置 ,配置內容簡單,不容易相互影響故障,變更故障風險最小
-  沒有瓶頸壓力,故障容錯最好,單機故障影響最小
-  資料庫上可以清楚看到SQL來自哪臺應用機器,方便排查故障
-  無需單獨機器資源

缺點:
-  每臺應用伺服器上都需要配置,當資料庫架構擴容或者其他變動時,需要應用則的ProxySQL做相應改動
-  當一臺應用上需要連線多套資料庫時,配置也會開始稍微複雜

2) 靠近資料庫端
方式: 通過獨立的ProxySQL叢集來提供服務

優點:
-  不需要每臺應用伺服器上配置,集中修改

缺點:
-  容易出現瓶頸,網路、機器效能等
-  集中配置,導致配置非常複雜,可能相互影響,變更故障風險高
-  全部應用通過ProxySQL來連線,資料庫上看到具體問題連線來自哪臺應用機器,無法進行故障定位
-  需要單獨的機器資源來部署ProxySQL,因為流量集中且是應用層,需要考慮效能瓶頸,佔用機器資源相對較多
-  機器故障時,影響是面級,通過額外高可用技術來減少影響

綜合上面的優缺點來說,使用ProxySQL+MGR來實現應用切換無感知方案其實並不大合適,Haproxy等方案也有類似問題。
所以建議採用下面方案來實現MGR無感知切換:
-  使用浮動IP來實現Mysql MGR的寫高可用(浮動IP需要自己實現)。 
-  使用LVS來實現Mysql MGR或者普通複製(擴充套件庫)讀庫的高可用和負載均衡
-  使用DNS域名切換來實現不同機房的切換

在實際線上業務中,MGR無感知故障切換的高可用可以使用的具體方案 (比如三個寫節點的MGR):
1)可以利用Keepalived,配置三個VIP,三個MGR節點之間實現相互"兩兩主從"關係,具體的keepalive的配置可參考:  https://www.cnblogs.com/kevingrace/p/6248941.html  (文章最後提高了3個VIP的配置)。 keepalived配置中監控mysql服務,當mysql服務掛掉時,實現vip漂移。然後對外提供一個域名 (最好是內網域名), 該域名解析指向這三個VIP地址。
2)在MGR的上層配置ProxySQL代理,通過ProxySQL實現負載均衡和讀寫分離,然後配置Keepaliced,通過浮動VIP實現ProxySQL的無感知切換。同樣,Keepalived配置中監控ProxySQL服務,當ProxySQL服務掛掉時,實現VIP漂移。

相關文章