GTID 的生命週期包含以下步驟
在來源上執行並提交交易。此用戶端交易會被指派一個 GTID,該 GTID 由來源的 UUID 和此伺服器上尚未使用的最小非零交易序號組成。GTID 會寫入來源的二進制日誌(在日誌中緊接在交易本身之前)。如果用戶端交易未寫入二進制日誌(例如,因為交易被篩選掉,或交易是唯讀的),則不會指派 GTID。
如果為交易指派了 GTID,則會在提交時透過將其寫入交易開始處的二進制日誌(作為
Gtid_log_event
)來以原子方式保存 GTID。每當二進制日誌輪換或伺服器關閉時,伺服器都會將寫入上一個二進制日誌檔案的所有交易的 GTID 寫入mysql.gtid_executed
表格。如果為交易指派了 GTID,則會在提交交易後不久透過將其新增至
gtid_executed
系統變數 (@@GLOBAL.gtid_executed
) 中的 GTID 集合來以非原子方式(非常短的時間後)將 GTID 外部化。此 GTID 集合包含所有已提交 GTID 交易集合的表示形式,並且在複製中用作表示伺服器狀態的符記。在啟用二進制日誌記錄的情況下(來源需要),gtid_executed
系統變數中的 GTID 集合是已應用交易的完整記錄,但mysql.gtid_executed
表格不是,因為最新的歷史記錄仍在目前的二進制日誌檔案中。在二進制日誌資料傳輸到副本並儲存在副本的中繼日誌中之後(使用此流程的既定機制,詳情請參閱 第 19.2 節「複製實作」),副本會讀取 GTID 並將其
gtid_next
系統變數的值設定為此 GTID。這會告知副本下一個交易必須使用此 GTID 進行記錄。請務必注意,副本是在工作階段內容中設定gtid_next
。複本會驗證,為了處理交易,沒有任何執行緒取得
gtid_next
中的 GTID 的擁有權。藉由在處理交易本身之前,先讀取並檢查複製交易的 GTID,複本不僅確保先前沒有具有此 GTID 的交易已套用在複本上,也確保沒有其他會話已讀取此 GTID,但尚未提交相關聯的交易。因此,如果多個客戶端嘗試同時套用相同的交易,伺服器會藉由僅允許其中一個執行來解決此問題。複本的gtid_owned
系統變數 (@@GLOBAL.gtid_owned
) 會顯示目前正在使用中的每個 GTID 以及擁有它的執行緒 ID。如果 GTID 已被使用,則不會引發錯誤,並且會使用自動略過功能來忽略該交易。如果 GTID 尚未使用,複本會套用複製的交易。因為
gtid_next
設定為來源已指派的 GTID,複本不會嘗試為此交易產生新的 GTID,而是使用儲存在gtid_next
中的 GTID。如果複本上啟用了二進制日誌記錄,則 GTID 會在提交時以原子方式持久化,方法是在交易開始時將其寫入二進制日誌 (作為
Gtid_log_event
)。每當二進制日誌輪換或伺服器關閉時,伺服器會將寫入先前二進制日誌檔案的所有交易的 GTID 寫入mysql.gtid_executed
資料表中。如果複本上停用了二進制日誌記錄,則 GTID 會以原子方式持久化,方法是將其直接寫入
mysql.gtid_executed
資料表中。MySQL 會將一個陳述式附加到交易中,以將 GTID 插入資料表。此操作對於 DDL 陳述式以及 DML 陳述式都是原子性的。在這種情況下,mysql.gtid_executed
資料表是複本上套用的交易的完整記錄。在複本上提交複製的交易後不久,GTID 會以非原子方式外部化,方法是將其新增至複本的
gtid_executed
系統變數 (@@GLOBAL.gtid_executed
) 中的 GTID 集合。至於來源,此 GTID 集合包含所有已提交 GTID 交易的集合的表示法。如果複本上停用了二進制日誌記錄,則mysql.gtid_executed
資料表也是複本上套用的交易的完整記錄。如果複本上啟用了二進制日誌記錄,表示某些 GTID 僅記錄在二進制日誌中,則gtid_executed
系統變數中的 GTID 集合是唯一的完整記錄。
在來源上完全篩選掉的客戶端交易不會被指派 GTID,因此它們不會被新增至 gtid_executed
系統變數中的交易集合,也不會新增至 mysql.gtid_executed
資料表。然而,在複本上完全篩選掉的複製交易的 GTID 會被持久化。如果複本上啟用了二進制日誌記錄,則篩選掉的交易會以 Gtid_log_event
的形式寫入二進制日誌,接著是一個僅包含 BEGIN
和 COMMIT
陳述式的空交易。如果停用了二進制日誌記錄,則篩選掉的交易的 GTID 會寫入 mysql.gtid_executed
資料表。保留篩選掉的交易的 GTID 可確保可以壓縮 mysql.gtid_executed
資料表和 gtid_executed
系統變數中的 GTID 集合。它也確保如果複本重新連線到來源,則不會再次擷取篩選掉的交易,如 第 19.1.3.3 節「GTID 自動定位」中所述。
在多執行緒複本上 (其中 replica_parallel_workers > 0
),可以平行套用交易,因此複製的交易可能會不按順序提交 (除非 replica_preserve_commit_order = 1
)。當這種情況發生時,gtid_executed
系統變數中的 GTID 集合包含多個 GTID 範圍,它們之間存在間隙。(在來源或單執行緒複本上,存在單調遞增的 GTID,數字之間沒有間隙。) 多執行緒複本上的間隙僅發生在最近套用的交易之間,並且隨著複製的進展而被填滿。當使用 STOP REPLICA
陳述式乾淨地停止複製執行緒時,會套用正在進行的交易,以便填補間隙。如果發生關機,例如伺服器故障或使用 KILL
陳述式停止複製執行緒,則間隙可能會保留。
典型的情況是伺服器為已提交的交易產生新的 GTID。然而,GTID 也可以指派給交易以外的其他變更,在某些情況下,單一交易可以指派多個 GTID。
每個寫入二進制日誌的資料庫變更 (DDL 或 DML) 都會指派 GTID。這包括自動提交的變更,以及使用 BEGIN
和 COMMIT
或 START TRANSACTION
陳述式提交的變更。GTID 也會指派給資料庫的建立、變更或刪除,以及非資料表資料庫物件,例如程序、函數、觸發程序、事件、檢視、使用者、角色或授權。
非交易更新和交易更新都會指派 GTID。此外,對於非交易更新,如果在嘗試寫入二進制日誌快取時發生磁碟寫入失敗,因此在二進制日誌中建立間隙,則產生的事件日誌事件會指派 GTID。
當資料表由二進制日誌中產生的陳述式自動卸除時,會為該陳述式指派 GTID。當複本開始套用剛啟動的來源的事件時,以及當使用基於陳述式的複製 (binlog_format=STATEMENT
) 且使用者會話中有開啟的暫時資料表斷開連線時,會自動卸除暫時資料表。使用 MEMORY
儲存引擎的資料表在伺服器啟動後第一次存取時會自動刪除,因為在關機期間可能會遺失資料列。
當交易未寫入原始伺服器上的二進制日誌時,伺服器不會為其指派 GTID。這包括回滾的交易,以及在原始伺服器上停用二進制日誌記錄時執行的交易,無論是全域 (在伺服器的設定中指定 --skip-log-bin
) 或針對會話 (SET @@SESSION.sql_log_bin = 0
)。這也包括使用基於資料列的複製 (binlog_format=ROW
) 時的無操作交易。
XA 交易會為交易的 XA PREPARE
階段和交易的 XA COMMIT
或 XA ROLLBACK
階段指派單獨的 GTID。XA 交易會持久準備,以便使用者可以在發生故障時 (在複製拓撲中可能包括容錯移轉至另一部伺服器) 提交或回滾它們。因此,交易的兩個部分會單獨複製,因此它們必須擁有自己的 GTID,即使回滾的非 XA 交易不會有 GTID。
在以下特殊情況下,單一陳述式可以產生多個交易,因此可以指派多個 GTID
會叫用提交多個交易的預存程序。針對程序提交的每個交易產生一個 GTID。
多資料表
DROP TABLE
陳述式會卸除不同類型的資料表。如果任何資料表使用不支援原子 DDL 的儲存引擎,或如果任何資料表是暫時資料表,則可以產生多個 GTID。當使用基於資料列的複製 (
binlog_format=ROW
) 時,會發出CREATE TABLE ... SELECT
陳述式。針對CREATE TABLE
動作產生一個 GTID,並針對資料列插入動作產生一個 GTID。
依預設,對於使用者會話中提交的新交易,伺服器會自動產生並指派新的 GTID。當交易套用在複本上時,會保留來自原始伺服器的 GTID。您可以藉由設定 gtid_next
系統變數的會話值來變更此行為
當
gtid_next
設定為AUTOMATIC
(預設) 且交易被提交並寫入二進制日誌時,伺服器會自動產生並指派新的 GTID。如果交易被回滾或因其他原因未寫入二進制日誌,則伺服器不會產生並指派 GTID。如果您將
gtid_next
設定為AUTOMATIC:
,則會將包含指定標籤的新 GTID 指派給每個新交易。TAG
如果您將
gtid_next
設定為有效的 GTID (包含 UUID、選用標籤和交易序號,以冒號分隔),則伺服器會將該 GTID 指派給您的交易。即使交易未寫入二進制日誌或交易為空,也會指派此 GTID 並將其新增至gtid_executed
。
請注意,在您將 gtid_next
設定為特定 GTID (格式為
或 UUID
:NUMBER
) 且交易已提交或回滾後,必須在任何其他陳述式之前發出明確的 UUID
:TAG
:NUMBER
SET @@SESSION.gtid_next
陳述式。如果您不想再明確指派任何 GTID,則可以使用它將 GTID 值設定回 AUTOMATIC
。
當複寫應用程式執行緒套用複寫的交易時,它們會使用此技術,將 @@SESSION.gtid_next
明確設定為來源伺服器上指派的複寫交易之 GTID。這表示保留來自來源伺服器的 GTID,而不是由複寫伺服器產生並指派新的 GTID。這也表示即使複寫伺服器上的二進位記錄或複寫更新記錄被停用,或者當交易為空操作或在複寫伺服器上被篩除時,GTID 仍然會被添加到複寫伺服器的 gtid_executed
中。
用戶端可以透過在執行交易之前將 @@SESSION.gtid_next
設定為特定的 GTID 來模擬複寫的交易。此技術被 mysqlbinlog 用來產生二進位日誌的轉儲,用戶端可以重播該轉儲以保留 GTID。透過用戶端提交的模擬複寫交易與透過複寫應用程式執行緒提交的複寫交易完全等效,並且在事後無法區分。
gtid_purged
系統變數 (@@GLOBAL.gtid_purged
) 中的 GTID 集包含伺服器上已提交的所有交易的 GTID,但這些交易不存在於伺服器上的任何二進位記錄檔中。gtid_purged
是 gtid_executed
的子集。gtid_purged
中包含以下類別的 GTID:
在複寫伺服器上停用二進位記錄的情況下提交的複寫交易之 GTID。
已寫入現已清除的二進位記錄檔中的交易之 GTID。
透過語句
SET @@GLOBAL.gtid_purged
明確添加到集合中的 GTID。
您可以變更 gtid_purged
的值,以在伺服器上記錄某個 GTID 集中所包含的交易已被應用,即使它們不存在於伺服器上的任何二進位記錄中。當您將 GTID 添加到 gtid_purged
時,它們也會被添加到 gtid_executed
中。此動作的一個使用案例是當您在伺服器上還原一個或多個資料庫的備份,但您沒有伺服器上包含這些交易的相關二進位記錄時。您也可以選擇是要將 gtid_purged
中的整個 GTID 集替換為指定的 GTID 集,還是將指定的 GTID 集添加到 gtid_purged
中已有的 GTID。有關如何執行此操作的詳細資訊,請參閱 gtid_purged
的描述。
當伺服器啟動時,會初始化 gtid_executed
和 gtid_purged
系統變數中的 GTID 集。每個二進位記錄檔都以 Previous_gtids_log_event
事件開始,該事件包含先前所有二進位記錄檔中的 GTID 集 (由先前檔案的 Previous_gtids_log_event
中的 GTID,以及先前檔案本身的每個 Gtid_log_event
的 GTID 組成)。最舊和最新的二進位記錄檔中 Previous_gtids_log_event
的內容用於計算伺服器啟動時的 gtid_executed
和 gtid_purged
集。
gtid_executed
的計算方式為:最新二進位記錄檔中Previous_gtids_log_event
中的 GTID、該二進位記錄檔中交易的 GTID,以及儲存在mysql.gtid_executed
表中的 GTID 的聯集。此 GTID 集包含在伺服器上使用過的所有 GTID(或明確添加到gtid_purged
的 GTID),無論它們目前是否在伺服器上的二進位記錄檔中。它不包含目前在伺服器上處理的交易之 GTID (@@GLOBAL.gtid_owned
)。gtid_purged
的計算方式為:首先加入最新二進位記錄檔中Previous_gtids_log_event
中的 GTID 和該二進位記錄檔中交易的 GTID。此步驟會產生目前或曾經在伺服器上的二進位記錄中記錄的 GTID 集 (gtids_in_binlog
)。接下來,從gtids_in_binlog
中減去最舊二進位記錄檔中Previous_gtids_log_event
中的 GTID。此步驟會產生目前在伺服器上的二進位記錄中記錄的 GTID 集 (gtids_in_binlog_not_purged
)。最後,從gtid_executed
中減去gtids_in_binlog_not_purged
。結果是在伺服器上使用過,但目前未記錄在伺服器上的二進位記錄檔中的 GTID 集,並且此結果用於初始化gtid_purged
。
如果您需要在伺服器上重設 GTID 執行歷程記錄,請使用 RESET BINARY LOGS AND GTIDS
語句。在新的啟用 GTID 的伺服器上執行測試查詢以驗證複寫設定之後,或者當您想將新的伺服器加入複寫群組,但它包含群組複寫不接受的一些不需要的本機交易時,您可能需要執行此操作。
請謹慎使用 RESET BINARY LOGS AND GTIDS
,以避免遺失任何需要的 GTID 執行歷程記錄和二進位記錄檔。
在發出 RESET BINARY LOGS AND GTIDS
之前,請確保您擁有伺服器的二進位記錄檔和二進位記錄索引檔(如果有的話)的備份,並取得並儲存 gtid_executed
系統變數的廣域值中持有的 GTID 集(例如,透過發出 SELECT @@GLOBAL.gtid_executed
語句並儲存結果)。如果您要從該 GTID 集中移除不需要的交易,請使用 mysqlbinlog 檢查交易的內容,以確保它們沒有值,不包含必須儲存或複寫的任何資料,並且沒有在伺服器上造成資料變更。
當您發出 RESET BINARY LOGS AND GTIDS
時,會執行下列重設操作:
gtid_purged
系統變數的值會設定為空字串 (''
)。gtid_executed
系統變數的廣域值(但不是會期值)會設定為空字串。mysql.gtid_executed
表格會被清除(請參閱 mysql.gtid_executed 表格)。如果伺服器已啟用二進位記錄,則會刪除現有的二進位記錄檔,並清除二進位記錄索引檔。
請注意,即使伺服器是停用二進位記錄的複寫伺服器,RESET BINARY LOGS AND GTIDS
也是重設 GTID 執行歷程記錄的方法。RESET REPLICA
對於 GTID 執行歷程記錄沒有影響。