NDB Cluster 中的複寫會使用在作為叢集複寫來源和複本的叢集中,每個作為 SQL 節點的 MySQL 伺服器執行個體上的 mysql
資料庫中的許多專用表格。無論複本是單一伺服器還是叢集,都是如此。
ndb_binlog_index
和 ndb_apply_status
表格會在 mysql
資料庫中建立。使用者不應明確地複寫它們。通常不需要使用者介入來建立或維護這些表格,因為兩者都由 NDB
二進位記錄檔 (binlog) 注入器執行緒維護。這會讓來源 mysqld 程序保持更新至 NDB
儲存引擎執行的變更。NDB
binlog 注入器執行緒會直接從 NDB
儲存引擎接收事件。NDB
注入器負責擷取叢集內的所有資料事件,並確保所有變更、插入或刪除資料的事件都會記錄在 ndb_binlog_index
表格中。複本 I/O(接收器)執行緒會將事件從來源的二進位記錄檔傳輸到複本的中繼記錄檔。
ndb_replication
表格必須手動建立。使用者可以更新此表格,以依據資料庫或表格執行篩選。如需更多資訊,請參閱 ndb_replication 表格。ndb_replication
也用於 NDB 複寫衝突偵測和衝突解決,以進行衝突解決控制;請參閱 衝突解決控制。
即使 ndb_binlog_index
和 ndb_apply_status
會自動建立和維護,建議在準備用於複寫的 NDB Cluster 時,檢查這些表格的存在和完整性作為初始步驟。可以透過直接在來源上查詢 mysql.ndb_binlog_index
表格來檢視記錄在二進位記錄檔中的事件資料。這也可以透過在來源或複本 SQL 節點上使用 SHOW BINLOG EVENTS
陳述式來完成。(請參閱 第 15.7.7.3 節,〈SHOW BINLOG EVENTS 陳述式〉。)
您也可以從 SHOW ENGINE NDB STATUS
的輸出取得有用的資訊。
在 NDB
表格上執行架構變更時,應用程式應該等待,直到 ALTER TABLE
陳述式在發出陳述式的 MySQL 用戶端連線中傳回,然後再嘗試使用表格的更新定義。
ndb_apply_status
用於記錄已從來源複寫到複本的操作。如果複本上不存在 ndb_apply_status
表格,ndb_restore 會重新建立它。
不同於 ndb_binlog_index
的情況,此表格中的資料不是特定於(複本)叢集中的任何一個 SQL 節點,因此 ndb_apply_status
可以使用 NDBCLUSTER
儲存引擎,如下所示
CREATE TABLE `ndb_apply_status` (
`server_id` INT(10) UNSIGNED NOT NULL,
`epoch` BIGINT(20) UNSIGNED NOT NULL,
`log_name` VARCHAR(255) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`start_pos` BIGINT(20) UNSIGNED NOT NULL,
`end_pos` BIGINT(20) UNSIGNED NOT NULL,
PRIMARY KEY (`server_id`) USING HASH
) ENGINE=NDBCLUSTER DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
ndb_apply_status
表格僅在複本上填入,這表示在來源上,此表格絕不會包含任何列;因此,不需要在那裡將任何 DataMemory
分配給 ndb_apply_status
。
因為此表格是從來源的資料填入,因此應該允許複寫;任何無意間阻止複本更新 ndb_apply_status
或阻止來源寫入二進位記錄檔的複寫篩選或二進位記錄檔篩選規則,都可能會阻止叢集之間的複寫正常運作。如需更多關於此類篩選規則可能產生之問題的資訊,請參閱 NDB 叢集之間複寫的複寫和二進位記錄檔篩選規則。
可以刪除此表格,但不建議這麼做。刪除它會將所有 SQL 節點設為唯讀模式;NDB
會偵測到已捨棄此表格,並重新建立它,之後可以再次執行更新。捨棄和重新建立 ndb_apply_status
會在二進位記錄檔中建立間隔事件;間隔事件會導致複本 SQL 節點停止套用來自來源的變更,直到重新啟動複寫通道為止。
此表格的 epoch
資料行中的 0
表示來自 NDB
以外儲存引擎的交易。
ndb_apply_status
用於記錄哪些 epoch 交易已從上游來源複寫和套用至複本叢集。此資訊會擷取在 NDB
線上備份中,但(依設計)不會由 ndb_restore 還原。在某些情況下,為了在新設定中使用,還原此資訊會很有幫助;您可以使用 ndb_restore 和 --with-apply-status
選項來完成。如需更多資訊,請參閱選項的描述。
NDB Cluster 複寫會使用 ndb_binlog_index
表格來儲存二進位記錄檔的索引資料。由於此表格是每個 MySQL 伺服器本機的,且不會參與叢集,因此它會使用 InnoDB
儲存引擎。這表示它必須在參與來源叢集的每個 mysqld 上單獨建立。(二進位記錄檔本身包含來自叢集中所有 MySQL 伺服器的更新。)此表格的定義如下
CREATE TABLE `ndb_binlog_index` (
`Position` BIGINT(20) UNSIGNED NOT NULL,
`File` VARCHAR(255) NOT NULL,
`epoch` BIGINT(20) UNSIGNED NOT NULL,
`inserts` INT(10) UNSIGNED NOT NULL,
`updates` INT(10) UNSIGNED NOT NULL,
`deletes` INT(10) UNSIGNED NOT NULL,
`schemaops` INT(10) UNSIGNED NOT NULL,
`orig_server_id` INT(10) UNSIGNED NOT NULL,
`orig_epoch` BIGINT(20) UNSIGNED NOT NULL,
`gci` INT(10) UNSIGNED NOT NULL,
`next_position` bigint(20) unsigned NOT NULL,
`next_file` varchar(255) NOT NULL,
PRIMARY KEY (`epoch`,`orig_server_id`,`orig_epoch`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
如果您是從較舊的版本升級,請執行 MySQL 升級程序,並確保透過使用 --upgrade=FORCE
選項啟動 MySQL 伺服器來升級系統表格。系統表格升級會針對此表格執行 ALTER TABLE ... ENGINE=INNODB
陳述式。為了回溯相容性,仍支援將 MyISAM
儲存引擎用於此表格。
在轉換為 InnoDB
之後,ndb_binlog_index
可能需要額外的磁碟空間。如果這成為問題,您可以透過以下方式節省空間:為此資料表使用 InnoDB
表空間、將其 ROW_FORMAT
變更為 COMPRESSED
,或同時使用這兩種方法。如需更多資訊,請參閱第 15.1.21 節「CREATE TABLESPACE Statement」、第 15.1.20 節「CREATE TABLE Statement」,以及第 17.6.3 節「表空間」。
ndb_binlog_index
資料表的大小取決於每個二進制記錄檔的時段數量和二進制記錄檔的數量。每個二進制記錄檔的時段數量通常取決於每個時段產生的二進制記錄數量和二進制記錄檔的大小,較小的時段會導致每個檔案有更多的時段。您應該知道,即使 --ndb-log-empty-epochs
選項為 OFF
,空的時段也會產生對 ndb_binlog_index
資料表的插入,這表示每個檔案的條目數量取決於檔案的使用時間長度;這種關係可以用這裡顯示的公式表示
[number of epochs per file] = [time spent per file] / TimeBetweenEpochs
繁忙的 NDB Cluster 會定期寫入二進制記錄檔,並且可能比不繁忙的 NDB Cluster 更快地輪換二進制記錄檔。這表示一個具有 --ndb-log-empty-epochs=ON
的「安靜」 NDB Cluster 實際上可能比一個活動量大的 NDB Cluster 每檔案擁有更多的 ndb_binlog_index
資料列。
當使用 --ndb-log-orig
選項啟動 mysqld 時,orig_server_id
和 orig_epoch
欄位分別儲存事件發生的伺服器 ID 和事件在原始伺服器上發生的時段,這在採用多個來源的 NDB Cluster 複寫設定中很有用。在多來源設定中,用於在複本上尋找最接近已套用最高時段的二進制記錄位置的 SELECT
陳述式(請參閱第 25.7.10 節「NDB Cluster 複寫:雙向和循環複寫」)使用這兩個未建立索引的欄位。這可能會在嘗試容錯移轉時導致效能問題,因為查詢必須執行資料表掃描,尤其是在來源已使用 --ndb-log-empty-epochs=ON
執行時。您可以透過將索引新增至這些欄位來縮短多來源容錯移轉時間,如下所示
ALTER TABLE mysql.ndb_binlog_index
ADD INDEX orig_lookup USING BTREE (orig_server_id, orig_epoch);
當從單一來源複寫到單一複本時,新增此索引沒有任何好處,因為在這種情況下,用於取得二進制記錄位置的查詢不會使用 orig_server_id
或 orig_epoch
。
如需有關使用 next_position
和 next_file
欄位的更多資訊,請參閱第 25.7.8 節「使用 NDB Cluster 複寫實作容錯移轉」。
下圖顯示 NDB Cluster 複寫來源伺服器、其二進制記錄注入執行緒和 mysql.ndb_binlog_index
資料表的關係。
ndb_replication
資料表用於控制二進制記錄和衝突解決,並以每個資料表為基礎運作。此資料表中的每一列都對應於一個正在複寫的資料表,決定如何記錄對資料表的變更,如果指定了衝突解決函式,則決定如何解決該資料表的衝突。
與 ndb_apply_status
和 ndb_replication
資料表不同,ndb_replication
資料表必須使用這裡顯示的 SQL 陳述式手動建立
CREATE TABLE mysql.ndb_replication (
db VARBINARY(63),
table_name VARBINARY(63),
server_id INT UNSIGNED,
binlog_type INT UNSIGNED,
conflict_fn VARBINARY(128),
PRIMARY KEY USING HASH (db, table_name, server_id)
) ENGINE=NDB
PARTITION BY KEY(db,table_name);
此資料表的欄位列出如下,並附有說明
db
欄位包含要複寫之資料表的資料庫名稱。
您可以在資料庫名稱中使用萬用字元
_
和%
的其中一個或兩個。(請參閱本節稍後的使用萬用字元比對)。table_name
欄位要複寫的資料表名稱。
資料表名稱可以包含萬用字元
_
和%
的其中一個或兩個。請參閱本節稍後的使用萬用字元比對。server_id
欄位MySQL 執行個體 (SQL 節點) 的唯一伺服器 ID,資料表位於其中。
此欄位中的
0
的作用類似於%
的萬用字元,並比對任何伺服器 ID。(請參閱本節稍後的使用萬用字元比對)。binlog_type
欄位要採用的二進制記錄類型。請參閱文字以取得值和說明。
conflict_fn
欄位要套用的衝突解決函式;可以是 NDB$OLD()、NDB$MAX()、NDB$MAX_DELETE_WIN()、NDB$EPOCH()、NDB$EPOCH_TRANS()、NDB$EPOCH2()、NDB$EPOCH2_TRANS() NDB$MAX_INS() 或 NDB$MAX_DEL_WIN_INS() 的其中一個;
NULL
表示此資料表不使用衝突解決。如需有關這些函式及其在 NDB 複寫衝突解決中的用途的更多資訊,請參閱衝突解決函式。
某些衝突解決函式(
NDB$OLD()
、NDB$EPOCH()
、NDB$EPOCH_TRANS()
)需要使用一或多個使用者建立的例外狀況資料表。請參閱衝突解決例外狀況資料表。
若要透過 NDB 複寫啟用衝突解決,必須在應該解決衝突的 SQL 節點上建立此資料表並填入控制資訊。根據要採用的衝突解決類型和方法,這可能是來源、複本或兩個伺服器。在可以也在複本上本機變更資料的簡單來源-複本設定中,這通常是複本。在更複雜的複寫配置中(例如雙向複寫),這通常是所有涉及的來源。如需更多資訊,請參閱第 25.7.12 節「NDB Cluster 複寫衝突解決」。
ndb_replication
資料表允許在衝突解決範圍之外對二進制記錄進行資料表層級的控制,在這種情況下,conflict_fn
指定為 NULL
,而其餘的欄位值則用於控制給定資料表或一組符合萬用字元運算式的資料表的二進制記錄。透過為 binlog_type
欄位設定適當的值,您可以讓給定資料表或多個資料表的記錄使用所需的二進制記錄格式,或完全停用二進制記錄。此欄位的可能值(附值和說明)顯示在下表中
表 25.42 binlog_type
值(附值和說明)
值 | 說明 |
---|---|
0 | 使用伺服器預設值 |
1 | 請勿在二進制記錄檔中記錄此資料表(與 sql_log_bin = 0 的效果相同,但僅適用於一個或多個指定的資料表) |
2 | 僅記錄更新的屬性;將這些屬性記錄為 WRITE_ROW 事件 |
3 | 記錄完整資料列,即使未更新(MySQL 伺服器預設行為) |
6 | 使用更新的屬性,即使值未變更 |
7 | 記錄完整資料列,即使沒有值變更;將更新記錄為 UPDATE_ROW 事件 |
8 | 將更新記錄為 UPDATE_ROW ;僅在更新前影像中記錄主鍵欄位,並僅在更新後影像中記錄更新的欄位(與 --ndb-log-update-minimal 的效果相同,但僅適用於一個或多個指定的資料表) |
9 | 將更新記錄為 UPDATE_ROW ;僅在更新前影像中記錄主鍵欄位,並在更新後影像中記錄主鍵欄位以外的所有欄位 |
binlog_type
值 4 和 5 未使用,因此從剛才顯示的資料表和下一個資料表中省略。
多個 binlog_type
值等同於 mysqld 記錄選項 --ndb-log-updated-only
、--ndb-log-update-as-write
和 --ndb-log-update-minimal
的各種組合,如下表所示
表 25.43 binlog_type
值(附等效的 NDB 記錄選項組合)
值 | --ndb-log-updated-only 值 |
--ndb-log-update-as-write 值 |
--ndb-log-update-minimal 值 |
---|---|---|---|
0 | -- | -- | -- |
1 | -- | -- | -- |
2 | ON | ON | OFF |
3 | OFF | ON | OFF |
6 | ON | OFF | OFF |
7 | OFF | OFF | OFF |
8 | ON | OFF | ON |
9 | OFF | OFF | ON |
透過使用適當的 db
、table_name
和 binlog_type
欄位值將資料列插入 ndb_replication
資料表中,可以為不同的資料表設定不同的二進制記錄格式。設定二進制記錄格式時,應使用上表所示的內部整數值。下列兩個陳述式將資料表 test.a
的二進制記錄設定為記錄完整資料列(值 3),並將資料表 test.b
的二進制記錄設定為僅記錄更新(值 2)
# Table test.a: Log full rows
INSERT INTO mysql.ndb_replication VALUES("test", "a", 0, 3, NULL);
# Table test.b: log updates only
INSERT INTO mysql.ndb_replication VALUES("test", "b", 0, 2, NULL);
若要停用一個或多個資料表的記錄,請將 binlog_type
設定為 1,如下所示
# Disable binary logging for table test.t1
INSERT INTO mysql.ndb_replication VALUES("test", "t1", 0, 1, NULL);
# Disable binary logging for any table in 'test' whose name begins with 't'
INSERT INTO mysql.ndb_replication VALUES("test", "t%", 0, 1, NULL);
停用給定資料表的記錄相當於設定 sql_log_bin = 0
,但它會個別套用至一個或多個資料表。如果 SQL 節點未對給定資料表執行二進制記錄,則不會將這些資料表的資料列變更事件傳送至 SQL 節點。這表示它不是接收所有變更並捨棄部分變更,而是未訂閱這些變更。
停用記錄在許多情況下都很有用,包括此處列出的情況
通常,不跨網路傳送變更可以節省頻寬、緩衝和 CPU 資源。
對於更新頻繁但其值不重要的資料表,不記錄變更是適合暫時性資料(例如工作階段資料)的做法,這類資料在叢集完全失效時可能相對不重要。
透過使用工作階段變數(或
sql_log_bin
)和應用程式碼,也可以記錄(或不記錄)某些 SQL 陳述式或類型的 SQL 陳述式;例如,在某些情況下,可能不希望記錄一個或多個資料表的 DDL 陳述式。將複寫串流分割成兩個(或更多)二進位日誌的原因可能是為了效能考量、需要將不同的資料庫複寫到不同的位置、為不同的資料庫使用不同的二進位日誌類型等等。
使用萬用字元比對。為了避免在複寫設定中,必須為每個資料庫、資料表和 SQL 節點的組合在 ndb_replication
資料表中插入一列,NDB
支援對此資料表的 db
、table_name
和 server_id
欄位使用萬用字元比對。在 db
和 table_name
中分別使用的資料庫和資料表名稱,可以包含下列一或多種萬用字元
_
(底線字元):比對零個或多個字元%
(百分比符號):比對單一字元
(這些是 MySQL LIKE
運算子支援的相同萬用字元。)
server_id
欄位支援使用 0
作為相當於 _
(比對任何內容)的萬用字元。這會用於先前顯示的範例中。
在 ndb_replication
資料表中的指定列可以使用萬用字元,來比對資料庫名稱、資料表名稱和伺服器 ID 的任何組合。如果資料表中有多個潛在的相符項目,則會根據此處顯示的資料表選擇最佳相符項目,其中 W 表示萬用字元比對,E 表示完全相符,且 品質 欄中的值越大,則相符程度越佳
表 25.44 mysql.ndb_replication 資料表中欄位上不同的萬用字元和完全相符組合的權重
db |
table_name |
server_id |
品質 |
---|---|---|---|
W | W | W | 1 |
W | W | E | 2 |
W | E | W | 3 |
W | E | E | 4 |
E | W | W | 5 |
E | W | E | 6 |
E | E | W | 7 |
E | E | E | 8 |
因此,資料庫名稱、資料表名稱和伺服器 ID 的完全相符被認為是最佳(最強)的,而最弱(最差)的相符則是三個欄位上的萬用字元比對。選擇要套用哪個規則時,只會考慮相符的強度;資料表中列的出現順序對此判斷沒有影響。
記錄完整或部分列。 記錄列的基本方法有兩種,由 --ndb-log-updated-only
選項的設定來決定,適用於 mysqld
記錄完整列(選項設定為
ON
)只記錄已更新的欄位資料,也就是說,無論此值是否真的已變更,都只會記錄已設定值的欄位資料。這是預設行為(選項設定為
OFF
)。
通常只記錄已更新的欄位已足夠,且更有效率;但是,如果您需要記錄完整列,可以將 --ndb-log-updated-only
設定為 0
或 OFF
來達成。
將變更的資料記錄為更新。 MySQL Server 的 --ndb-log-update-as-write
選項設定決定是否記錄含有或不含 「之前」 影像的變更。
由於更新和刪除作業的衝突解決是在 MySQL Server 的更新處理常式中完成的,因此有必要控制複寫來源執行的記錄,以便將更新視為更新而非寫入;也就是說,即使更新取代了現有的列,也要將更新視為現有列中的變更,而不是寫入新的列。
此選項預設為開啟;換句話說,更新會被視為寫入。也就是說,更新預設會以二進位日誌中的 write_row
事件形式寫入,而不是以 update_row
事件形式寫入。
若要停用此選項,請使用 --ndb-log-update-as-write=0
或 --ndb-log-update-as-write=OFF
來啟動來源 mysqld。當從 NDB 資料表複寫到使用不同儲存引擎的資料表時,您必須執行此操作;請參閱從 NDB 複寫到其他儲存引擎和從 NDB 複寫到非交易儲存引擎以取得更多資訊。
若要使用 NDB$MAX_INS()
或 NDB$MAX_DEL_WIN_INS()
進行插入衝突解決,SQL 節點(也就是 mysqld 程序)可以在來源叢集上記錄列更新為 WRITE_ROW
事件,並啟用 --ndb-log-update-as-write
選項,以達到等冪性並獲得最佳大小。此方法適用於這些演算法,因為它們都會將 WRITE_ROW
事件對應到插入或更新,取決於該列是否已存在,而且所需的 metadata(時間戳記欄的 「之後」 影像)會出現在 「WRITE_ROW」 事件中。