目錄
一、組複製性能
1. 概述
組複製的基本保證是,只有在組中的大多數節點接收到事務並且就併發事務的相對順序達成一致之後,纔會提交事務。其對事務的基本處理流程爲:
- 在提交之前攔截服務器接收到的客戶端事務,並構建事務寫入集。該寫入集唯一標識了對應事務所修改的數據集合。
- 將寫入集發送給組成員,並就併發事務的應用順序達成一致。
- 如果事務與之前的事務不存在衝突則提交,否則回滾該事務。即相互衝突的事務第一個成功提交,其它回滾。
影響組複製性能的組件主要有三個:組通信層、認證和二進制日誌應用程序。
(1)組通信層
組複製實現了一個基於Paxos協議的組通信層,以允許多個服務器在事務提交順序上達成一致。發送給組通信層的消息在每個組成員中以相同的順序接收。Paxos協議很複雜,但爲了理解組複製中實現變體對性能的影響,需要知道處理一個典型消息的過程:
- 從消息源向每個其它組成員發送帶有用戶事務的消息。
- 向消息源發送每個接收者的投票信息,當達到多數票後,客戶端將消息視爲已傳遞。
- 將消息源所接收的信息發送給其它所有組成員。
由此可見,組複製性能的關鍵因素是網絡吞吐量(可以在網絡通道中容納多少並行消息)和節點到節點的延遲(需要多長時間才能與發送方達成一致)。Paxos的組複製實現包括許多優化,如並行處理多條消息,並將多個消息打包成一個消息,以便在可能的時候發送到每個節點。從用戶角度來看到的結果是:
- 在現有網絡帶寬下,發送者將儘可能多的事務發送到其它節點。節點間的實際帶寬是網絡帶寬除以組成員數量。
- 在準備好提交之後,每個事務將被延遲至少從發送者到接收者的一箇中間網絡往返時間。
(2)認證
從組通信層接收到的事務消息會被放入一個隊列進行認證。在每個節點中運行的算法判斷認證結果以決定如何處理事務。若認證通過,事務被認爲在面向客戶端的服務器(事務發起方)上完成,然後在本地中繼日誌中排隊,以便在其它組成員上執行後續操作。反之如果認證失敗,事務將根據需要被丟棄或回滾。
認證是在每個節點接收到正確排序的事務消息後獨立完成的,因此不需要進一步的網絡同步活動。認證算法在一個專用線程中運行,該線程遵循由組通信層建立的事務順序,如果事務是遠程的,則將其寫入中繼日誌。因爲認證每個事務都需要時間,所以該過程可能成爲爭用點。影響認證吞吐量的主要因素是中繼日誌帶寬,如果用於本地中繼日誌的存儲子系統(即認證事務排隊等待應用程序線程的存儲子系統)無法跟上寫入請求,其事務認證隊列開始增長,事務應用開始落後於發起事務的成員。從下面的查詢可以獲得每個組成員認證隊列大小的近似值:
select member_id, count_transactions_in_queue from performance_schema.replication_group_member_stats;
多主組複製中,由於多個組成員都可以執行寫事務,gtid_executed集合的複雜性可能成爲另一個影響認證性能的因素。當多個成員同時向組寫入時,認證數據庫上執行的大量gtid_executed集合可能變得難以處理,因爲其中可能出現許多間隙,並且無法按照GTID範圍進行壓縮。這也可以看作是成員節點之間的吞吐量平衡性降低了。
(3)二進制日誌應用程序
將事務寫入中繼日誌後,它們就可以像異步或半同步複製一樣,由複製的二進制日誌應用程序執行。然而,組複製的二進制日誌應用程序有一個應該注意的細微差別。一旦組成員對事務進行了認證,認證程序會立即將事務更新行標記爲已更改,但實際該事務可能會在中繼日誌中保留一段時間等待應用。多主模式中,在此期間嘗試更改這些行的本地事務都被回滾。
與MySQL傳統主從異步複製同理,具有足夠線程的MTS(multi-threaded slave)應用程序來處理接收到的工作負載,有助於增加從庫的吞吐量。對於異步複製,LOGICAL_CLOCK調度程序使用二進制日誌組提交機制來確定哪些事務可以在從庫上並行執行。組提交能提高從庫併發度。但是,存儲子系統速度太快或客戶端併發量太小都會使提交組中的事務變少(一個組提交不能包含來自同一客戶端的多個事務),從而降低了效率。尤其是在級聯複製中,因爲複製線程通常比用戶線程少的多,這意味着較低級別從庫的並行度更低。
使用選項binlog_group_commit_sync_delay或binlog_group_commit_sync_no_delay_count可以增加提交組中的事務數量,以抵消存儲速度過快的影響。而基於寫集(WRITESET)的依賴跟蹤允許更高的並行度,特別是在低併發工作負載下。基於寫集的依賴項跟蹤可能重新排序來自同一會話的事務,這意味着來自同一會話的兩個事務在主從庫的提交順序可能不同。以犧牲一點性能爲代價,可以選擇強制使用slave_preserve_commit_order選項來保持從庫上會話歷史與主庫保持一致。
組複製考慮了用於驗證每個成員中事務的寫入集,並根據認證順序和事務更改的數據行構建依賴項。如果兩個事務在其寫入集中存在相同的行,則它們不能在從庫中並行運行,因此後一個更新這些行的事務將依賴於前一個事務。
關於多線程複製的詳細討論,參見“MySQL 8 複製(六)——拓撲與性能”。
簡單說,組複製性能受限於組通信層、認證和二進制日誌應用程序三個主要組件:
- 缺乏網絡帶寬會降低在途消息數量,而高的網絡往返時間會相應地增加用戶事務延遲。
- 缺乏中繼日誌存儲帶寬會延遲認證,因此要注意認證隊列的增長。
- 二進制日誌應用程序瓶頸除了會增加複製延遲外,還可能增加多主場景中的事務中止。
對於每個組件,組複製提供了若干選項,適當配置這些選項可以從底層計算資源中獲取最佳性能。後面小節中將詳細介紹這些選項。
MySQL官方描述的組複製性能影響因素,參見http://mysqlhighavailability.com/tuning-mysql-group-replication-for-fun-and-profit/。
2. 測試規劃
在討論具體選項配置前,希望使用一個統一的測試方法,對比不同配置值對複製性能產生的影響,測量的指標包括主、從庫的每秒事務數(TPS)和從庫的複製延遲時長。測試目的在於對比不同配置情況下組複製的性能,而不是針對測量絕對值進行優化。這裏使用的思路是:主庫加壓,同時從庫複製。記錄加壓前後的GTID,得到需要執行的總事務數。主庫的執行時間等於加壓時間。等待從庫應用完所有事務,記錄從庫的執行時間。用總事務數除以相應執行時間得到主、從庫的TPS。加壓使用tpcc-mysql基準測試工具。
(1)測試環境
單主模式下一主兩從的組複製基本信息如下:
單主庫:172.16.1.125
從庫1:172.16.1.126
從庫2:172.16.1.127
MySQL版本:8.0.16
操作系統:CentOS Linux release 7.2.1511 (Core)
硬件配置:
三個服務器均爲Linux虛擬機,雙核雙 2.10GHz CPU,8G物理內存,100G硬盤空間,1000MB/s 網卡。MySQL實例基本配置:
[mysqld]
server_id=1125 # 兩個從庫爲1126、1127
gtid_mode=ON
enforce-gtid-consistency=true
innodb_buffer_pool_size=4G
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
log_bin=binlog
log_slave_updates=ON
binlog_format=ROW
binlog_checksum=NONE
master_info_repository=TABLE
relay_log_info_repository=TABLE
plugin-load=group_replication.so
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address= "172.16.1.125:33061" # 兩個從庫爲"172.16.1.126:33061"、"172.16.1.127:33061"
group_replication_group_seeds= "172.16.1.125:33061,172.16.1.126:33061,172.16.1.127:33061"
group_replication_bootstrap_group=off
爲保證不同配置的測試環境相同,每次修改配置後重啓三個MySQL實例。開始測試前,使用下面的腳本重啓組複製:
-- 主
change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;
select * from performance_schema.replication_group_members;
-- 從
stop slave;
reset slave all;
change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
start group_replication;
(2)測試腳本
每次測試只需要執行同一個腳本文件tpcc_test.sh,內容如下:
[mysql@hdp2~/tpcc-mysql-master]$more tpcc_test.sh
# 初始化tpcc數據
mysql -uwxy -p123456 -h172.16.1.125 < tpcc_test.sql
# 開始GTID
read start_gtid < <(mysql -uwxy -p123456 -e "show variables like 'gtid_executed';" --skip-column-names | awk '{print $2}' | sed "s/\\\n//g")
# 等待從庫執行完初始化複製
mysql -uwxy -p123456 -h172.16.1.126 -e "select wait_for_executed_gtid_set('$start_gtid');" > /dev/null &
mysql -uwxy -p123456 -h172.16.1.127 -e "select wait_for_executed_gtid_set('$start_gtid');" > /dev/null
# 開始時間
start_time=`date '+%s'`
# 主庫執行壓測,10個倉庫,32個併發線程,預熱1分鐘,壓測5分鐘
tpcc_start -h172.16.1.125 -d tpcc_test -u wxy -p "123456" -w 10 -c 32 -r 60 -l 300 > tpcc_test.log 2>&1
# 結束GTID
read end_gtid < <(mysql -uwxy -p123456 -e "show variables like 'gtid_executed';" --skip-column-names | awk '{print $2}' | sed "s/\\\n//g")
# 等待從庫執行完複製
mysql -uwxy -p123456 -h172.16.1.126 -e "select wait_for_executed_gtid_set('$end_gtid'); select unix_timestamp(now());" --skip-column-names | awk 'NR>1' > end_time1 &
mysql -uwxy -p123456 -h172.16.1.127 -e "select wait_for_executed_gtid_set('$end_gtid'); select unix_timestamp(now());" --skip-column-names | awk 'NR>1' > end_time2
# 結束時間
end_time1=`cat end_time1`
end_time2=`cat end_time2`
# 複製執行時長
elapsed1=$(($end_time1 - $start_time))
elapsed2=$(($end_time2 - $start_time))
# 執行的事務數
read start end < <(mysql -uwxy -p123456 -e "select gtid_subtract('$end_gtid','$start_gtid');" --skip-column-names | awk -F: '{print $2}' | awk -F- '{print $1,$2}')
trx=$(($end - $start + 1))
# 計算主庫、從庫的TPS
Master_TPS=`expr $trx / 360`
Slave1_TPS=`expr $trx / $elapsed1`
Slave2_TPS=`expr $trx / $elapsed2`
# 打印輸出
echo "TRX: $trx"
echo "Master TPS: $Master_TPS"
echo "Elapsed1: $elapsed1" "Slave1 TPS: $Slave1_TPS"
echo "Elapsed2: $elapsed2" "Slave2 TPS: $Slave2_TPS"
關於tpcc工具的安裝和tpcc_test.sql文件的生成及作用,參見https://wxy0327.blog.csdn.net/article/details/94614149#1.%20%E6%B5%8B%E8%AF%95%E8%A7%84%E5%88%92。每條指令前的註釋已經明確表明其用途,這裏做兩點補充說明:
- MySQL組複製要求表具有主鍵。tpcc測試庫中的history表沒有主鍵,因此需要手工編輯tpcc_test.sql文件,在其建表的create table語句中增加主鍵定義。這完全是爲了滿足組複製的要求,因此只要將所有字段一起定義成聯合主鍵即可,即使出現主鍵重複的錯誤,也不會影響測試繼續進行。況且這裏要得到的只是對比結果,而測試結果的絕對值並無多大參考意義。
- 使用MySQL 5.7.5新增的wait_for_executed_gtid_set函數,等待從庫應用完事務,返回複製結束時間。本測試中採用一主兩從的組複製拓撲,需要並行但分別取得兩個從庫的結束時間,因此使用 & 符號,將第一條執行wait_for_executed_gtid_set的命令在後臺執行。這樣可以獲得兩個從庫各自的執行時間,而後面的命令會在它們都執行完後纔開始執行,而不論它們誰先執行完。
(3)執行缺省配置測試
獲得缺省配置的測試結果,作爲後面不同配置的對比基準。測試結果如下:
TRX: 176527
Master TPS: 490
Elapsed1: 708 Slave1 TPS: 249
Elapsed2: 922 Slave2 TPS: 191
缺省配置下,主庫360秒內執行了 176527 個事務,TPS爲490。從庫1執行了708秒,比主庫延時了348秒,TPS爲249。而從庫2更慢,執行了922秒,比主庫延時了562秒,TPS僅爲191。
3. 消息壓縮
當網絡帶寬成爲瓶頸時,消息壓縮可以在組通信層提高吞吐量。如圖1所示,壓縮發生在組通信系統API級別,因此事務負載可以在被髮送到組之前被壓縮,並且在成員接收事務時進行解壓縮。壓縮使用LZ4算法,閾值缺省爲1000000字節,由group_replication_compression_threshold參數控制,即只壓縮大於該參數指定字節數的事務,設置爲0將禁用壓縮。收到消息後,組成員檢查消息是否被壓縮。如果需要,該成員在將事務交付給上層之前解壓縮該事務。組複製不要求組中的所有服務器都同時啓用壓縮。
將group_replication_compression_threshold設置爲0、100、1024時的測試結果如下表:
group_replication_compression_threshold |
TRX |
Master TPS |
Slave1 Elapsed |
Slave1 TPS |
Slave2 Elapsed |
Slave2 TPS |
0 |
175932 |
488 |
727 |
241 |
914 |
192 |
100 |
175384 |
487 |
715 |
233 |
895 |
195 |
1024 |
176601 |
490 |
743 |
237 |
904 |
195 |
禁用壓縮、壓縮大於100字節的事務、壓縮大於1K字節的事務,與缺省壓縮大於1000000字節的事務相比,在我的測試環境中,主、從庫的TPS、從庫複製延時並無顯著差異。結論是此測試環境和負載壓力下,網絡傳輸不是瓶頸,因此後面的測試保持group_replication_compression_threshold的缺省值不變。
4. 組通信線程循環
組通信線程(Group Communication Thread,GCT)在加載組複製插件後循環運行。GCT從組插件接收消息,處理仲裁和故障檢測相關任務,發送活動消息,並處理服務器和組之間的雙向事務傳輸。當隊列中沒有消息時,GCT進入睡眠狀態。通過在實際進入睡眠狀態之前將等待時間設置爲稍長,即進行主動等待,在某些情況下是有益的,因爲GCT頻繁休眠可能浪費可用的CPU時間。要強制GCT執行活動等待,使用group_replication_poll_spin_loops選項。此選項控制GCT在進入睡眠狀態前嘗試接收消息的次數,也可說是控制通信線程的貪婪程度,缺省值爲0。在網速很慢的環境中,適當配置該選項可以降低事務延遲。
這裏沒有針對group_replication_poll_spin_loops參數進行不同配置的實驗,原因有二:一是在我的實驗環境下網絡不是瓶頸,這點從上面的壓縮選項測試中已經得到佐證。二是即便在慢網環境中,按MySQL官方文檔的說法,該選項也只是作爲一種微調手段。
5. 寫入集
在前面測試執行過程中,通過執行查詢觀察認證隊列中的事務數量:
select member_id, count_transactions_in_queue from performance_schema.replication_group_member_stats;
發現count_transactions_in_queue的值始終很小,大於0的時候非常少,而且最大也不過十幾。從組複製的流程可知,認證不存在積壓情況。但是從庫延遲如此之大,網絡無瓶頸,認證不積壓,剩下就是針對二進制日誌應用程序做調整了。從前面的組複製性能概述中,自然想到了MTS和WRITESET,於是修改以下配置選項繼續測試。
- 主庫啓用寫入集增加組提交併行度
binlog_transaction_dependency_tracking = WRITESET
transaction_write_set_extraction = XXHASH64
- 從庫啓用8線程MTS
slave_parallel_type = LOGICAL_CLOCK
slave_parallel_workers = 8
slave_preserve_commit_order=1
測試結果如下:
TRX: 175459
Master TPS: 487
Elapsed1: 478 Slave1 TPS: 367
Elapsed2: 589 Slave2 TPS: 297
可以看到,總事務數和主庫的TPS沒有基本不變,但兩個從庫的TPS卻增加了50%以上,吞吐量明顯得到提升。但即便如此,兩個從庫的複製延遲還是分別將近2分和4分鐘。說明在此壓力負載下,從庫無力追趕上主庫。如果一定要縮減主從之間的複製延遲時間,就要啓用下面介紹限流措施。
MySQL官方提供的寫入集與多線程下組複製基準測試,參見https://mysqlhighavailability.com/zooming-in-on-group-replication-performance/。
6. 流控
組複製可確保事務僅在組中的大多數成員收到事務,並同意所有併發發送事務之間的相對順序後提交。如果對組的寫入總量不超過組中任何成員的寫入容量,則此方法很有效。如果某些成員的寫入吞吐量低於其它成員,特別是少於主庫,那些成員可能會開始落後於主庫。必須強調的是,MySQL組複製並不要求成員保持同步,複製延遲只會增加本地中繼日誌中掛起的事務數。
成員落後於組會帶來一些問題,例如:對這些成員的讀取可能會使舊數據外化到應用程序;組中其它成員可能必須保存更多複製上下文,以便能夠滿足來自慢成員的數據傳輸請求等等。組複製協議中存在一種被稱爲流量控制的機制,可以避免快速和慢速成員之間的應用事務存在太大距離。它試圖達到的主要目標是保持成員的已執行事務足夠接近。
流量控制依賴於兩種基本機制:
- 監控服務器,收集所有組成員的吞吐量和隊列大小統計數據,對每個成員可以承受的最大寫入量進行有根據的猜測。
- 限制服務器,避免寫入超出其可用容量限制。
(1)探測和統計
監控機制的工作原理是讓每個成員部署一組探針來收集有關其工作隊列和吞吐量的信息。成員會定期將該信息傳播給組,以便與其它成員共享這些統計數據。此類探針分散在整個插件中,允許建立以下指標:
- 認證隊列大小。
- 複製應用程序隊列大小。
- 經認證的事務總數。
- 成員中應用的遠程事務總數。
- 本地事務總數。
監控數據每秒與組中其它成員共享一次。一旦成員收到其它成員的統計信息,它將計算在上一個監控週期內認證、應用和本地執行的事務數量。
(2)限流
根據在組中所有服務器上收集的統計數據,限制機制決定成員能夠提交新事務的速率。流量控制考慮了兩個工作隊列:認證隊列和二進制日誌應用程序隊列,因此用戶可以選擇在認證器或複製應用程序執行流量控制,或者兩者都執行。使用以下變量控制相應隊列的大小:
- group_replication_flow_control_mode:指定是否開啓流控,可取值爲quota和disable。缺省值爲quota,表示啓用流控限額,如果指定爲disable則禁用流控。
- group_replication_flow_control_certifier_threshold:如果認證隊列中的事務數超過該變量值觸發認證流控,缺省值爲25000,值域爲0-2147483647。
- group_replication_flow_control_applier_threshold:如果複製應用隊列中的事務數超過該變量值觸發應用流控,缺省值爲25000,值域爲0-2147483647。
如果認證隊列或二進制日誌應用程序隊列大小超過用戶定義的閾值,則限制機制將強制執行寫入配額。配額將本監控週期的事務數比上一週期減少10%,以允許觸發問題的隊列減小其大小。爲了避免吞吐量的大幅跳躍,增加吞吐量同樣僅允許增長上個週期的10%。當前的限制機制不會影響低於配額的事務,但會延遲完成那些超過它的事務,直到監控期結束。
從前面的測試中已知,認證隊列始終很小,基本不存在積壓,複製延遲主要是由從庫的複製應用程序緩慢造成的。因此調整主庫的group_replication_flow_control_applier_threshold變量以對應用隊列進行流控,縮小主從複製延遲。該變量設置爲100、1000、10000時的測試結果如下表:
group_replication_flow_control_applier_threshold |
TRX |
Master TPS |
Slave1 Elapsed |
Slave1 TPS |
Slave2 Elapsed |
Slave2 TPS |
100 |
98469 |
273 |
361 |
272 |
361 |
272 |
1000 |
106442 |
295 |
361 |
294 |
363 |
293 |
10000 |
162866 |
452 |
461 |
353 |
556 |
292 |
從表中看到:
- 當group_replication_flow_control_applier_threshold=100時,兩個從庫基本沒有延遲,但整個組的TPS只有273左右。
- 當group_replication_flow_control_applier_threshold=1000時,兩個從庫的延遲依然很小,整個組的TPS爲294,提升了不到8%。
- 當group_replication_flow_control_applier_threshold=10000時,從庫1、從庫2分別延遲了100秒和200秒,主庫、從庫1、從庫2的TPS分別是452、353、292。
在本測試環境的壓力下,解讀表中的結果可得以下結論:
- 組複製的吞吐量和主從複製延時無法兼得。
- 要保持主從複製低延時,組複製的吞吐量取決去最小TPS的節點,符合木桶原理。
- group_replication_flow_control_applier_threshold大於某一閾值時,主從延遲將變得非常明顯。
7. 其它配置
(1)消息分段
當組複製組成員之間發送異常大的消息時,可能會導致某些組成員報告爲失敗並從組中移除。這是因爲組通信引擎使用的單個線程被處理消息佔用時間太長,使得某些組成員將接收狀態報告爲失敗。從MySQL 8.0.16開始,默認情況下,大消息會自動拆分爲單獨發送的消息片段,並由接收方重新組裝爲原消息。
系統變量group_replication_communication_max_message_size指定組複製通信的最大消息大小,超過該大小的消息將被分段。缺省值爲10485760字節(10MB),允許的最大值與slave_max_allowed_packet系統變量的最大值相同,即1073741824字節(1GB)。group_replication_communication_max_message_size的值不能大於slave_max_allowed_packet的值,因爲複製應用程序線程無法處理大於slave_max_allowed_packet的消息片段。要關閉消息分段,可將group_replication_communication_max_message_size設置爲0。
當所有組成員收到並重新組裝消息的所有片段時,認爲消息傳遞已完成。分段消息包括其標頭中的信息,這些信息在消息傳輸期間加入,以使成員恢復之前發送的早期消息片段。如果組成員無法恢復消息,則將其從組中移除。爲了使複製組使用消息分段,所有組成員必須爲MySQL 8.0.16或更高版本,並且組使用的複製通信協議版本也必須設置爲8.0.16或更高版本。
如果複製組因某些成員不支持而無法使用消息分段時,系統變量group_replication_transaction_size_limit可用於限制組接收的最大事務。在MySQL 8.0中,缺省值爲150000000(約143MB),大於該值的事務將被回滾。
(2)XCom緩存
作爲組複製協議的一部分,用於組複製的通信引擎(XCom,Paxos變體)包括用於組成員之間交換的消息及其元數據的高速緩存,用於與其它組成員通信超時後重新連接時進行恢復。從MySQL 8.0.16開始,可以使用group_replication_message_cache_size系統變量設置XCom的消息緩存大小,缺省值和最小值爲1GB。如果達到緩存大小限制,XCom將刪除已交付的最舊條目。
如果重新連接成員時需要恢復消息,但該消息已從消息高速緩存中刪除,則該成員無法重新連接。當使用了group_replication_member_expel_timeout系統變量(在MySQL 8.0.13中引入)指定可疑成員從組中移除之前的延遲時間,更有可能發生這種情況。組複製通信系統(GCS)通過警告消息告知用戶何時從消息緩存中刪除當前無法訪問的成員恢復時可能需要的消息。此警告消息記錄在所有活動組成員上,表明高速緩存大小可能不足以支持移除成員之前的超時時間。在這種情況下,應參考group_replication_member_expel_timeout系統變量指定的時間段內的預期消息量來增加高速緩存大小,以便高速緩存包含成員成功返回所需的所有錯過的消息。
可以使用以下語句查詢性能模式表memory_summary_global_by_event_name:
select * from performance_schema.memory_summary_global_by_event_name where event_name like 'memory/group_rpl/gcs_xcom::xcom_cache'\G
這將返回消息緩存的內存使用情況統計信息,包括當前緩存條目數和緩存的當前大小。如果減小緩存大小限制,XCom將刪除已確定並交付的最舊條目,直到當前大小低於限制。在此刪除過程正在進行時,XCom可能會暫時超出緩存大小限制。
(3)故障檢測
組複製的故障檢測機制旨在識別不再與該組通信的組成員,並在它們可能發生故障時將其移除。通常,所有小組成員定期與所有其它小組成員交換消息。如果組成員在5秒內沒有收到來自特定成員的任何消息,會引起對該成員的懷疑。當懷疑超時時,假定被懷疑的成員失敗,並將其移出該組。被移除成員從其它成員看到的成員列表中刪除,但它不知道自己已被移出該組,因此它將自己視爲在線而其它成員無法訪問。如果該成員實際上沒有失敗(例如網絡閃斷)並且能夠恢復與其它成員的通信,則它會收到已被從組中移除的信息。默認情況下,如果懷疑某個成員失敗,則會發生以下行爲:
- 當懷疑被創建時,它會立即超時(group_replication_member_expel_timeout缺省值爲0),因此成員只要被懷疑就會被立即移除。該成員可能會在超時後存活幾秒鐘,因爲對過期懷疑的檢查會定期進行。
- 如果被驅逐的成員恢復通信並意識到被移除,它不會嘗試重新加入該組。
- 當被驅逐的成員接受其移除時,它會切換到超級只讀模式(super_read_only)並等待管理員干預。
這些缺省設置優先考慮組能夠正確處理請求。但在較慢或不穩定的網絡情況下,可能經常需要管理員干預來修復被移除的成員。可以使用組複製配置選項永久或臨時更改這些行爲:
- 可以使用可從MySQL 8.0.13新增的group_replication_member_expel_timeout系統變量,在產生懷疑和移除可疑成員之間留出更多時間,最大爲3600秒。處於此狀態的可疑成員不可訪問,但不會從組的成員列表中刪除。創建懷疑之前的5秒檢測週期是不可配置的。
- 可以使用可從MySQL 8.0.16新增的group_replication_autorejoin_tries系統變量指定成員被移除後嘗試重新加入該組的次數。缺省值0表示成員不嘗試重新加入組,並繼續執行由group_replication_exit_state_action系統變量指定的操作(缺省爲READ_ONLY)。每次重試間隔5分鐘,最多可以進行2016次重試。在自動重新加入過程中,被移除成員保持超級只讀模式,並在其複製組視圖上顯示ERROR狀態。
- 可以使用group_replication_exit_state_action系統變量選擇未能重新加入(或不嘗試)的被移除成員的行爲,可選值爲ABORT_SERVER或READ_ONLY,缺省值爲READ_ONLY。ABORT_SERVER表示關閉MySQL服務器,READ_ONLY表示切換爲超級只讀模式。與自動重新加入過程一樣,如果成員進入超級只讀模式,則讀取過時舊數據的可能性會增加。指示成員自行關閉意味着MySQL Server實例不可用,必須重新啓動。無論設置了什麼退出操作,都需要管理員干預,因爲已經耗盡其自動重新加入嘗試(或從未有過)並且已被移出組的成員不允許在不重新啓動組複製的情況下重新加入。
- 如果希望避免由於不適當的配置產生裂腦情況,可以使用系統變量group_replication_unreachable_majority_timeout設置成員在與大多數組成員失去聯繫後等待的秒數。在此之後,將回滾該成員和少數組中其它成員處理的所有待處理事務,並且該組中的服務器將變爲ERROR狀態,然後執行group_replication_exit_state_action指定的退出操作。
8. 主從、半同步、組複製性能對比測試
現在將關注點從組複製性能本身,轉移到主從、半同步、組複製三種MySQL複製的橫向性能對比上。我們最爲關心的是不同複製方式對主庫TPS的影響。測試環境不變,不同的只是更改相應的複製配置。三種複製均爲一主兩從,具體測試步驟描述如下。(1)MySQL實例基本配置
[mysqld]
server_id=1125 # 兩個從庫爲1126、1127
gtid_mode=ON
enforce-gtid-consistency=true
innodb_buffer_pool_size=4G
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
log_bin=binlog
log_slave_updates=ON
binlog_format=ROW
binlog_checksum=NONE
master_info_repository=TABLE
relay_log_info_repository=TABLE
# 主庫啓用寫集
binlog_transaction_dependency_tracking = WRITESET
transaction_write_set_extraction = XXHASH64
# 從庫使用8線程MTS
slave_parallel_type = LOGICAL_CLOCK
slave_parallel_workers = 8
slave_preserve_commit_order=1
(2)啓動傳統主從複製
-- 在從庫執行
change master to
master_host = '172.16.1.125',
master_port = 3306,
master_user = 'repl',
master_password = '123456',
master_auto_position = 1;
start slave;
(3)執行主從複製測試
./tpcc_test.sh
(4)配置半同步複製
# 主庫增加配置:
plugin-load="rpl_semi_sync_master=semisync_master.so"
rpl_semi_sync_master_enabled=1
# 從庫增加配置:
plugin-load="rpl_semi_sync_slave=semisync_slave.so"
rpl_semi_sync_slave_enabled=1
然後重啓三個MySQL實例。
(5)執行半同步複製測試
./tpcc_test.sh
(6)組複製配置
去掉上一步的半同步配置,並增加組複製配置:
plugin-load=group_replication.so
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address= "172.16.1.125:33061" # 兩個從庫爲"172.16.1.126:33061"、"172.16.1.127:33061"
group_replication_group_seeds= "172.16.1.125:33061,172.16.1.126:33061,172.16.1.127:33061"
group_replication_bootstrap_group=off
然後重啓三個MySQL實例。之後:
-- 主庫執行
reset master;
reset slave all;
change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
set global group_replication_bootstrap_group=on;
start group_replication;
set global group_replication_bootstrap_group=off;
-- 從庫執行
reset master;
stop slave;
reset slave all;
change master to master_user='repl', master_password='123456' for channel 'group_replication_recovery';
start group_replication;
(7)執行組複製測試
./tpcc_test.sh
三種複製測試結果如下表所示。
複製方式 |
TRX |
Master TPS |
Slave1 Elapsed |
Slave1 TPS |
Slave2 Elapsed |
Slave2 TPS |
主從 |
196808 |
546 |
360 |
546 |
435 |
452 |
半同步 |
189303 |
525 |
361 |
524 |
414 |
457 |
組複製 |
166032 |
461 |
462 |
359 |
561 |
295 |
從測試結果可以看到,相同條件下:
- 半同步複製主庫的TPS是傳統主從複製的96%,組複製主庫的TPS是傳統主從複製的84%。
- 在複製延遲上,從庫1的傳統主從和半同步複製基本無延遲,從庫2的傳統主從延遲還大於半同步複製;而兩個從庫的組複製延遲都很大(100秒和200秒)。
- 傳統主從複製與半同步複製沒有提供縮小複製延遲的機制;組複製可以通過流控機制,減少從庫的複製延遲,代價是將組複製整體的吞吐量拉低到組中吞吐量最差節點的水平。
由於組複製會帶來整體吞吐量的下降,大多數情況下,使用傳統主從異步複製即可。如果在讀寫分離場景下要求讀取一致性,可以考慮半同步複製。與異步複製相比,半同步複製的吞吐量並沒有顯著衰減。只有在首要需求爲多主可寫、自動處理事務衝突、主庫失敗自動轉移等情況下,再考慮使用組複製。
MySQL官方提供的組複製性能基準測試,參見http://mysqlhighavailability.com/an-overview-of-the-group-replication-performance/。
二、組複製要求與限制
目前的MySQL組複製對於存儲引擎、網絡帶寬、表設計,以及服務器實例的配置還存在諸多要求與限制,尤其是多主模式,使用時更要格外注意。下面是MySQL官方文檔中指出的已知問題,在實際應用中使用組複製前,有必要了解它們以幫助做出正確的選擇。在採坑前做到未雨綢繆總是有益的。
1. 組複製要求
(1)基礎架構
- 數據必須存儲在InnoDB事務存儲引擎中。事務以樂觀方式執行,然後在提交時檢查衝突。如果存在衝突,爲了保持整個組的一致性,將回滾一些事務,因此需要事務存儲引擎。此外,InnoDB還提供了一些附加功能,可以在與組複製一起操作時更好地管理和處理衝突。使用其它存儲引擎(包括臨時MEMORY存儲引擎)可能會導致組複製出錯。可以通過在組成員上設置disabled_storage_engines系統變量來阻止使用其它存儲引擎,例如:
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
- 組複製的每個表必須具有主鍵,或者具有等效的非空唯一鍵。它們作爲表中每一行的唯一標識符是必需的,這使得系統能夠通過準確識別每個事務已修改的行來確定哪些事務存在衝突。
- 網絡性能會影響組的性能,網絡延遲和網絡帶寬都會影響組複製性能及穩定性。因此組複製中的MySQL服務器實例應該部署在彼此非常接近的集羣環境中,使得所有組成員之間始終保持雙向通信。如果阻止服務器實例的收發消息(例如通過防火牆限制),則該成員無法在組中運行,並且組成員(包括有問題的成員)可能無法報告受影響的服務器實例的正確成員狀態。從MySQL 8.0.14開始,可以使用IPv4或IPv6網絡基礎結構,或兩者的混合,用於遠程組複製服務器之間的TCP通信。
(2)服務器實例配置
必須在作爲組成員的服務器實例上配置以下選項:
- 設置--log-bin [= log_file_name] 激活二進制日誌,MySQL 8中缺省啓用此選項。與其它MySQL複製方式一樣,組複製需要複製二進制日誌內容,因此需要打開二進制日誌才能運行。
- 設置--log-slave-updates 記錄從庫更新。服務器需要記錄通過複製應用程序應用的二進制日誌。組中的服務器需要記錄它們收到的所有事務並從組中應用。這是必需的,因爲分佈式恢復依賴組中成員的二進制日誌進行。因此,每個事務的副本都需要存在於每個服務器上,即使對於那些未在服務器本身上啓動的事務也是如此。MySQL 8中缺省啓用此選項。
- 設置--binlog-format = row 將二進制日誌設爲行格式。組複製依賴於基於行的複製格式,以在組成員之間一致地傳播更改。它依賴於基於行的基礎結構來提取必要信息,以檢測在組中不同服務器併發執行的事務之間的衝突。
- 設置--binlog-checksum = NONE 關閉二進制日誌校驗。由於複製事件校驗和的設計限制,組複製無法使用它們,因此必須禁用。
- 設置--gtid-mode = ON 開啓全局事務標識符。組複製使用全局事務標識符來準確跟蹤在每個服務器實例上已提交的事務,從而能夠推斷哪些服務器執行的事務可能與其它地方已提交的事務衝突。換句話說,顯式事務標識符是框架的基本部分,以便能夠確定哪些事務可能發生衝突。
- 設置--master-info-repository = TABLE和--relay-log-info-repository = TABLE,將複製信息資料庫存儲到表中。複製應用程序需要將主庫信息和中繼日誌元數據寫入mysql.slave_master_info和mysql.slave_relay_log_info系統表。這可確保組複製插件具有一致的可複製性和複製元數據的事務管理。從MySQL 8.0.2開始,這些選項缺省值爲TABLE,而從MySQL 8.0.3開始,不推薦使用FILE設置。
- 設置--transaction-write-set-extraction = XXHASH64,以便在以將數據行記錄到二進制日誌時,服務器也會收集寫入集。寫入集基於每行的主鍵,唯一標識已更改的行,用於檢測事務衝突。MySQL 8中缺省啓用此選項。
- 推薦設置slave_parallel_workers爲大於零的值,啓用組成員上的多線程複製應用程序,最多可以指定1024個並行複製應用程序線程。設置slave_preserve_commit_order = 1,確保並行事務的最終提交與原始事務的順序相同,這是組複製所需的,它依賴於所有組成員以相同順序接收和應用已提交事務,以保證並行事務的數據一致性。slave_preserved_commit_order = 1需要設置slave_parallel_type = LOGICAL_CLOCK,該策略指定用於決定允許哪些事務在從庫上並行執行的策略。設置slave_parallel_workers = 0會禁用並行複製,併爲從庫提供單個應用程序線程,而不是協調器線程。使用該設置,slave_parallel_type和slave_preserve_commit_order選項無效並被忽略。
2. 組複製限制
組複製存在以下已知限制:
- 使用MINIMAL選項(--upgrade = MINIMAL)的MySQL服務器升級後,無法啓動組複製,該選項不會升級複製內部所依賴的系統表。
- 認證過程沒有考慮間隙鎖。除非應用程序中依賴REPEATABLE READ語義,否則MySQL建議將READ COMMITTED隔離級別與組複製一起使用。InnoDB在READ COMMITTED中不使用間隙鎖,它將InnoDB中的本地衝突檢測與組複製執行的分佈式衝突檢測統一化。
- 認證過程不考慮表鎖(LOCK TABLES和UNLOCK TABLES)或命名鎖(GET_LOCK)。
- 複製不支持SERIALIZABLE隔離級別。將事務隔離級別設置爲SERIALIZABLE會將使組拒絕提交事務。
- 使用多主模式時,不支持針對同一對象但在不同服務器上執行的併發數據定義語句(DDL)和數據操作語句(DML)。
- 多主模式不支持具有多級外鍵依賴關係的表,特別是具有已定義CASCADING外鍵約束的表。MySQL建議在多主模式組複製中設置group_replication_enforce_update_everywhere_checks = ON,以避免未檢測到的衝突。
- 當組複製以多主模式運行時,SELECT .. FOR UPDATE語句可能導致死鎖。
- 全局複製過濾器不能在爲組複製配置的MySQL服務器實例上使用。
- MySQL服務器自MySQL 8.0.16起可以支持TLSv1.3協議,並且需要使用OpenSSL 1.1.1或更高版本編譯MySQL。組複製當前不支持TLSv1.3,如果使用此支持編譯服務器,則在組通信引擎中明確禁用它。
如果單個事務太大,以至於在5秒鐘內無法通過網絡在組成員之間複製消息,則可能會懷疑成員失敗,然後被移出組。由於內存分配問題,大型事務也可能導致系統速度變慢。要避免這些問題,使用以下緩解措施:
- 儘可能嘗試限制事務規模。例如,將與LOAD DATA一起使用的文件拆分爲較小的塊。
- 使用系統變量group_replication_transaction_size_limit指定組接收的最大事務大小。超過此大小的事務將回滾,不會發送到組。在MySQL 8.0中,此係統變量缺省值爲150000000字節(大約143 MB)。
- 從MySQL 8.0.13開始,可以使用系統變量group_replication_member_expel_timeout來允許在懷疑失敗的成員在被移出之前有更多的時間。可以在最初的5秒檢測期後最多延長一個小時。
- 從MySQL 8.0.16開始,大型消息會自動分段,這意味着大型消息不會觸發引發懷疑的5秒檢測週期,除非此時存在其它網絡問題。爲了使複製組使用分段,所有組成員必須處於MySQL 8.0.16或更高版本,並且組使用的組複製通信協議版本必須允許分段。如果MySQL版本不支持消息分段,可以使用系統變量group_replication_communication_max_message_size來調整最大消息大小,缺省值爲10485760字節(10 MB),或通過指定零值來關閉分段。