PolarDB MySQL版多主叢集(庫表)實現從一寫多讀架構到多寫多讀多主架構的升級;支援不同資料庫或不同資料對象在不同計算節點並發寫入;支援資料庫和資料對象跨節點動態調度,秒級完成切換,極大提升執行個體整體並發讀寫能力。資料對象目前包括如下對象:表(Table)、視圖(View)、觸發器(Trigger)、定時任務(Event)、預存程序(Procedure)、自訂函數(Function)。本文介紹多主叢集(庫表)的使用說明。
前提條件
使用限制
每個資料庫或資料對象的資料只能通過一個節點寫入。沒有分配資料庫或資料對象的節點,不能進行讀寫操作。預設情況下,按照資料庫的維度進行操作,如果需要按照資料對象的維度進行操作,需要使用指定的文法切換。
不支援跨RW節點的資料查詢。如果一個查詢SQL中包含多個RW節點上的資料庫或資料對象,系統則會報錯。建議您先把所有資料庫或資料對象的訪問點調整到其中一個RW節點上,再進行查詢操作。
僅提供叢集地址,不支援主地址。
資料庫訪問點切換支援以下模式:
如果使用資料庫隔離等級,則需要切換資料庫訪問點。
如果使用資料對象隔離等級,則需要切換資料對象訪問點。
建立資料庫時指定RW節點
在指定的RW節點上建立資料庫。文法結構如下:
CREATE DATABASE name [POLARDB_WRITE_NODE master_id];
在資料庫隔離等級維度操作模式下,每個資料庫的資料只能通過一個節點寫入。
如果上述文法中省略了
[POLARDB_WRITE_NODE master_id]
,那麼建立資料庫時就會參考loose_innodb_mm_default_master_id參數的值來指定建立資料庫的RW節點。如果loose_innodb_mm_default_master_id參數的值為0,系統則隨機指定一個RW節點來建立資料庫。
樣本:在RW1上建立一個資料庫db1
。
CREATE DATABASE db1 POLARDB_WRITE_NODE 1;
如果需要在RW2上建立資料庫db1
,把上述樣本中的1換成2即可。
刪除在指定RW節點上建立的資料庫
刪除在指定RW節點上建立的資料庫。文法結構如下:
DROP DATABASE name;
樣本:刪除在RW1節點上建立的資料庫db1
。
DROP DATABASE db1;
刪除資料庫時,無需指定POLARDB_WRITE_NODE。
資料庫訪問點切換
把資料庫的訪問點切換到其他RW節點上。文法結構如下:
ALTER DATABASE name POLARDB_WRITE_NODE master_id;
樣本:把資料庫db1
切換到RW2上。
ALTER DATABASE db1 POLARDB_WRITE_NODE 2;
正常情況下,訪問點切換是一個耗時的操作。具體執行時間取決於以下兩個因素:
資料庫下表的個數。數量越多,切換速度越慢。
切換時資料庫的DML壓力。壓力越大,切換速度越慢。
資料庫隔離等級切換為資料對象隔離等級
預設情況下,多主叢集隔離等級是資料庫層級,即同一個資料庫下的所有資料對象只能在一個RW節點上訪問。如果想讓同一個資料庫下的所有資料對象通過多個RW訪問,那麼就需要把資料庫隔離等級修改成資料對象隔離等級。文法結構如下:
ALTER DATABASE name TO TABLE_LOCK POLARDB_WRITE_NODE master_id;
其中name為資料庫的名稱。master_id為資料對象的訪問點。
樣本:把資料庫db1
的資料對象隔離等級改為資料庫隔離等級,並且設定訪問點為RW2。
ALTER DATABASE db1 TO TABLE_LOCK POLARDB_WRITE_NODE 2;
正常情況下,隔離等級切換是一個耗時的操作。具體執行時間取決於以下兩個因素:
資料庫下的所有對象的個數。數量越多,切換速度越慢。
切換時資料庫的DML壓力。壓力越大,切換速度越慢。
資料對象隔離等級切換為資料庫隔離等級
如果將一個資料庫的最小粒度改為資料對象層級後,再恢複成資料庫隔離等級以方便管理,可以使用如下的切換語句:
ALTER DATABASE name TO DB_LOCK POLARDB_WRITE_NODE master_id;
其中name為資料庫的名稱。master_id為資料庫的訪問點。
樣本:把資料庫db1
的資料對象隔離等級改為資料庫隔離等級,並且設定訪問點是RW1。
ALTER DATABASE db1 TO DB_LOCK POLARDB_WRITE_NODE 1;
正常情況下,隔離等級切換是一個耗時的操作。具體執行時間取決於以下兩個因素:
資料庫下的所有對象的個數。數量越多,切換速度越慢。
切換時資料庫的DML壓力。壓力越大,切換速度越慢。
資料對象訪問點切換
多主叢集的隔離等級調整為資料對象層級後,同一個資料庫下,可能會有多個物件類型,包括TABLE、VIEW、TRIGGER、FUNCTION、PROCEDURE、EVENT。如果需要切換這些對象的訪問點,可以使用如下的切換語句:
ALTER obj_type name POLARDB_WRITE_NODE master_id;
其中obj_type可選的值分別為:TABLE、VIEW、TRIGGER、FUNCTION、PROCEDURE、EVENT。name為資料對象的名稱。
樣本1:把資料庫db1
下的t1表的訪問點切換到RW3。
ALTER TABLE db1.t1 POLARDB_WRITE_NODE 3;
樣本2:把當前資料庫下的t2 VIEW的訪問點切換到RW2。
ALTER VIEW t2 POLARDB_WRITE_NODE 2;
樣本3:把資料庫db2
下的function f1和function f2的訪問點切換到RW1。
ALTER FUNCTION db2.f1, db2.f2 POLARDB_WRITE_NODE 1;
正常情況下,訪問點切換是一個耗時的操作。具體執行時間取決於以下因素:
切換時資料對象的DML壓力。壓力越大,切換速度越慢。
對象之間可能會有關聯,如果關聯對象的訪問點沒有在同一個RW上,可能會導致對象失效。
例如,視圖VIEW1底層依賴表t1,但是視圖VIEW1的訪問點在RW1,而表t1的訪問點在RW2。那麼我們在RW1上訪問視圖VIEW1時會訪問出錯。同理,如果FUNCTION、PROCEDURE、EVENT引用的對象沒有正確的訪問點,也會導致執行失敗。TRIGGER和TABLE的訪問點不在一起,也會導致TABLE無法修改資料。
如果表t1和t2之間有外鍵約束關係,那麼修改任意一個表的訪問點,會自動修改另外一個表的訪問點。
指定SQL語句執行的RW節點
該功能僅適用於非資料查詢的語句,例如查詢information_schema、查詢status變數等。如果需要查詢資料,例如查詢語句SELECT * FROM table1
,不需要指定RW節點,資料庫代理會自動選擇正確的RW節點執行查詢。
如果需要把某條SQL語句發送到指定的RW節點,則需要執行以下SQL語句鎖定某個RW節點:
ALTER SESSION POLARDB_WRITE_NODE master_id;
樣本:查詢RW1節點上innodb_buffer_pool_size
這個變數的值。
ALTER SESSION POLARDB_WRITE_NODE 1; #把SQL語句發送到RW1節點。
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; #查詢RW1節點上innodb_buffer_pool_size的值。
如果在執行某條SQL語句時不指定RW節點,那麼資料庫代理會隨機播放一個RW節點執行該SQL語句。
執行以下命令可以解鎖指定執行SQL語句的RW節點:
RESET SESSION POLARDB_WRITE_NODE;
查詢節點資訊
執行以下命令可以查詢某個RW節點上的資料庫分布情況:
ALTER SESSION POLARDB_WRITE_NODE master_id; SELECT * FROM INFORMATION_SCHEMA.INNODB_MASTER_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X';
樣本:查詢RW1節點上的資料庫分布情況。
ALTER SESSION POLARDB_WRITE_NODE 1; SELECT * FROM INFORMATION_SCHEMA.INNODB_MASTER_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X';
查詢結果如下:
SELECT * FROM INFORMATION_SCHEMA.INNODB_MASTER_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X'; +------------+---------------------+----------+--------------+-----------+----------+-------------+-------------+---------------------+-----------------+ | table_name | table_id | space_id | s_lock_count | lock_mode | object | current_lsn | hold_thread | hold_start_time | hold_total_time | +------------+---------------------+----------+--------------+-----------+----------+-------------+-------------+---------------------+-----------------+ | test3/f1 | 9149389368458135753 | 0 | 0 | SLS_X | function | 28076635 | 17 | 2024-07-10 21:35:20 | 214 | | test3/e1 | 9149389368458332874 | 0 | 0 | SLS_X | event | 28077248 | 17 | 2024-07-10 21:35:30 | 204 | | test3/v1 | 9149389368457234649 | 0 | 0 | SLS_X | view | 28075972 | 17 | 2024-07-10 21:35:08 | 226 | | sbtest | 2107518311328629409 | 0 | 0 | SLS_X | db | 28034927 | 4294967295 | 2024-07-07 23:04:41 | 254053 | | test | 7190879906290573778 | 0 | 0 | SLS_X | db | 28034927 | 4294967295 | 2024-07-10 11:20:57 | 37077 | | test2 | 3381728963524265351 | 0 | 0 | SLS_X | db | 28034927 | 4294967295 | 2024-07-10 11:13:09 | 37545 | +------------+---------------------+----------+--------------+-----------+----------+-------------+-------------+---------------------+-----------------+ 6 rows in set (0.00 sec)
上述查詢結果中的每一行都是一個資料庫或資料對象的資訊(雖然列名是table_name)。上圖中,
sbtest
、test
、test2
分別是資料庫的隔離等級,function test3.f1
是資料對象隔離等級,event test3.e1
是資料對象隔離等級,view test3.v1
也是資料對象隔離等級。此外,可能會查詢出名稱為mysql/global_ddl_lock且object類型為Table的資訊,這個是內部使用的資訊,您無需關注。執行以下命令可以查詢整個叢集上所有資料庫的分布情況:
說明僅支援通過高許可權帳號查詢,您不能通過建立的帳號進行查詢。
SELECT * FROM INFORMATION_SCHEMA.INNODB_CC_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X';
查詢結果如下:
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_CC_GLOBAL_LOCK_INFO WHERE LOCK_MODE = 'SLS_X'; +-----------+------------+---------------------+-----------+-----------+-------------+---------------------+-----------------+ | master_id | table_name | table_id | lock_mode | object | current_lsn | hold_start_time | hold_total_time | +-----------+------------+---------------------+-----------+-----------+-------------+---------------------+-----------------+ | 1 | test3/v1 | 9149389368457234649 | SLS_X | view | 28075972 | 2024-07-10 21:35:08 | 754 | | 2 | test5/t1 | 9149389447232697561 | SLS_X | table | 7256175 | 2024-07-10 21:46:36 | 66 | | 1 | test2 | 3381728963524265351 | SLS_X | db | 28034927 | 2024-07-10 11:13:09 | 38073 | | 2 | test4 | 3381728963524272009 | SLS_X | db | 7255352 | 2024-07-10 21:46:27 | 75 | | 1 | test3/f1 | 9149389368458135753 | SLS_X | function | 28076635 | 2024-07-10 21:35:20 | 742 | | 1 | test3/e1 | 9149389368458332874 | SLS_X | event | 28077248 | 2024-07-10 21:35:30 | 732 | | 1 | test | 7190879906290573778 | SLS_X | db | 28034927 | 2024-07-10 11:20:57 | 37605 | | 2 | test5/p1 | 9149389447233473757 | SLS_X | procedure | 7257051 | 2024-07-10 21:46:45 | 57 | | 1 | sbtest | 2107518311328629409 | SLS_X | db | 28034927 | 2024-07-07 23:04:41 | 254581 | +-----------+------------+---------------------+-----------+-----------+-------------+---------------------+-----------------+ 9 rows in set (0.00 sec)
上述查詢結果中的每一行就是一個資料庫或資料對象的資訊(雖然列名是table_name),表示這個資料庫或資料對象是在對應的RW上。此外,可能會查詢出名稱為mysql/global_ddl_lock且object類型為Table的資訊,這個是內部使用的資訊,您無需關注。
如何設定Binlog
多主叢集(庫表)100%相容MySQL的Binlog,它整合叢集中所有RW節點上的動作記錄,產生出全域統一、邏輯有序的Binlog日誌。
您可以通過loose_polar_log_bin來開啟多主叢集(庫表)的Binlog功能,通過binlog_expire_logs_seconds來設定多主叢集(庫表)Binlog的儲存時間長度。詳細資料請參見開啟Binlog。
多主叢集(庫表)可以作為Data Transmission Service的源端和目的端,來進行資料的單向或雙向同步。