本節列出和解釋了組復制相關的要求和限制。
1.組復制的要求
要使用組復制,每個MySQL節點必須滿足以下條件:
1.1 基本要求
- InnoDB存儲引擎:數據必須存儲在事務型的InnoDB存儲引擎中。事務以樂觀形式執行,然后在提交前會檢測沖突問題。如果有沖突,為了維護組中一致性,有些事務必須回滾。這意味着需要事務型的存儲引擎。此外,InnoDB 存儲引擎提供了一些額外的功能,它們結合組復制時能更好地管理和處理沖突。
- Primary Keys:每張需要被組復制的表都必須顯式定義一個主鍵。主鍵在判斷事務是否沖突扮演極其重要的角色:通過主鍵來准確識別每個事務中修改了表中的哪些行。(實際上是將主機hash成寫集,然后由certifier來並發事務之間的檢測沖突性)
- 使用IPv4 地址:MySQL組復制使用的組通信引擎組件只支持 IPv4。因此,必須使用IPv4的網絡。
- 良好的網絡性能:組復制設計的初衷是部署在集群環境中,集群中的節點相互之間都非常近,因此除了網絡延遲,網絡帶寬也會影響組復制。
1.2 配置上的要求
組中的每個成員都必須配置以下選項:
- 必須開啟二進制日志:設置
--log-bin[=log_file_name]
。MySQL組復制會復制二進制日志的內容,因此必須開啟二進制日志。 - Slave Updates Logged:設置
--log-slave-updates
。節點需要記錄applier已應用的日志。組中的每個節點都需要記錄它們所接收到並應用的所有事務,這是必須的,因為恢復過程是依賴於組中參與者的二進制日志來進行的。因此,組中每個成員都必須保留每個事務的副本,即使某事務不是在該節點上開始的。 - Row Format的二進制日志:設置
--binlog-format=row
。組復制依賴於基於行格式的二進制日志,以便在組中傳播所發生的更改能保持一致性。而且,在探測組中不同節點間發生的並發事務是否沖突時,需要從行格式的日志中提取一些內容來做比較。 - 開啟GTID復制:設置
--gtid-mode=ON
。組復制使用GTID(全局事務ID)來精確跟蹤每個節點上已經提交了哪些事務。也因此可以推斷出某節點上要執行的事務是否和已執行的事務(每個節點上都有副本)沖突。換句話說,GTID是整個組復制判斷事務是否沖突的基礎。 - Replication Information Repositories:設置
--master-info-repository=TABLE
和--relay-log-info-repository=TABLE
。applier需要將 master 和 relay log 的元數據信息寫入到系統表 mysql.slave_master_info 和 mysql.slave_relay_log_info 中。這保證了組復制插件具有一致性恢復的能力和復制的元數據事務管理能力。 - Transaction Write Set Extraction:設置
--transaction-write-setextraction=XXHASH64
,以便將行寫入到二進制日志中時,節點也收集寫集。寫集基於每行的主鍵,是唯一標識被更改行的標簽的簡化形式,該標簽后續會用於探測事務沖突性。 - Multithreaded Appliers:(某些舊版本沒有該要求)可以將組復制成員配置為多線程appliers,使得可以並行應用事務。需要設置
--slave-parallel-workers=N
(N是applier線程數量)、--slavepreserve-commit-order=1
以及--slave-parallel-type=LOGICAL_CLOCK
。--slaveparallel-workers=N
表示啟用多applier線程,組復制依賴於建立在所有參與節點都以相同順序接收和應用、提交事務的一致性機制,因此還必須設置--slave-preserve-commit-order=1
以保證並行事務的最終提交是和原事務所在順序位置一致的。最后,為了決定哪些事務可以並行執行,relay log 必須包含由--slave-parallel-ype=LOGICAL_CLOCK
生成的事務父信息(transaction parent information)。當嘗試加入一個只設置了--slave-parallel-workers
大於0,卻沒有設置其他兩項的新成員,將會報錯並阻止它的加入。
2.組復制的限制(局限性)
下面是使用組復制已知的限制:
- Replication Event Checksums:由於對復制事件校驗的設計缺陷,目前組復制不能使用它們。因此,需要設置
--binlog-checksum=NONE
。 - Gap Locks:在驗證階段中(certification process),不會考慮 Gap Locks,因此在 InnoDB 的外部無法獲取任何關於Gap 鎖的信息。
注意:
除非你的應用程序或業務需求依賴於REPEATABLE READ(MySQL默認該隔離級別),否則建議在組復制中使用READ COMMITTED隔離級別。在READ COMMITTED隔離級別中,InnoDB基本上不會使用Gap Locks,這將使得InnoDB自帶的沖突探測能和組復制的沖突探測相互對齊從而保持一致。
- Table Locks and Named Locks:驗證階段(certification process)中不考慮表鎖和命名鎖(見get_lock())。
- 不支持 SERIALIZABLE 隔離級別:在多主模型下,默認不支持該隔離級別。如果在多主模型下設置了該隔離級別,將拒絕提交事務。
- 不支持並發的 DDL 和 DML 操作:不支持在多主模型下不同節點上同時執行DDL和DML修改同一對象。在某節點上對某對象執行DDL語句時,如果在其他節點同時執行DML修改該對象,將有一定風險探測到沖突。(譯注:是 DDL+DML 的並發,DDL+DDL 的並發也不允許。這是因為MySQL中沒有DDL事務,不能保證DDL的原子性,當DDL和DML同時操作某一個對象,可能DDL修改后,DML將因為對象結構的改變而無法執行,繼而回滾)
- 不支持級聯的外鍵約束:多主模型的組(所有節點都配置了
group_replication_single_primary_mode=OFF
)不支持多級外鍵依賴,特別是表上定義了級聯的外鍵約束(CASCADING foreign key constraints)。這是因為多主模型下執行外鍵約束的級聯操作可能會出現未檢測到的沖突,從而導致組內成員間數據不一致。因此,我們推薦在使用多主模型時,在每個節點上都設置group_replication_enforce_update_everywhere_checks=ON
以避免出現未檢測到的沖突。在單主模型下沒有這種問題,因為沒有並發寫操作,從而不可能會出現未被探測到的沖突。 - 大事務可能會錯誤:如果一個事務非常大,導致GTID的內容非常多,以至於無法在 5 秒內通過網絡傳輸完成,這時組成員間的通信將失敗。要避免該問題,可以盡可能地限制事務的大小。例如,將
LOAD DATA INFILE
的文件切割為多個小塊。 - 多主模型可能出現死鎖:在多主模型下,
SELECT ... FOR UPDATE
語句可能會導致死鎖。這是因為組內成員之間不會共享鎖資源(譯注:share nothing),因此這樣的語句可能達不到預期的結果。