本節提供預存函數的範例(請參閱第 27 章,預存物件),您可以使用 MySQL 提供的一些內建函數來建立這些函數,以用於基於 GTID 的複製,這些函數在此處列出
GTID_SUBSET()
:顯示一個 GTID 集是否為另一個 GTID 集的子集。GTID_SUBTRACT()
:傳回一個 GTID 集中不屬於另一個 GTID 集的 GTID。WAIT_FOR_EXECUTED_GTID_SET()
:等待直到執行指定 GTID 集中所有交易。
請參閱第 14.18.2 節,「搭配全域交易識別符 (GTID) 使用的函數」,以取得有關剛列出函數的更多資訊。
請注意,在這些儲存函數中,已使用分隔符號命令將 MySQL 語句分隔符號變更為垂直線,如下所示:
mysql> delimiter |
本節中顯示的所有儲存函數都將 GTID 集合的字串表示形式作為參數,因此在使用時,GTID 集合必須始終加上引號。
如果兩個 GTID 集合是相同的集合,即使它們的格式不同,此函數也會傳回非零值(true)。
CREATE FUNCTION GTID_IS_EQUAL(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS INT
RETURN GTID_SUBSET(gs1, gs2) AND GTID_SUBSET(gs2, gs1)
|
如果兩個 GTID 集合不相交,此函數會傳回非零值(true)。
CREATE FUNCTION GTID_IS_DISJOINT(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS INT
RETURN GTID_SUBSET(gs1, GTID_SUBTRACT(gs1, gs2))
|
如果兩個 GTID 集合不相交,且 sum
是它們的聯集,則此函數會傳回非零值 (true)。
CREATE FUNCTION GTID_IS_DISJOINT_UNION(gs1 LONGTEXT, gs2 LONGTEXT, sum LONGTEXT)
RETURNS INT
RETURN GTID_IS_EQUAL(GTID_SUBTRACT(sum, gs1), gs2) AND
GTID_IS_EQUAL(GTID_SUBTRACT(sum, gs2), gs1)
|
此函數會傳回 GTID 集合的標準化形式,全部為大寫,沒有空格,沒有重複項,UUID 按字母順序排列,間隔按數字順序排列。
CREATE FUNCTION GTID_NORMALIZE(gs LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gs, '')
|
此函數會傳回兩個 GTID 集合的聯集。
CREATE FUNCTION GTID_UNION(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_NORMALIZE(CONCAT(gs1, ',', gs2))
|
此函數會傳回兩個 GTID 集合的交集。
CREATE FUNCTION GTID_INTERSECTION(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gs1, GTID_SUBTRACT(gs1, gs2))
|
此函數會傳回兩個 GTID 集合之間的對稱差,也就是說,存在於 gs1
但不存在於 gs2
中的 GTID,以及存在於 gs2
但不存在於 gs1
中的 GTID。
CREATE FUNCTION GTID_SYMMETRIC_DIFFERENCE(gs1 LONGTEXT, gs2 LONGTEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(CONCAT(gs1, ',', gs2), GTID_INTERSECTION(gs1, gs2))
|
此函數會從 GTID 集合中移除所有具有指定來源的 GTID,並傳回剩餘的 GTID(如果有的話)。UUID 是交易來源伺服器所使用的識別碼,通常是 server_uuid
的值。
CREATE FUNCTION GTID_SUBTRACT_UUID(gs LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gs, CONCAT(UUID, ':1-', (1 << 63) - 2))
|
此函數的作用與前一個相反;它只會傳回 GTID 集合中來自具有指定識別碼(UUID)之伺服器的那些 GTID。
CREATE FUNCTION GTID_INTERSECTION_WITH_UUID(gs LONGTEXT, uuid TEXT)
RETURNS LONGTEXT
RETURN GTID_SUBTRACT(gs, GTID_SUBTRACT_UUID(gs, uuid))
|
範例 19.1 驗證複本是否為最新狀態
可以使用內建函數 GTID_SUBSET()
和 GTID_SUBTRACT()
來檢查複本是否至少已套用來源已套用的每個交易。
若要使用 GTID_SUBSET()
執行此檢查,請在複本上執行下列語句:
SELECT GTID_SUBSET(source_gtid_executed, replica_gtid_executed);
如果傳回值為 0
(false),則表示 source_gtid_executed
中的某些 GTID 不存在於 replica_gtid_executed
中,並且複本尚未套用在來源上套用的交易,這表示複本不是最新狀態。
若要使用 GTID_SUBTRACT()
執行相同的檢查,請在複本上執行下列語句:
SELECT GTID_SUBTRACT(source_gtid_executed, replica_gtid_executed);
此語句會傳回 source_gtid_executed
中但不在 replica_gtid_executed
中的任何 GTID。如果有任何 GTID 被傳回,則表示來源已套用複本尚未套用的一些交易,因此複本不是最新狀態。
範例 19.2 備份和還原情境
儲存函數 GTID_IS_EQUAL()
、GTID_IS_DISJOINT()
和 GTID_IS_DISJOINT_UNION()
可用於驗證涉及多個資料庫和伺服器的備份和還原作業。在此範例情境中,server1
包含資料庫 db1
,而 server2
包含資料庫 db2
。目標是將資料庫 db2
複製到 server1
,而 server1
上的結果應該是兩個資料庫的聯集。使用的程序是使用 mysqldump 備份 server2
,然後在 server1
上還原此備份。
假設 mysqldump 在 --set-gtid-purged
設定為 ON
或 AUTO
(預設值)的情況下執行,則輸出包含一個 SET @@GLOBAL.gtid_purged
語句,該語句會將來自 server2
的 gtid_executed
集合新增至 server1
上的 gtid_purged
集合。gtid_purged
包含在指定伺服器上已提交,但不存在於伺服器上任何二進位日誌檔案中的所有交易的 GTID。當資料庫 db2
複製到 server1
時,在 server2
上提交,但不在 server1
上二進位日誌檔案中的交易的 GTID,必須新增至 gtid_purged
以使 server1
的集合完整。
可以使用儲存函數來協助此情境中的下列步驟:
使用
GTID_IS_EQUAL()
來驗證備份作業是否為SET @@GLOBAL.gtid_purged
語句計算出正確的 GTID 集合。在server2
上,從 mysqldump 輸出中擷取該語句,並將 GTID 集合儲存到本機變數中,例如$gtid_purged_set
。然後執行下列語句:server2> SELECT GTID_IS_EQUAL($gtid_purged_set, @@GLOBAL.gtid_executed);
如果結果為 1,則表示兩個 GTID 集合相等,並且已正確計算集合。
使用
GTID_IS_DISJOINT()
來驗證 mysqldump 輸出中的 GTID 集合與server1
上的gtid_executed
集合不重疊。如果兩個伺服器上都存在相同的 GTID,則會導致在將資料庫db2
複製到server1
時發生錯誤。若要檢查,請在server1
上,擷取gtid_purged
並將其從輸出中儲存到如前所述的本機變數中,然後執行下列語句:server1> SELECT GTID_IS_DISJOINT($gtid_purged_set, @@GLOBAL.gtid_executed);
如果結果為 1,則表示兩個 GTID 集合之間沒有重疊,因此不存在重複的 GTID。
使用
GTID_IS_DISJOINT_UNION()
來驗證還原作業是否在server1
上產生正確的 GTID 狀態。在還原備份之前,請在server1
上執行下列語句,以取得現有的gtid_executed
集合:server1> SELECT @@GLOBAL.gtid_executed;
將結果儲存到本機變數
$original_gtid_executed
中,以及如前所述的gtid_purged
中的集合。當來自server2
的備份已還原到server1
上時,執行下列語句以驗證 GTID 狀態:server1> SELECT -> GTID_IS_DISJOINT_UNION($original_gtid_executed, -> $gtid_purged_set, -> @@GLOBAL.gtid_executed);
如果結果為
1
,則表示儲存函數已驗證來自server1
的原始gtid_executed
集合($original_gtid_executed
)和從server2
新增的gtid_purged
集合($gtid_purged_set
)沒有重疊,並且server1
上更新的gtid_executed
集合現在包含來自server1
的先前gtid_executed
集合,以及來自server2
的gtid_purged
集合,這是預期的結果。請確保在server1
上發生任何進一步的交易之前執行此檢查,否則gtid_executed
中的新交易會導致其失敗。
範例 19.3 為手動容錯移轉選擇最新的複本
儲存函數 GTID_UNION()
可用於從一組複本中識別最新的複本,以便在來源伺服器意外停止後執行手動容錯移轉作業。如果某些複本正在經歷複寫延遲,則可以使用此儲存函數來計算最新的複本,而無需等待所有複本套用其現有的中繼日誌,從而最大程度地減少容錯移轉時間。該函數可以傳回每個複本上的 gtid_executed
與複本接收的交易集合的聯集,該交易記錄在 Performance Schema replication_connection_status
表格中。您可以比較這些結果,以找出哪個複本的交易記錄最新,即使並非所有交易都已提交。
在每個複本上,發出下列語句來計算完整的交易記錄:
SELECT GTID_UNION(RECEIVED_TRANSACTION_SET, @@GLOBAL.gtid_executed)
FROM performance_schema.replication_connection_status
WHERE channel_name = 'name';
然後,您可以比較每個複本的結果,以查看哪個複本具有最新的交易記錄,並將此複本用作新的來源。
範例 19.4 檢查複本上是否有額外的交易
儲存函數 GTID_SUBTRACT_UUID()
可用於檢查複本是否已收到並非來自其指定的來源或多個來源的交易。如果是,則表示您的複寫設定、proxy、路由器或負載平衡器可能存在問題。此函數的作用是從 GTID 集合中移除所有來自指定來源伺服器的 GTID,並傳回剩餘的 GTID(如果有的話)。
對於具有單一來源的複本,請發出下列語句,並提供來源伺服器的識別碼,該識別碼通常與 server_uuid
相同:
SELECT GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed, server_uuid_of_source);
如果結果不為空,則傳回的交易是並非來自指定來源的額外交易。
對於多來源拓撲中的複本,請在函數呼叫中包含每個來源的伺服器 UUID,如下所示:
SELECT
GTID_SUBTRACT_UUID(GTID_SUBTRACT_UUID(@@GLOBAL.gtid_executed,
server_uuid_of_source_1),
server_uuid_of_source_2);
如果結果不為空,則傳回的交易是並非來自任何指定來源的額外交易。
範例 19.5 驗證複寫拓撲中的伺服器是否為唯讀
儲存函數 GTID_INTERSECTION_WITH_UUID()
可用於驗證伺服器是否未產生任何 GTID,並且處於唯讀狀態。該函數只會從 GTID 集合中傳回來自具有指定識別碼的伺服器的那些 GTID。如果此伺服器中 gtid_executed
中列出的任何交易使用伺服器自己的識別碼,則表示伺服器本身產生了那些交易。您可以在伺服器上發出下列語句來進行檢查:
SELECT GTID_INTERSECTION_WITH_UUID(@@GLOBAL.gtid_executed, my_server_uuid);
範例 19.6 在多來源複寫中驗證額外的複本
儲存函數 GTID_INTERSECTION_WITH_UUID()
可用於找出附加到多源複製設定的副本是否已套用來自特定來源的所有交易。在此情境中,source1
和 source2
都是來源和副本,並彼此複製。source2
也有自己的副本。如果 source2
設定為 log_replica_updates=ON
,則副本也會接收並套用來自 source1
的交易,但如果 source2
使用 log_replica_updates=OFF
,則不會這樣做。無論如何,我們目前只想找出副本是否與 source2
同步。在這種情況下,可以使用 GTID_INTERSECTION_WITH_UUID()
來識別 source2
起始的交易,並捨棄 source2
從 source1
複製的交易。然後,可以使用內建函數 GTID_SUBSET()
,將結果與副本上的 gtid_executed
集合作比較。如果副本與 source2
同步,則副本上的 gtid_executed
集合包含交集集合中的所有交易(即來自 source2
的交易)。
若要執行此檢查,請將 source2
的 gtid_executed
值和伺服器 UUID,以及副本的 gtid_executed
值,儲存到使用者變數中,如下所示:
source2> SELECT @@GLOBAL.gtid_executed INTO @source2_gtid_executed;
source2> SELECT @@GLOBAL.server_uuid INTO @source2_server_uuid;
replica> SELECT @@GLOBAL.gtid_executed INTO @replica_gtid_executed;
然後使用 GTID_INTERSECTION_WITH_UUID()
和 GTID_SUBSET()
,並以這些變數作為輸入,如下所示:
SELECT
GTID_SUBSET(
GTID_INTERSECTION_WITH_UUID(@source2_gtid_executed,
@source2_server_uuid),
@replica_gtid_executed);
來自 source2
的伺服器識別碼 (@source2_server_uuid
) 與 GTID_INTERSECTION_WITH_UUID()
一起使用,以識別並僅傳回來自 source2
上起始的 GTID 集合中的那些 GTID,並省略來自 source1
的 GTID。然後,使用 GTID_SUBSET()
將產生的 GTID 集合與副本上所有已執行 GTID 的集合進行比較。如果此陳述式傳回非零值 (true),則來自 source2
的所有已識別 GTID(第一個集合輸入)也會在副本的 gtid_executed
中找到,這表示副本已接收並執行來自 source2
的所有交易。