摘要: 在阿里巴巴,「柔性事務」 已是重構分佈式事務的標準方法,覆蓋了商品、交易、支付各個大規模應用場景,而且經受了雙十一的考驗。數據庫
DRDS 是阿里雲提供的一款分佈式數據庫產品,它的原型是在阿里內部使用了 10 年的數據庫中間件 TDDL。DRDS 在 TDDL 提供的數據切分和 SQL 路由能力上,強化了分佈式查詢,事務和水平擴容能力。後端
在分佈式數據庫中,數據存儲在多個節點將引入兩個問題:性能優化
因爲全局二級索引的同步依賴於事務,所以 分佈式事務 是全部分佈式數據庫產品都須要解決的核心問題。這一問題的關鍵是 —— 數據存儲在多個節點,本來在單機數據庫上不難實現的 ACID 特性在分佈式環境下變得困難:網絡
所以,在高可用與高性能的應用場景,分佈式事務的最佳實踐是放棄 ACID,遵循 BASE 的原則重構業務流程:架構
區別於 ACID 特性的數據庫事務,這種放棄強一致性,採起最終一致方式執行的分佈式事務稱爲 「柔性事務」 (Flexible Transactions)。併發
在阿里巴巴,「柔性事務」 已是重構分佈式事務的標準方法,覆蓋了商品、交易、支付各個大規模應用場景,而且經受了雙十一的考驗。阿里內部最經常使用的柔性事務方案有 「消息事務」 與 「TCC 事務」 (Try / Confirm / Cancel),它們的基本原理是一致的:框架
柔性事務放棄了隔離性,減少了事務中鎖的粒度,使得應用可以更好的利用數據庫的併發性能,實現吞吐量的線性擴展。異步執行方式能夠更好的適應分佈式環境,在網絡抖動、節點故障的狀況下可以儘可能保障服務的可用性 (Availability)。所以在高可用、高性能的應用場景,柔性事務是最佳的選擇。異步
可是,現有的柔性事務方案都存在一個共同問題:它們是以框架或者中間件的形式存在,應用須要付出較大的改形成本:分佈式
有沒有更好的方案?工具
有。 DRDS / TDDL 在新發布的 5.3 版本開始提供兩種類型的分佈式事務:柔性事務 (FLEXIBLE) 和兩階段提交事務 (XA)。前者將柔性事務與傳統數據庫的使用方式相結合,提供了簡單易用、低成本、高性能的 DRDS 分佈式事務功能。
開啓 DRDS 柔性事務只須要一行代碼:
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 語句執行的原子性:所有成功,或者所有失敗。
相比 TCC 或消息事務, DRDS 不須要業務編寫補償操做的回滾語句。DRDS 會根據事務中 SQL 語句的語義,自動生成相應的補償操做。
例如,若是業務執行的是一條典型的資金扣減操做:
UPDATE account SET balance = balance - 100 WHERE id = 123 AND balance >= 100
DRDS 會自動生成對應的反向退款操做:
UPDATE account SET balance = balance + 100 WHERE id = 123
因爲柔性事務的弱隔離性,應用一般會擔憂:提交失敗後,異步回滾操做是否會覆蓋併發的更新,形成 "Lost update" 或者 「回滾覆蓋」 問題。在傳統 TCC 或消息事務中,回滾覆蓋問題須要由應用引入狀態、版本號、或樂觀鎖機制來規避。
DRDS 柔性事務則使用了一些創新的方式來解決這個問題:
前面的例子已經展現了增量回滾是如何工做的:若是 DRDS 識別應用的 UPDATE 語句中包含 「增量操做」,例如:balance = balance - 100
,則會在回滾語句中使用 balance = balance + 100
進行補償。因爲增量操做的結果與順序無關,即便事務異步回滾,也不會覆蓋任何一筆業務的更新結果。
增量操做的定義是 UPDATE 語句符合如下格式:
UPDATE {表名} SET {列名} = {列名} [+/-] {常量表達式}, ... WHERE {條件表達式}
增量回滾對帳戶、積分、庫存這樣的字段很是有用,而這些字段又一般是須要用分佈式事務嚴格保證一致性的關鍵數據。建議在應用中儘可能對這一類字段採用 「增量操做」 的方式更新,既節省了一次數據庫操做(SELECT),又避免了柔性事務 「回滾覆蓋」 的風險。
另外一個防止回滾覆蓋的方法是 「關鍵事務」。
在 DRDS 柔性事務中,應用第一次在事務內執行的 DML(INSERT/UPDATE/DELETE) 操做被放入 「關鍵事務」 內執行。在柔性事務的執行流程中,「關鍵事務」 老是第一個開始,最後一個提交。
DRDS 「關鍵事務」 的執行機制與單機事務相同,不須要記錄補償操做,也不須要異步回滾。所以,把具備回滾覆蓋風險的 UPDATE 操做放入 「關鍵事務」 內執行,是一個防止異步回滾的好方法。
「關鍵事務」 的設計,可讓一個 DRDS 單機事務天然切換到分佈式事務。在傳統的柔性事務方案中,應用須要識別業務場景是否是存在分佈式事務,而後再根據場景採用不一樣的事務方式。而 DRDS 的特殊設計,能夠作到開啓柔性事務,執行單機事務也不產生任何額外代價。
第三個方法是使用 「後置執行」 優化事務流程,防止產生回滾。
DRDS 提供了一個全新的 SQL 執行方式:「後置執行」。用來優化分佈式事務中不影響業務最終執行結果的跨庫操做。在分佈式事務理論中,這一類優化被稱爲 「Best Efforts 1PC」:
使用 「後置執行」 很是簡單,只須要在 SQL 語句的頭部加入 /*TDDL:DEFER*/
:
/*TDDL:DEFER*/ UPDATE account SET balance = balance + 100 WHERE id = 123
DRDS 保證後置執行的 SQL 僅僅執行一次,不須要應用關心出錯重試或者冪等的問題。
「後置執行」 將事務中同步執行的操做轉移至異步執行,減小了分佈式事務中持有鎖的時間,提升了事務執行的並行度,所以能夠很好的提高分佈式事務的性能。同時,因爲 「後置執行」 用異步重試替代了回滾,它也是解決回滾覆蓋問題的另外一個方法。
新版本 DRDS 也支持 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 在提交與回滾階段始終加鎖,避免了事務結束前的髒讀和覆蓋,可是對性能有較大影響。
「後置執行」 功能在 DRDS XA 事務中一樣可用,可以減小 XA 協議中的鎖,提供了進一步的性能優化空間。
因爲 MySQL XA 實現機制的限制,咱們建議只有在 DRDS 後端是 MySQL 5.7 版本以上才啓用 XA 事務功能。
從穩定性和成本出發,DRDS 柔性事務不引入額外的服務和存儲節點,而是利用後端的 RDS/MySQL 存儲事務日誌和回滾信息。在實現上,DRDS 儘量的減小了事務過程當中的數據傳輸和日誌開銷,以提高分佈式事務的性能。
使用 sysbench 壓測工具代表,在標準的 8core 16G 規格 DRDS 實例上,開啓柔性事務能夠達到 9000 QPS 的優異性能。相比不開啓事務的 sysbench 壓測結果,性能差別不到 10%.
從分佈式事務的原理出發,最終一致的 「柔性事務」 與提供 ACID 保證的 「強一致事務」 是兩個獨立的發展方向。前者實現了更高的水平擴展能力與性能,代價是應用須要付出額外的開發成本;後者提供了強一致的數據訪問和更好的開發體驗,但存在性能上的限制。
做爲行業領先的雲原生分佈式數據庫,DRDS 同時在兩個方向拓展產品的邊界:
DRDS 新版本提供的分佈式事務功能(柔性事務以及 XA 事務)正是第一階段的成果。
將來的 DRDS 產品將爲企業用戶提供更多、更好的選擇:做爲基礎的 「強一致事務」、標準的全局事務隔離級別、基於分佈式 MVCC 的一致性讀、以及爲高性能應用提供的 「柔性事務」 。在默認配置下,DRDS 將提供標準的事務 ACID 保證,以及高於業界水準的性能;而應用只須要付出較少的代價,就能夠適配 DRDS 的特性,得到更高的水平擴展能力和性能保證。