但是,但是,但是,問題來了,雖然滿足了一主多從,讀寫分析,數據一致,但是,依舊有兩個弊端:
涉及知識點 故障探測( Failure Detection): Group Replication中有一個故障檢測機制,會提供某些節點可能死掉的信息,然後廣播給同一個Group的各個節點,如果確定宕機,那麼組內的節點就會與它隔離開來,該節點即無法同步其他節點的傳送過來的binlog events,也無法執行任何本地事務。 這裡有個問題,故障探測中,假設N個節點,一個節點故障,是采用多數投票機制還是全部一致投票機制?
這裡需要注意到,搭建group的時候,每個實例中的auto_increment_increment跟auto_increment_offset的配置情況。
1 mysql> show global variables like 'auto_inc%'; 2 +--------------------------+---------+ 3 | Variable_name | Value | 4 +--------------------------+---------+ 5 | auto_increment_increment | 7 | 6 | auto_increment_offset | 2143340 | 7 +--------------------------+---------+ 8 2 rows in set (0.00 sec)
1 #查看當前主機名 2 hostname 3 4 #修改主機名 5 hostname sutest242 6 7 #進入vim /etc/hosts 8 #添加記錄,不要修改默認的 127.0.0.1跟::1的記錄,其他的系統服務會使用到的 9 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 10 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 11 192.168.9.242 sutest242 12 192.168.9.244 sutest244配置後檢查如下:
1 #動態配置: 2 set global transaction_write_set_extraction='XXHASH64'; 3 set global group_replication_start_on_boot=OFF; 4 set global group_replication_bootstrap_group = OFF ; 5 set global group_replication_group_name= '9ac06b4e-13aa-11e7-a62e-5254004347f9'; #某個UUID 6 set global group_replication_local_address='192.168.9.242:24201'; 7 set global group_replication_group_seeds ='192.168.9.242:24201,192.168.9.242:24202,192.168.9.242:24401'; 8 set global group_replication_ip_whitelist = '127.0.0.1/8,192.168.9.0/24'; 9 set global group_replication_single_primary_mode=True; 10 set global group_replication_enforce_update_everywhere_checks=False; 11 12 #cnf文件配置: 13 server-id=12001 14 transaction_write_set_extraction = XXHASH64 15 loose-group_replication_group_name = '9ac06b4e-13aa-11e7-a62e-5254004347f9' 16 loose-group_replication_ip_whitelist = '127.0.0.1/8,192.168.9.0/24' 17 loose-group_replication_start_on_boot = OFF 18 loose-group_replication_local_address = '192.168.9.242:24201' 19 loose-group_replication_group_seeds = '192.168.9.242:24201,192.168.9.242:24202,192.168.9.242:24401' 20 loose-group_replication_bootstrap_group = OFF 21 loose-group_replication_single_primary_mode = true 22 loose-group_replication_enforce_update_everywhere_checks = false這一步這裡采用配置文件添加的方式,添加成功後重啟數據庫服務。
1 #實例A 2 #1 查看當前的group replication相關參數是否配置有誤 3 show global variables like 'group%'; 4 5 #2 啟動 group_replication_bootstrap_group 6 SET GLOBAL group_replication_bootstrap_group=ON; 7 8 #3 配置MGR 9 CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; 10 11 #4 啟動MGR 12 start group_replication; 13 14 #5 查看Error log,截圖如下 15 #error log如果有問題,拉到本文末端,對應找錯誤,如果沒有解決,請google或者留言 16 17 #6 關閉 group_replication_bootstrap_group 18 SET GLOBAL group_replication_bootstrap_group=OFF;進入到數據目錄,發現新建了幾個文件: *_apaplier.* 系列文件 提供 SQL_Thread 使用,存儲同個組內其他SERVER的binnary log,這個文件在第一個組成員加入組的時候,可以在Error Log看到其安裝信息。 *_recovery.* 系列文件 是做什麼使用的呢,在第一個成員啟動MGR的時候,並沒有看到其相關信息,稍後解疑! 先在實例A上開始造數據,建立數據庫mgr,建立表格tb1,INSERT部分數據,操作如下: #實例A mysql> create database mgr; Query OK, 1 row affected (0.01 sec) mysql> use mgr Database changed mysql> create table tb1(id int primary key auto_increment not null,name varchar(100)); Query OK, 0 rows affected (0.10 sec) mysql> insert into tb1(name) select @@server_id; Query OK, 1 row affected (0.09 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into tb1(name) select @@server_id; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into tb1(name) select @@server_id; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> insert into tb1(name) select @@server_id; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from tb1; +----+---------+ | id | name | +----+---------+ | 6 | 2423310 | | 13 | 2423310 | | 20 | 2423310 | | 27 | 2423310 | +----+---------+ 4 rows in set (0.00 sec) mysql> show master status; +----------------+----------+--------------+------------------+------------------------------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +----------------+----------+--------------+------------------+------------------------------------------+ | bin_log.000002 | 1795 | | | 9ac06b4e-13aa-11e7-a62e-5254004347f9:1-7 | +----------------+----------+--------------+------------------+------------------------------------------+ 1 row in set (0.00 sec) 模擬數據操作 接著,對實例B 進行操作:
1 #實例B 2 #1 查看當前的group replication相關參數是否配置有誤 3 show global variables like 'group%'; 4 5 #2 配置MGR 6 CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; 7 8 #3 啟動MGR 9 start group_replication; 10 11 #4 查看Error log,截圖如下 12 #error log如果有問題,拉到本文末端,對應找錯誤,如果沒有解決,請google或者留言
通過errrlog,可以詳細看到啟動過程的所有步驟信息,由於新增數據,導致實例B需要使用到 group_replication_recovery 通道來恢復數據。但是是怎麼一個恢復過程呢?查看 *_recovery.* 系列文件 都是只有文件頭沒有binlog內容的文件。 在加入實例C之前,再次在實例A上造數據,這次造多多數據。新建表格tb2,設置2個大字段,然後insert 2w+的數據量。
1 #實例A 2 mysql> use mgr 3 Database changed 4 mysql> create table tb2(id int auto_increment primary key not null,namea varchar(8000),nameb varchar(8000)); 5 Query OK, 0 rows affected (0.03 sec) 6 7 mysql> insert into tb2(namea,nameb) select repeat('a',8000),repeat('b',8000); 8 Query OK, 1 row affected (0.02 sec) 9 Records: 1 Duplicates: 0 Warnings: 0 10 11 #insert 自行操作,看試驗需要,本次需要大量數據來recovery,所以後面采用 insert into tb2 .. select .. from tb2 方式造數據 2w+行最後,對實例C 進行操作:
1 #實例C 2 #1 查看當前的group replication相關參數是否配置有誤 3 show global variables like 'group%'; 4 5 #2 配置MGR 6 CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; 7 8 #3 啟動MGR 9 start group_replication; 10 11 #4 查看Error log,截圖如下 12 #error log如果有問題,拉到本文末端,對應找錯誤,如果沒有解決,請google或者留言通過errrlog,可以詳細看到啟動過程的所有步驟信息,由於新增數據,導致實例C需要使用到 group_replication_recovery 通道來恢復數據,這跟實例B是一模一樣的過程,但是,由於前期實例A造了大量的數據,所以在整個recovery的過程中,可以查看到 *_recovery.* 系列文件 的變化情況。 通過error log大小的變化,是通過group_replication_recovery 通道來恢復數據,需要恢復的binary log是存放在 *_recovery.* 系列文件 ,通過本次recovery 文件查看,發現,在recovery過程中,通道內的IO_THREAD拉去日志存儲在 *_recovery.* 系列文件 中,當通道內的 SQL_Thread 完成日志應用後,則會刪除掉 *_recovery.* 系列文件 文件,新建空文件,代表已經沒有數據需要恢復。 至此,單主模式已搭建結束,實例A可提供讀寫,但是實例B跟實例C僅提供讀服務。
在搭建的過程中,也理清了兩個重要通道的使用情況:
# 動態修復方式 set global group_replication_single_primary_mode=OFF; # 配置文件修改方式 loose-group_replication_single_primary_mode = OFF但是,既然說到配置多主模式,除了從頭就直接配置多主外,還有一種情況是,本來是單主模式,現在修改為多主模式,這個轉換過程,則是這部分要來描述的。 首先,考慮到的是,能否直接在多主模式運行的情況下,就直接動態修改這個參數呢?因為這個參數是可以動態調整,BUT,在 GROUP_REPLICATION 運行的過程中,是不能修改這個參數的,會友好的提示您: 所以,需要新停掉GROUP_REPLICATION。 操作流程:業務端連接IP處理 -> GROUP內成員逐個依次主動退出GROUP -> 關閉 group_replication_single_primary_mode參數-> 逐個啟動GROUP內的SERVER
1 #實例A 2 stop group_replication; 3 4 #檢查實例B,C的error log,發現實例A主動退出,group成員刪除實例AError Log內容如下: 這個時候,A可讀寫,但是不在group中,其binlog內容不會在組內同步;C升級自動升級為主庫,可讀寫,binlog會同步到B上。這裡的主庫升級,是看MEMBER_ID的升序排序情況,最小的升級為主庫。 在B上通過表格 replication_group_members跟global_status,可以查看現在的組成員以及主庫是哪個。查看截圖如下: 連接實例B:
1 #實例B 2 stop group_replication; 3 4 #檢查實例B,C的error log,發現實例A主動退出,group成員刪除實例A這個時候,A,B均可以讀寫,但是不在GROUP中,業務目前在A上運行,C也可以讀寫,目前是主庫。 連接實例C:
#實例c stop group_replication;這個時候,整個GROUP內的所有成員都依次自動退出了GROUP。
#動態修改 #實例A set global group_replication_single_primary_mode =OFF #實例B set global group_replication_single_primary_mode =OFF #實例C set global group_replication_single_primary_mode =OFF #配置文件添加 #實例A的cnf文件中修改 loose-group_replication_single_primary_mode = OFF #實例B的cnf文件中修改 loose-group_replication_single_primary_mode = OFF #實例C的cnf文件中修改 loose-group_replication_single_primary_mode = OFF為了模擬有業務在實例A上操作,在實例A上創建表格 tb4,並導入tb2的所有數據
#實例A mysql> create table tb4 like tb2; Query OK, 0 rows affected (0.18 sec) mysql> insert into tb4 select * from tb2; Query OK, 20480 rows affected (33.13 sec) Records: 20480 Duplicates: 0 Warnings: 0
#實例A #需要啟動 group_replication_bootstrap_group 引導組,啟動後需要關閉,防止腦裂 mysql> set global group_replication_bootstrap_group=ON; Query OK, 0 rows affected (0.00 sec) mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; Query OK, 0 rows affected, 2 warnings (0.02 sec) mysql> START GROUP_REPLICATION; Query OK, 0 rows affected (1.16 sec) mysql> set global group_replication_bootstrap_group=Off; Query OK, 0 rows affected (0.00 sec) #實例B mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; Query OK, 0 rows affected, 2 warnings (0.04 sec) mysql> start group_replication; Query OK, 0 rows affected (4.31 sec) #實例C mysql> CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; Query OK, 0 rows affected, 2 warnings (0.07 sec) mysql> start group_replication; Query OK, 0 rows affected (3.83 sec)
mysql> select * from performance_schema.replication_group_members; +---------------------------+--------------------------------------+-------------+-------------+--------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | +---------------------------+--------------------------------------+-------------+-------------+--------------+ | group_replication_applier | 2ec0fecd-16a2-11e7-97e1-52540005b8e1 | sutest244 | 3340 | ONLINE | | group_replication_applier | 94e39808-15ed-11e7-a7cf-52540005b8e2 | sutest242 | 3310 | ONLINE | | group_replication_applier | 9b78d231-15ed-11e7-a82a-52540005b8e2 | sutest242 | 3320 | ONLINE | +---------------------------+--------------------------------------+-------------+-------------+--------------+ 3 rows in set (0.21 sec) mysql> select * from performance_schema.global_status where variable_name like '%group%'; +----------------------------------+----------------+ | VARIABLE_NAME | VARIABLE_VALUE | +----------------------------------+----------------+ | group_replication_primary_member | | +----------------------------------+----------------+ 1 row in set (0.35 sec) mysql> show global variables like 'group_replication_single_primary_mode'; +---------------------------------------+-------+ | Variable_name | Value | +---------------------------------------+-------+ | group_replication_single_primary_mode | OFF | +---------------------------------------+-------+ 1 row in set (0.33 sec) mysql> show global variables like 'super%'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | super_read_only | OFF | +-----------------+-------+ 1 row in set (1.20 sec)至此,多主模式已搭建結束,實例A、B、C均可提供讀寫。PS: 這裡需要注意沖突處理機制,可以查看第五部分的故障模擬。
節選測試過程的圖,跟之前配置的GROUP有些不一致,理解注重思路即可,部分測試細節沒有再次描述。
select * from performance_schema.replication_group_members; select * from performance_schema.global_status where VARIABLE_NAME='group_replication_primary_member'; show global variables like 'server_uuid'; show global variables like 'super%'; select * from performance_schema.replication_connection_status; select * from performance_schema.replication_applier_status;
模擬group中,有三個實例,端口分別為 3320,3330,3340,用簡稱來 m3320、m3330、m3340來分別描述。
m3330在屬於主庫,模擬其主庫宕機,使用 kill 進程方式,當m3330宕機後,m3320及m3340檢查到 timeout reading,則會從group_member中剔除該實例,同時檢測宕機實例是否小於 floor((n-1)/2) (n為group中所有實例個數),如果滿足,則啟動新的GROUP,按照GROUP中各個實例的UUID進行 升序排序,選擇第一個作為新的主庫,由於新主庫之前是super_read_only狀態,僅支持只讀,升級為新主庫後,會執行 ,不設置 super_read_only,關閉此參數,那麼新主庫則是可提供讀寫服務,原先的從庫現在依舊為從庫,super_read_only依舊為啟動狀態,僅提供讀服務。CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; START GROUP_REPLICATION;其他兩個節點檢查連接情況,連接無誤後,加入group中,更新 GROUP Member,同時開始同步差異binlog日志內容。
1 innobackupex --datadir=/data/mysql/mysql3320/data/ --user=root --password=ycf.com --no-timestamp --socket=/tmp/mysql3320.sock /data/backup3320 2 innobackupex --apply-log /data/backup3320第一次啟動數據庫時,報錯,找不到relay log文件,因為拷貝過來的時候 ,備份庫指定參數如下,mysql庫中的master_relay_log_info指定了relay log的相關信息,但是現在沒有找到文件,數據庫會自動創建 applier跟recovery系列文件。 master_info_repository=TABLE relay_log_info_repository=TABLE 所以需要進入數據庫中,truncate 兩個表格:mysql.slave_master_info, mysql.slave_relay_log_info ,然後刪除 applier跟recovery系列文件 。
1 truncate table mysql.slave_master_info 2 truncate table mysql.slave_relay_log_info 3 4 rm -rf applier系列文件 5 rm -rf recovery系列文件查看下備份的GTID集合,如下 重啟數據庫服務,進入數據庫,重新配置GTID集合與備份中的一致,啟動GROUP_REPLICATION。
RESET MASTER; SET @@GLOBAL.GTID_PURGED='9ac06b4e-13aa-11e7-a62e-5254004347f9:1-10';
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; START GROUP_REPLICATION;
SET @@GLOBAL.GTID_PURGED='9ac06b4e-13aa-11e7-a62e-5254004347f9:1-18'; #看GTID集合是否一致 CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; START GROUP_REPLICATION;
#部分參考SQL
SET @@GLOBAL.GTID_PURGED='9ac06b4e-13aa-11e7-a62e-5254004347f9:1-26:1000004'; CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='replforslave' FOR CHANNEL 'group_replication_recovery'; START GROUP_REPLICATION;
1 ip間隔是 逗號
2 不要有分號,本人就這麼笨的開始!
3 port是使用端口號 ,非實例端口號
4 [ERROR] Plugin group_replication reported: 'This member has more executed transactions than those present in the group. Local transactions: 32538cbf-12fc-11e7-af43-5254004347f9:1-5 > Group transactions: 2236bd6b-12fc-11e7-a706-5254004347f9:1-16
[ERROR] Plugin group_replication reported: 'This member has more executed transactions than those present in the group. Local transactions: 32538cbf-12fc-11e7-af43-5254004347f9:1-5 > Group transactions: 2236bd6b-12fc-11e7-a706-5254004347f9:1-16,9ac06b4e-13aa-11e7-a62e-5254004347f9:1'[ERROR] Plugin group_replication reported: 'The member contains transactions not present in the group. The member will now exit the group.'
[Note] Plugin group_replication reported: 'To force this member into the group you can use the group_replication_allow_local_disjoint_gtids_join option'
5 [ERROR] Plugin group_replication reported: 'Table te does not have any PRIMARY KEY. This is not compatible with Group Replication'
表格需要添加主鍵
6 mysql> insert into ct(id,name) select 2,'b'; ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
只讀模式下,不提供寫服務。
7 [ERROR] Plugin group_replication reported: 'Transaction cannot be executed while Group Replication is on ERROR state. Check for errors and restart the plugin' 2017-03-29T15:46:13.619141Z 31 [ERROR] Run function 'before_commit' in plugin 'group_replication' failed
GROUP出錯了,是否是重復執行沖突了,好好處理下