本文介紹了分析和處理資料扭曲問題的方法。
概述
PolarDB-X是由阿里巴巴自主研發的PolarDB分布式版資料庫,在實體資源上是由多個節點所組成的分布式叢集。通過資料分區的方式,可以將資料分布到叢集中的多個儲存節點,發揮多個節點的儲存和計算能力。
當資料分布不均勻,大部分資料集中在一兩個節點時,將導致節點負載過高、查詢緩慢,甚至造成節點故障,這種現象稱之為資料扭曲。這類問題無法通過擴容來解決,需要使用本文介紹的方法分析和處理。
問題分析
資料扭曲問題,DRDS模式資料庫可按照分庫級、分表級的方式進行分析。
AUTO模式資料庫可按照分區層級進行排查。
傳統單機資料庫切換到PolarDB-X分散式資料庫,請參見透明分布式。
分庫層級的資料扭曲(DRDS模式資料庫)
執行如下代碼,即可查看當前資料庫中的所有物理庫的資料大小:
show db status;返回資訊,樣本如下:
+----+---------------------------+--------------------+---------------------------+------------+--------+----------------+
| ID | NAME | CONNECTION_STRING | PHYSICAL_DB | SIZE_IN_MB | RATIO | THREAD_RUNNING |
+----+---------------------------+--------------------+---------------------------+------------+--------+----------------+
| 1 | hehe@polardbx-polardbx | 47.100.XX.XX:3306 | TOTAL | 0.875 | 100% | 1 |
| 2 | hehe@polardbx-polardbx | 47.100.XX.XX:3306 | hehe_000000 | 0.203125 | 23.21% | |
| 3 | hehe@polardbx-polardbx | 47.100.XX.XX:3306 | hehe_000001 | 0.203125 | 23.21% | |
| 4 | hehe@polardbx-polardbx | 47.100.XX.XX:3306 | hehe_000002 | 0.203125 | 23.21% | |
| 5 | hehe@polardbx-polardbx | 47.100.XX.XX:3306 | hehe_000003 | 0.203125 | 23.21% | |
| 6 | hehe@polardbx-polardbx | 47.100.XX.XX:3306 | hehe_single | 0.0625 | 7.14% | |
+----+---------------------------+--------------------+---------------------------+------------+--------+----------------+部分參數說明如下:
PHYSICAL_DB:物理庫名。
SIZE_IN_MB:資料大小。
RATIO:資料比例。
在資料扭曲的情況下,多個物理庫的資料大小SIZE_IN_MB和資料所佔比率RATIO會相差較大。
對於資料量較多的分庫,可以通過分表級的資訊進一步確認該分庫中的資料屬於哪些資料表。
分表層級資料扭曲(DRDS模式資料庫)
執行如下代碼,查看當前庫的所有資料表大小:
show table status;返回資訊,樣本如下:
+----------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+ | NAME | ENGINE | VERSION | ROW_FORMAT | ROWS | AVG_ROW_LENGTH | DATA_LENGTH | MAX_DATA_LENGTH | INDEX_LENGTH | DATA_FREE | AUTO_INCREMENT | CREATE_TIME | UPDATE_TIME | CHECK_TIME | COLLATION | CHECKSUM | CREATE_OPTIONS | COMMENT | +----------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+ | test_tb | InnoDB | 10 | Dynamic | 0 | 0 | 131072 | 0 | 131072 | 0 | 100000 | 2021-08-19 07:40:07 | <null> | <null> | utf8mb4_general_ci | <null> | | | +----------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------+說明部分參數說明如下:
ROWS:近似的資料行數。
DATA_LENGTH:近似的資料量。
執行
show table info from $TABLE語句,分析test_tb表中各個分表的資料大小,樣本如下:建立樣本表
test_tb:CREATE TABLE `test_tb` ( `id` int(11) DEFAULT NULL, `c1` bigint(20) DEFAULT NULL, `c2` varchar(100) DEFAULT NULL, KEY `auto_shard_key_id` USING BTREE (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 dbpartition by hash(`id`) tbpartition by hash(`id`) tbpartitions 2;查看並分析
test_tb表中各個分表的資料大小:show table info from test_tb;說明僅PolarDB-X的5.4.11及以上版本支援該命令。
返回資訊,樣本如下:
+----+--------------------+----------------+------------+ | ID | GROUP_NAME | TABLE_NAME | SIZE_IN_MB | +----+--------------------+----------------+------------+ | 0 | test_polarx_000000 | test_tb_hg6z_0 | 0.03125 | | 1 | test_polarx_000000 | test_tb_hg6z_1 | 0.03125 | | 2 | test_polarx_000001 | test_tb_hg6z_2 | 0.03125 | | 3 | test_polarx_000001 | test_tb_hg6z_3 | 0.03125 | | 4 | test_polarx_000002 | test_tb_hg6z_4 | 0.03125 | | 5 | test_polarx_000002 | test_tb_hg6z_5 | 0.03125 | | 6 | test_polarx_000003 | test_tb_hg6z_6 | 0.03125 | | 7 | test_polarx_000003 | test_tb_hg6z_7 | 0.03125 | +----+--------------------+----------------+------------+說明SIZE_IN_MB即每個分表的資料大小。
如果分表之間的資料容量相差較多,表示發生了分表的資料扭曲,可能是由於
tbpartition by的拆分不當導致的。如果分庫之間的資料量相差較多,表示發生了分庫的資料扭曲,可能是由於
dbpartition by拆分不當導致的。
分區級資料扭曲(AUTO模式資料庫)
對於PolarDB-X的分區表來說,支援更靈活的資料拆分方式,即LIST、HASH或RANGE分區,以及靈活的分區分裂、合并、遷移。
分區級資料扭曲樣本如下:
建立樣本表
test_tb:CREATE TABLE `test_tb` ( `id` int(11) DEFAULT NULL ) PARTITION BY RANGE(`id`) ( PARTITION p1 VALUES LESS THAN (1000), PARTITION p2 VALUES LESS THAN (2000), PARTITION p3 VALUES LESS THAN (3000), PARTITION p4 VALUES LESS THAN (4000), PARTITION p5 VALUES LESS THAN (5000), PARTITION p6 VALUES LESS THAN (6000), PARTITION p7 VALUES LESS THAN (7000), PARTITION p8 VALUES LESS THAN (8000) );執行如下程式碼分析
test_tb表中各個分區的資料大小:show table info from test_tb;執行如下代碼查詢
test_tb表的分區級的詳細資料:select * from information_schema.table_detail where table_name='test_tb';返回資訊,樣本如下:
+-------------+------------------+---------------+----------------+---------------+----------------+------------+-------------+--------------+----------------------------------------------+------------------------------------+ | TABLE_SCHEMA | TABLE_GROUP_NAME | TABLE_NAME | PHYSICAL_TABLE | PARTITION_SEQ | PARTITION_NAME | TABLE_ROWS | DATA_LENGTH | INDEX_LENGTH | BOUND_VALUE | PERCENT | +-------------+------------------+---------------+----------------+---------------+----------------+------------+-------------+--------------+----------------------------------------------+------------------------------------+ | partdb_test | tg73 | test_tb | test_tb_00000 | 0 | p1 | 0 | 16384 | 16384 | [MINVALUE, -6917529027641081843) | 0.00%├-------------------------┤ | | partdb_test | tg73 | test_tb | test_tb_00001 | 1 | p2 | 1 | 16384 | 16384 | [-6917529027641081843, -4611686018427387893) | 9.09%├███-----------------------┤ | | partdb_test | tg73 | test_tb | test_tb_00002 | 2 | p3 | 1 | 16384 | 16384 | [-4611686018427387893, -2305843009213693943) | 9.09%├███-----------------------┤ | | partdb_test | tg73 | test_tb | test_tb_00003 | 3 | p4 | 0 | 16384 | 16384 | [-2305843009213693943, 7) | 0.00%├-------------------------┤ | | partdb_test | tg73 | test_tb | test_tb_00004 | 4 | p5 | 6 | 16384 | 16384 | [7, 2305843009213693957) | 54.55%├██████████████------------┤ | | partdb_test | tg73 | test_tb | test_tb_00005 | 5 | p6 | 2 | 16384 | 16384 | [2305843009213693957, 4611686018427387907) | 18.18%├█████---------------------┤ | | partdb_test | tg73 | test_tb | test_tb_00006 | 6 | p7 | 1 | 16384 | 16384 | [4611686018427387907, 6917529027641081857) | 9.09%├███-----------------------┤ | | partdb_test | tg73 | test_tb | test_tb_00007 | 7 | p8 | 0 | 16384 | 16384 | [6917529027641081857, 9223372036854775807) | 0.00%├-------------------------┤ | +-------------+------------------+---------------+----------------+---------------+----------------+------------+-------------+--------------+----------------------------------------------+------------------------------------|說明部分參數說明:
PARTITION_NAME:分區名。
TABLE_ROWS:分區的資料行數。
DATA_LENGTH:分區的資料大小。
PERCENT:分區的資料比例。
在以上樣本中,p5分區的資料量明顯多於其他分區,存在資料扭曲。
解決方案
資料扭曲通常是由於資料拆分的方式不當造成的,常見原因如下:
使用了不恰當的拆分函數,例如UNI_HASH ,但拆分鍵不具備均勻分布的特徵;
拆分鍵的區分度過低,例如HASH分區,按照省份拆分,但省份實際較少,容易造成資料不均;
某些拆分鍵存在較多的資料,例如訂單表按照賣家ID進行拆分,部分的大賣家可能存在較多的資料。
分庫分表方式調整(DRDS模式資料庫)
對於拆分方式選擇不當導致的資料扭曲問題,通常需要調整拆分方式,包括以下兩方面:
調整拆分函數:分庫分表可以選擇HASH、UNI_HASH或STR_HASH等拆分函數;分區表可採用HASH、KEYS、RANGE或RANGE COLUMN等拆分方式;
調整拆分鍵:
選擇較為均勻,不存在熱點的拆分鍵;
選擇區分度較高的拆分鍵,避免HASH結果不均勻;
大部分查詢都通過拆分鍵做等值查詢,盡量避免查詢多個分區。
在選擇好資料拆分方式之後,可以通過如下方法對資料表進行調整:
重建表:重建一個新的表,將舊錶的資料匯入。
說明重建表需要暫停該表的業務流量。
線上調整分區:通過變更表類型及拆分規則線上修改分區方式;無需停止業務寫入,但此過程仍然需要重寫全表資料,開銷較大,需要在業務低峰期執行。
樣本:發現test_tb表存在資料扭曲,原因在於資料拆分鍵使用不當,使用如下語句進行調整:
ALTER TABLE test_tb dbpartition BY hash(`c1`);分區調整(AUTO模式資料庫)
在PolarDB-X中,實現了更靈活的基於分區表的資料分布,因此可以實現分區級的分裂及遷移,解決資料扭曲問題。分區調整能夠解決的情境主要是分區過大導致的資料扭曲,不適用於拆分函數選擇不當等問題。
以Range分區舉例:
建表時指定兩個分區,p0和p1,其範圍分別是 [-inf,1000), [1000,2000);
發現分區p0資料過多,存在資料扭曲,因此將分區p0進行分裂,使其分布到多個節點;
預設建立的分區會建立到資料量最少的節點上,如果不滿足需求,可另外進行分區遷移。
CREATE TABLE `table_range` (
`id` int(11) DEFAULT NULL
) PARTITION BY RANGE(`id`)
(PARTITION p0 VALUES LESS THAN (1000),
PARTITION p1 VALUES LESS THAN (2000)
) /* tablegroup = `tg110` */ ;
ALTER TABLEGROUP tg110 SPLIT PARTITION p0 INTO
(partition p0_1 values less than (500),
partition p0_2 values less than (1000) );SPLIT PARTITION操作的對象是TABLEGROUP而非單個表,通過SHOW FULL CREATE TABLE命令可以查看一個表所屬的tablegroup。