本文檔介紹了PolarDB-X對超大事務的支援情況。
在分散式資料庫中,超大事務一般滿足以下條件中的一個或多個:
事務修改的資料涉及多個分區;
事務修改的資料量比較大;
事務執行的SQL語句比較多。
下面通過以下情境的測試,以這三個維度為切入點,介紹PolarDB-X對超大事務的支援情況。
測試所用執行個體規格
使用以下PolarDB-X執行個體進行測試:
PolarDB-X版本 | polarx-kernel_5.4.11-16301083_xcluster-20210805 |
節點規格 | 4核16GB |
節點個數 | 4 |
建立一個規格為4C16G的ECS串連執行個體進行測試,該ECS與執行個體位於同一網段下,由同一個虛擬交換器串連。
執行以下命令,建立如下表:
CREATE TABLE `tb` (
`id` bigint(20) NOT NULL,
`c` longblob/char(255)/char(1),
PRIMARY KEY (`id`)
);該表只有兩列,一列為id(bigint類型,主鍵),一列為c(在不同的情境下,分別為longblob/char(255)/char(1)類型)。針對分區數,主要考慮以下三種設定:
1分區,即單庫單表的情形,PolarDB-X對於單分區上的事務提交會最佳化為一階段提交;
8分區,以ID為拆分鍵將上述實驗表拆分成8個分區,每個儲存節點(DN)2 個分區;
16分區,以ID為拆分鍵將上述實驗表拆分成16個分區,每個儲存節點(DN)4 個分區;
情境一
在該情境下,執行SQL語句數量中等,每條語句攜帶資料量較大,事務寫入資料量較大。
執行SQL語句數量 | 2048 |
每條語句攜帶的資料量 | 約256 KB~8 MB |
資料修改總量 | 512 MB~16 GB |
資料修改條數 | 2048 |
測試過程
測試中,每一條SQL語句形如:
INSERT INTO `tb` VALUES (id, c)資料表中c列的資料類型為longblob,c的大小從256 KB到8 MB不等。即每個事務寫入2048條資料時,資料寫入總量從512 MB到16 GB不等。實際的寫入量比這個值稍大,因為bigint類型的ID也佔用一定的空間。
受計算節點(CN)的參數MAX_ALLOWED_PACKET的影響,每個查詢的請求包大小不應超過MAX_ALLOWED_PACKET個位元組。該值預設為16 MB,可通過參數設定修改,即每條SQL語句攜帶的資料量應小於參數MAX_ALLOWED_PACKET。如果您通過JDBC串連PolarDB-X資料庫,在發送的包大於MAX_ALLOWED_PACKET個位元組時,會收到CommunicationsException: Communications link failure的報錯。
在單表的情況下,當c的大小為1 MB,事務總寫入量略大於2 GB 時,執行該事務會報錯:
ERR-CODE: [TDDL-4614][ERR_EXECUTE_ON_MYSQL] Error occurs when execute on GROUP ...: Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again 受DN的參數MAX_BINLOG_CACHE_SIZE的限制,事務執行過程中,引起的binlog寫入量不應超過該值。對於分散式交易,每個分區對應一個分支事務,每個分支事務引起的binlog寫入量不應超過該值。以本測試情境為例,如果事務的每條語句都是INSERT語句,那麼每個分區的資料寫入量不應超過2 GB,事務總的資料寫入量不能超過:分區數量×2 GB,例如8分區的情況下,寫入總量在16 GB時也會觸發這個報錯。但是,上述討論並不意味著只要您的交易資料寫入量小於:分區數量×2 GB,就一定能執行成功。
DN的參數MAX_BINLOG_CACHE_SIZE無法修改,預設值為2147483648,即2 GB。實際上,由於DN受MySQL的限制,即使這個參數可以修改,MAX_BINLOG_CACHE_SIZE最大也不應超過4 GB。
測試結論
無論是否開啟事務,每條SQL語句攜帶的資料量受CN的參數MAX_ALLOWED_PACKET的限制,不能超過該值。
對於每個事務,在每個分區上執行的語句所引起的binlog寫入量受DN的參數MAX_BINLOG_CACHE_SIZE的影響,不能超過該值。例如,在INSERT情境下,binlog需要記錄插入的值,則事務對每個分區插入的資料量不應超過該值。
如果想支援更大的事務,比如在一個事務中插入更多的資料,請把資料表劃分到更多的分區上。
情境二
在該情境下,執行SQL語句數量較少,每條語句攜帶資料量較小,事務修改資料量較大。
執行SQL語句數量 | 1 |
每條語句攜帶的資料量 | 約256 KB |
資料修改總量 | 256 MB~8 GB |
資料修改條數 | 2^20~2^25 |
測試過程
在本測試中,資料表中c列的資料類型為char(255)。首先在資料表中匯入2^25條資料,資料的id為0, 1, 2, ..., 2^26-1,每條資料的c列值為 "aa...aa"(255個a的字串)。然後開啟事務,執行以下語句:
UPDATE `tb` SET c = “bb...bbb” (255個b的字串) where id < ?假設語句中的?為x,則會修改共x條資料,每條資料修改約256位元組的資料,資料總修改量為x * 2^8位元組。本測試中x取值從2^20到2^25不等,資料修改總量從512 MB到8 GB不等。
在單表的情況下,當x為2^22,事務修改的資料量約為1 GB時,執行該事務會和情境一樣報錯:
ERR-CODE: [TDDL-4614][ERR_EXECUTE_ON_MYSQL] Error occurs when execute on GROUP ...: Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again 對於UPDATE語句,binlog需要記錄修改前和修改後的值,即每條資料修改了256位元組的資料,binlog需記錄至少512位元組的資料。在單表情況下,事務修改量約為1 GB時,引起binlog寫入量超過了2 GB,就觸發了這個報錯。同理,對於分散式交易,如果事務執行的都是UPDATE語句,那麼每個分區上的資料修改量不應超過1 GB。例如,在本測試中,8分區的情境下,在一個事務中UPDATE的資料為8 GB時,也會觸發此報錯。
測試結論
與情境一類似,對於每個事務,在每個分區上所引起的binlog寫入量受DN的參數MAX_BINLOG_CACHE_SIZE的影響,不能超過該值。例如,在事務語句全為UPDATE的情境下,binlog需要記錄修改前的值和修改後的值,則事務在每個分區上修改的資料量不應超過該值的一半。在本情境下,單分區的事務修改的資料量最多不應超過1 GB,8分區的事務修改的資料量最多不應超過4 GB。
如果想支援更大的事務,比如在一個事務中修改更多的資料,請把資料表劃分到更多的分區上。
情境三
在該情境下,執行SQL語句數量較多,每條語句攜帶資料量較小,事務寫入資料量較小。
執行SQL語句數量 | 64,000~1,280,000 |
每條語句攜帶的資料量 | 若干位元組 |
資料修改總量 | 32 B |
資料修改條數 | 32 |
測試過程
在本測試中,資料表中c列的資料類型為char(1)。首先往資料表插入32條資料,資料的id為0~31,c為 "a"。然後開啟事務,反覆執行以下語句x次,即每個事務會執行64x條SQL:
UPDATE `tb` SET c = “b” where id = 0;
UPDATE `tb` SET c = “a” where id = 0;
UPDATE `tb` SET c = “b” where id = 1;
UPDATE `tb` SET c = “a” where id = 1;
...
UPDATE `tb` SET c = “b” where id = 31;
UPDATE `tb` SET c = “a” where id = 31;測試結論
本情境下,一個事務內執行128萬條SQL仍未達到瓶頸,不同分區設定下都能正常執行。因此,在多數情況下,首先觸發事務瓶頸的更可能是交易資料寫入、刪除、修改量。
情境四
在該情境下,測試分區數對事務的效能影響。
執行SQL語句數量 | 1 |
每條語句攜帶的資料量 | 若干位元組 |
資料修改總量 | 8 KB~8 MB |
資料修改條數 | 8 KB~8MB |
分區數 | 1~2048 |
測試過程
在本情境中,資料表中c列的資料類型為char(1)。首先往資料表插入x條資料,資料的id為0~x,c為 "a"。然後開啟事務,執行以下語句,即每個事務會修改x條記錄,修改x位元組資料:
UPDATE `tb` SET c = “b” where id < x每個事務執行一次該SQL,資料修改量為x位元組,資料修改條數為x。考慮x=8 KB和8 MB的情況。
測試結論
當資料修改量在8 KB時,由於事務修改的資料量較小,SQL語句的執行時間較短,事務的執行時間受事務提交時間的影響較大。在該情境下,事務執行時間隨分區數增多而增大。具體而言,在分區數為1~64時,當分區數增長為原來的n倍時,事務執行的時間比原來的n倍少得多。這是因為分區數較少時,雖然事務提交時間有一定的影響,但事務內DML語句的執行也佔用了較多的時間。而當分區數在1024~2048的情況下,事務執行時間則基本全部由事務提交時間構成。相比之下,DML語句的執行時間可以忽略不計。因此,此時事務執行時間與分區數近似成倍數增加的關係。
當資料修改量在8 MB時,事務執行時間則不再隨分區數增多而明顯增大,這時事務執行時間主要由DML的執行時間組成,事務提交時間可以忽略不計。
總而言之,根據前文的結論,當要支援更大的事務時,建議將表劃分到更多的分區上。但分區數越多,事務提交的時間也會越長。在多分區小事務的情境下,事務執行時間甚至主要由事務提交時間組成。因此,您可以參考本文在不同情境下的結論,根據具體的業務情境,選擇合適的分區數,以擷取更好的事務效能。
情境五
該情境下測試CN的計算壓力較大的時候,對事務的影響。
測試過程
在本情境中,將資料表tb劃分到16個分區進行實驗。資料表中,c列的資料類型為char(255)。首先往資料表插入2^26條資料,資料的id為0~2^26-1,c和id相同。接著,建立另一個表tb2,表結構和資料與tb完全一致。此時,每個表的大小約為16 GB。最後,建立一個暫存資料表tmp,其表結構和tb也相同,然後開啟事務,執行下面的語句:
INSERT INTO tmp
SELECT tb.id, tb.c
FROM tb, tb2
WHERE tb.c = tb2.c AND tb.id > x AND tb2.id > x通過explain語句可以看到這條SQL的執行計畫:
LogicalInsert(table="tmp", columns=RecordType(BIGINT id, CHAR c))
Project(id="id", c="c")
HashJoin(condition="c = c", type="inner")
Gather(concurrent=true)
LogicalView(tables="[000000-000015].tb_VjuI", shardCount=16, sql="SELECT `id`, `c` FROM `tb` AS `tb` WHERE (`id` > ?)")
Gather(concurrent=true)
LogicalView(tables="[000000-000015].tb2_IfrZ", shardCount=16, sql="SELECT `c` FROM `tb2` AS `tb2` WHERE (`id` > ?)")即把兩個表id>x的部分拉到CN做hash join。通過x來控制拉取的資料量,即CN需要計算的資料量。當x=0,會拉取所有的資料到CN做hash join,此時CN總共需要處理約32 GB的資料,並且單個CN節點的記憶體只有16 GB。
測試結論
單個事務導致CN端的計算壓力較大、計算量較多時(比如事務內有複雜的join且這些join無法下推,必須要在CN處理的情境),PolarDB-X對大事務的支援仍然穩定。具體表現為,在需要處理的資料量呈倍數增長時,事務執行不報錯,且執行時間也呈線性增長。
總結
無論是否開啟事務,每條SQL語句自身攜帶的資料量受CN的參數MAX_ALLOWED_PACKET的限制,不能超過該值。
對於每個事務,在每個分區上執行的語句所引起的binlog寫入量受DN的參數MAX_BINLOG_CACHE_SIZE的影響,不能超過該值。
該參數值預設為2 GB,受MySQL的限制,最大值為4 GB,以INSERT為例,如果一個事務中全是INSERT語句,由於binlog需要記錄插入的值,資料寫入總量最大不超過:分區數×4 GB。
如果想支援更大的事務,比如在一個事務中插入/刪除/修改更多的資料,請把資料表劃分到更多的分區上。
在事務修改資料量較少的情況下,分區數對事務執行時間的影響較大;在事務修改資料量較多的情況下,分區數對事務執行時間的影響則不大。因此,您可以參考本文在不同情境下的結論,根據具體的業務情境,選擇合適的分區數,以擷取更好的事務效能。
單個事務導致CN端的計算壓力較大、計算量較多時,PolarDB-X對大事務的支援仍然穩定。