第三代DRDS分布式SQL引擎全新發布
DRDS (阿裏雲分布式關系型數據庫服務,https://www.aliyun.com/product/drds)於 4 月 30 號發布了 5.3 版本,這是一個年度大更新。主要帶來了以下特性:
性能提升。在大多數場景下(拆分鍵上的等值查詢、讀寫分離等),同規格的吞吐量(最大 QPS)可以提升到之前的300%。
原生分布式事務。無需額外付費或者開通,不依賴第三方組件,即可執行分布式事務。提供柔性事務與 XA 兩種實現。
Outline
明確的 SQL 邊界文檔。在 SQL 邊界內,進行了大量的隨機測試,確保功能的穩定可靠。
更強大的分布式查詢優化器。確保分布式 SQL 執行代價的最小化。
簡潔易讀的執行計劃。提供一種新的執行計劃顯示格式,可以非常方便的看出 SQL 的執行策略。
1. 性能
DRDS 5.3,使用了 Plan Cache、協程、FastSQL 等技術,大幅提升了吞吐量,在同規格下,最大 QPS 提升到了之前的 300%。
例如,對於之前的版本,8C16G 的 DRDS 最大可以提供 2W/s 的 QPS;對於 DRDS 5.3,8C16G 的 DRDS 最大可以提供 6W+/s 的 QPS。
測試場景:
1.實例規格為入門版 8C16G
2.測試工具為 sysbench
3.後端 RDS 不存在瓶頸
4.測試 SQL:單表拆分鍵上的等值查詢
SELECT * FROM t1 WHERE partition_key=?
5.持續加大並發,直至 DRDS CPU 接近 100%,並且 rt 在5ms左右
Plan Cache
DRDS 5.3 中,引入了 Plan Cache,大幅降低了 SQL 解析與查詢優化的代價。DRDS 5.3 中,針對不同類型的 SQL,分成了多級 Plan Cache,其中,性能最高的是命中了一級 Plan Cache 的 SQL。無論參數取值如何,一定可以被下推到單分片執行的 SQL 會命中一級 Plan Cache,常見的形式有以下幾種:
1.單表拆分鍵上的等值查詢,例如:
SELECT * FROM t1 WHERE partition_key=?
2.拆分鍵上的等值 JOIN 查詢,並且至少其中一個表帶了拆分鍵上的等值條件,例如:
SELECT * FROM t1 JOIN t2 ON t1.partition_key = t2.partition_key WHERE t1.partition_key=?
3.拆分鍵上的等值關聯子查詢,並且其中內表或者外表帶了拆分鍵上的等值條件,例如:
SELECT * FROM t1 WHERE EXSITS (SELECT 1 FROM t2 WHERE t1.partition_key = t2.partition_key) AND t1.partition_key=?
在應用中,更多的使用能夠命中一級 Plan Cache 的 SQL,能更高的提升系統容量。
協程
DRDS 5.3 使用了 AliJDK 的 Wisp 協程。在業務邏輯相同的情況下,使用協程模型與使用線程模型相比,系統容量提升了 30% 左右。
更快的 Parser:FastSQL
DRDS 5.3 中的 Parser 部分,換成了從 Druid(https://github.com/alibaba/druid)剝離出來的 FastSQL。相對於老的 Parser,FastSQL 在 SQL 解析方面,比 antlr、javacc 等自動生成的 Parser 快了數十倍至數百倍,相對 DRDS 老版本的 Parser 帶來了一倍的性能提升。FastSQL 近期會開源。
2. 原生分布式事務
DRDS 5.3 提供原生的分布式事務功能,有以下特點:
提供 柔性事務 與 XA 事務 兩種事務方案供用戶在不同的場景下進行選擇。
不依賴任何第三方組件,能力集成在 DRDS Server 中,專有雲無需額外資源進行部署。
無熱點情況下性能線性可擴,無單點瓶頸。
無需額外開通,公有雲上購買的實例即可立即使用,不產生額外費用。
DRDS 5.3 提供柔性事務和 XA 事務兩種方案,一般情況下,當 DRDS 後端的 MySQL 為 5.7 及以上版本時,推薦使用 XA 事務。
柔性事務
DRDS 5.3 提供的最終一致方式執行的分布式事務稱為柔性事務(Flexible Transactions)。
柔性事務放棄了隔離性,減小了事務中鎖的粒度,使得應用能夠更好的利用數據庫的並發性能,實現吞吐量的線性擴展。異步執行方式可以更好的適應分布式環境,在網絡抖動、節點故障的情況下能夠盡量保障服務的可用性(Availability)。
DRDS 5.3 中開啟柔性事務只需要一行代碼:
SET drds_transaction_policy = 'flexible'; SHOW VARIABLES LIKE 'drds_transaction_policy'; +-------------------------+----------+ | VARIABLE_NAME | VALUE | +-------------------------+----------+ | drds_transaction_policy | FLEXIBLE | +-------------------------+----------+ 1 row in set (0.07 sec)
除此之外,DRDS 柔性事務的使用方法和普通事務完全相同:應用首先用 SET autocommit = 0
和 SET drds_transaction_policy = 'flexible'
開啟柔性事務;然後在同一個會話中執行事務的 SQL 語句 —— 最後當應用發起 commit
或 rollback
後,DRDS 將保證這些 SQL 語句執行的原子性:全部成功,或者全部失敗。
XA 事務
DRDS 5.3 也支持 XA 事務,在柔性事務的基礎上提供了強一致能力。由於 MySQL XA 實現機制的限制,我們要求只有在 DRDS 後端是 MySQL 5.7 版本以上才啟用 XA 事務功能。
SET drds_transaction_policy = 'XA'; SHOW VARIABLES LIKE 'drds_transaction_policy'; +-------------------------+-------+ | VARIABLE_NAME | VALUE | +-------------------------+-------+ | drds_transaction_policy | XA | +-------------------------+-------+ 1 row in set (0.07 sec)
DRDS XA 事務使用兩階段提交協議(XA Protocol)保護子事務的提交與回滾,消除了柔性事務的異步回滾問題。由於 XA Protocol 在提交與回滾階段始終加鎖,避免了事務結束前的臟讀和覆蓋,但是對性能有較大影響。
3. Outline
DRDS 5.3 提供 Outline 機制,允許用戶在不修改程序與 SQL 的情況下,對特定類型的 SQL 的行為進行定制。簡單說,Outline 可以將一個類型的源 SQL 在執行時動態的替換成另一個目標 SQL,目標 SQL 中可以帶一些 HINT。
一些典型的應用場景:
使用
SLAVE HINT
將特定的SQL路由到只讀實例執行:
CREATE OUTLINE O1 ON SELECT * FROM T1 WHERE ID=? TO SELECT /*+TDDL:SLAVE()*/ * FROM T1 WHERE ID=?
使用 MySQL 原生的
FORCE INDEX
為特定的 SQL 指定需要選擇的索引:
CREATE OUTLINE O2 ON SELECT * FROM T1 WHERE ID=? TO SELECT * FROM T1 FORCE INDEX(index_xxx) WHERE ID=?
使用 DRDS 的 HINT 將特定的 SQL 路由到指定分片上執行:
CREATE OUTLINE O3 ON SELECT * FROM T1 WHERE ID=? TO SELECT /*+TDDL:node('0')*/ * FROM T1 WHERE ID=?
DRDS 中的 Outline,可以對參數化的 SQL 進行匹配,也可以對特定參數的 SQL 進行匹配。例如,對於 SQL:
SELECT * FROM T1 WHERE ID=?
當 ID 取 1 時,需求到只讀實例執行;當 ID 取其他值時,需求到主實例執行,則可以創建以下兩個 Outline:
CREATE OUTLINE O1 ON SELECT * FROM T1 WHERE ID=1 TO SELECT /*+TDDL:SLAVE()*/ * FROM T1 WHERE ID=1; CREATE OUTLINE O2 ON SELECT * FROM T1 WHERE ID=? TO SELECT /*+TDDL:MASTER()*/ * FROM T1 WHERE ID=?;
DRDS 會優先匹配帶具體參數的 Outline。
DRDS Outline 的詳細說明:https://help.aliyun.com/document_detail/71254.html
DRDS Hint 說明:https://help.aliyun.com/document_detail/71287.html
4. SQL 支持
SQL 兼容性方面,DRDS 5.3 最大的特點在於明確了 SQL 的邊界,也即能夠明確的說明哪些 SQL 支持、哪些 SQL 不支持。
DRDS 5.3 SQL 邊界文檔:https://help.aliyun.com/document_detail/71252.html。
一些重要的 SQL 類型:
子要查詢方面,支持 Correlated Subqueries(不要求關聯項一定是拆分鍵)、Derived Tables,暫不支持列子查詢。更多子查詢的支持範圍參考:https://help.aliyun.com/document_detail/71295.html。
支持分布式 JOIN(不要求一定要帶拆分鍵,不要求必須是拆分鍵上的 JOIN),暫不支持 STRAIGHT_JOIN 和 NATURAL JOIN。
支持大部分 MySQL 函數,主要暫不支持的為:全文檢索函數、XML 函數、空間分析函數與 JSON 函數。
UPDATE/DELETE 語句僅支持單表操作,不支持 UPDATE/DELETE 中包含 JOIN 以及子查詢。
聚合函數支持 COUNT/SUM/MAX/MIN/AVG,GROUP BY 不要求FULL_GROUP_BY(https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_only_full_group_by)。
支持邏輯 SQL 的
KILL
與SHOW PROCESSLIST
:https://help.aliyun.com/document_detail/71372.html。支持
CREATE USER
創建更多用戶,並使用GRANT
語句對用戶權限進行授權:https://help.aliyun.com/document_detail/71356.html。支持 PREPARE 協議、多語句與壓縮協議。
5. Optimizer 與執行計劃
DRDS 5.3 中,提供了非常豐富的分布式 SQL 優化策略,一些重要的例如:
對 Filter 的上拉、下壓、推導等優化,確保 DRDS 可以準確的識別出 SQL 中可以下推的部分,這個能很大程度上提升 JOIN、子查詢的性能,避免應該能下推卻無法下推帶來的性能損耗。
子查詢的 SEMI-JOIN 優化。DRDS中,子查詢會被改寫為 SEMI-JOIN 進行優化,從而使其能夠復用大量針對的 JOIN 的優化策略,提升性能和功能穩定性。
提供了一系列 Hint,允許調整執行計劃的任意一個節點,結合 Outline 機制,達到不更改 SQL 也能對 SQL 進行性能優化的目的。
針對不同的場景,對排序與 Limit 進行優化,確保能將排序與 Limit 盡可能多的下推到存儲節點上,保證傳輸的數據量最小。
DRDS 5.3 設計了全新的執行計劃顯示格式,相對老版本,具有以下特征:
收縮了分片的顯示,執行計劃不會因為涉及多個分片而臃腫龐大。
執行計劃中包含了完整的執行策略,不存在二義性。
執行計劃使用了標準的算子的語義,易於將標準的數據庫知識應用到 DRDS 的查詢優化中。
執行計劃中將同時包含分布式執行計劃以及存儲分片上的執行計劃(此特性 6 月份上線)。
提供 Optimizer Tracing 功能,能一步一步的展示出執行計劃的優化過程,方便進行 SQL 調優。
通過執行計劃可以清晰的判斷出:
SQL 需要在哪些分片上執行,是否跨分片
JOIN、子查詢、聚合、排序等操作是否能夠下推
JOIN、排序等所使用的算法是什麽
例如,針對以下 SQL 的執行計劃:
mysql> explain SELECT count(*), name FROM drds GROUP BY name ORDER BY count(*); +-----------------------------------------------------------------------------------------------------------------------------------------------------------+ | LOGICAL PLAN | +-----------------------------------------------------------------------------------------------------------------------------------------------------------+ | Project(count(*)="count(*)", name="name") | | MemSort(sort="count(*) ASC") | | Aggregate(group="name", count(*)="SUM(count(*))") | | MergeSort(sort="name ASC") | | LogicalView(tables="[00-03].drds", shardCount=4, sql="SELECT `name`, COUNT(*) AS `count(*)` FROM `drds` GROUP BY `name` ORDER BY `name`") | +-----------------------------------------------------------------------------------------------------------------------------------------------------------+ 5 rows in set (0.13 sec)
從此執行計劃中,我們可以獲得以下信息:
需要在 00-03 供 4 個分片上執行物理 SQL (
LogicalView
算子):SELECTname
, COUNT(*) AScount(*)
FROMdrds
GROUP BYname
ORDER BYname
。Group By 操作基於排序實現,需要對
name
進行排序。由於每個分片上已經完成了 Order By 操作,因此分布式層需要對各個分片的數據做歸並排序(MergeSort
算子)。每個分組內,對 COUNT(*) 的結果做 SUM 操作,以匯總每個分片 COUNT(*) 的結果(
Aggregate
算子)。使用內存排序,對 Aggregate 節點輸出的 count(*) 進行排序(
MemSort
算子)。最終結果集輸出的是 count(*) 與 name 兩列(
Project
算子)。
更多關於 DRDS 5.3 執行計劃的介紹,請關註後續的文章。
What's NEXT
6 月底,DRDS 將發布 5.3.2,將會提供以下特性:
帶計算能力的 DRDS 只讀實例。可以直接在RDS主實例或者只讀實例上,進行最高可提供 READ COMMITTED 級別的復雜 SQL(例如千萬級的表的 JOIN 等)執行能力,並且隨規格的提升,響應時間能進行近線性的擴展。
回收站,可對 DROP TABLE 操作進行閃回,方便在誤刪表的場景下快速對數據進行恢復。
基於事務的廣播表寫入。廣播表將不再依賴任何第三方組件,可自行創建使用。
跨實例、機房、單元依然能保證全局唯一的主鍵服務。
原文鏈接
第三代DRDS分布式SQL引擎全新發布