化繁为简 - 腾讯计费高一致TDXA的实践之路
導語:騰訊計費是孵化于支撐騰訊內(nèi)部業(yè)務千億級營收的互聯(lián)網(wǎng)計費平臺,在如此龐大的業(yè)務體量下,騰訊計費要支撐業(yè)務的快速增長,同時還要保證每筆交易不錯賬。采用最終一致性或離線補償?shù)姆桨竿鶗磔^多的處理風險或投訴。因此,我們提出了一種通用的基于應用層的長事務解決方案,將復雜的分布式一致性問題化繁為簡。
1 引言
英國計算機專家Hoare所言,軟件設計構建有兩種方法,一是使其盡可能簡單,從而一目了然確定其中不存在缺陷;另一種方法則是使其極為復雜,以至于看不出什么明顯的缺陷。然而,實現(xiàn)第一種方法要困難的多。
騰訊計費是孵化于支撐騰訊內(nèi)部業(yè)務千億級營收的互聯(lián)網(wǎng)計費平臺,目前匯集國內(nèi)外主流支付渠道,提供賬戶管理、精準營銷、安全風控、稽核分賬、計費分析等多維度服務。平臺承載了公司每天數(shù)億收入大盤,為上百個國家(地區(qū))、萬級業(yè)務代碼、 百萬級結算商戶提供服務,托管賬戶總量 300 多億,是一個全方位的一站式計費平臺。
在如此龐大的業(yè)務體量下,騰訊計費要支撐業(yè)務的快速增長,同時還要保證每筆交易不錯賬。然而在分布式場景下要滿足ACID,保證所有操作均執(zhí)行成功才提交結果,隨著分布式規(guī)模的擴大要達成一致性的時間周期越長。例如,Bitcoin的Scalability問題,為了滿足一致性一筆交易的平均確認時間需要10分鐘。因此,為了適應復雜的業(yè)務場景出現(xiàn)了Base理論,使用最終一致性來代替強一致性。在計費場景下,通常的一些最佳實踐是:
先長款后短款原則。由平臺方掌握主動權,即使出現(xiàn)異常情況下也可以通過補償?shù)姆绞奖WC一致性。例如,先支付后發(fā)貨,若發(fā)貨失敗通過重試機制達到最終一致。
臨界資源訪問盡量使用樂觀鎖。例如,在讀多寫少場景使用樂觀鎖實現(xiàn)互斥,在保證一致性的前提下提高并發(fā)處理能力。
遠程服務調(diào)用保證可重入。例如,已經(jīng)支付成功的訂單,如果再次提交也不允許重復支付。
非關鍵服務異步化。例如,對于支付旁路的操作,通常借助消息中間件進行解耦處理,并保證最終執(zhí)行完成。
服務全鏈路實時監(jiān)控。關鍵操作實時上報,監(jiān)控每一步的成功率和轉(zhuǎn)化率,做到異常的實時發(fā)現(xiàn)。
通過上述等機制,在異常情況下可做到讀修復,寫修復,異步修復等,以保證事前和事中的交易高一致。但考慮到問題的閉環(huán),我們也建立了一套完善的針對實時訂單,異步訂單,離線訂單的三級對賬機制,以做到事后的保證。
然而,對于日均過億的交易量,采用最終一致性或補償性的方案往往會帶來較多的處理風險及投訴,需要我們做到實時的一致性。同時,計費系統(tǒng)的邏輯多且復雜,目前涵蓋了近百個特點迥異的支付渠道,異常處理強依賴開發(fā)者的經(jīng)驗,需要由平臺統(tǒng)一處理異常問題來提高服務的容錯性。隨著業(yè)務系統(tǒng)的發(fā)展,系統(tǒng)會有不斷的新功能迭代,加強邏輯的可管理性從而降低開發(fā)門檻,也是我們需要考慮的。
化繁為簡是我們的目標,為了應對上述挑戰(zhàn),結合我們在計費領域的多年工程實踐經(jīng)驗,決定著力打造一套通用的基于應用層的分布式高一致解決方案TDXA (Titan Distribute eXtended Architecture),將復雜的分布式一致性問題交給引擎平臺處理使業(yè)務開發(fā)更加聚焦,主要實現(xiàn)以下目標。
分布式事務的原子性,保證交易實時高一致。
自動的異常處理,提高容錯性。
基于狀態(tài)機的流程管理,加強流程的可管理性。
TDXA通過在內(nèi)部業(yè)務的試點,基于TDXA實現(xiàn)的計費服務,上線后通過對賬統(tǒng)計發(fā)現(xiàn)異常的交易訂單數(shù)量明顯減少,整體服務質(zhì)量提高。同時,由于TDXA屏蔽了復雜的異常處理,業(yè)務開發(fā)效率也隨之提高,相同需求的開發(fā)工作周期較之前減少了近50%。
2 設計思路
2.1 分布式事務
在工程上,作為完整的計費服務,一致性不僅需要考慮數(shù)據(jù)層的數(shù)據(jù)一致性,同時也要考慮應用層的邏輯一致性。比如,轉(zhuǎn)賬這個行為,數(shù)據(jù)層可以保證每次數(shù)據(jù)的更新一致性,而應用層如果只減不加,用戶看到的賬戶數(shù)據(jù)也是不一致的。交易的一致性,簡單講就是收對錢,發(fā)對貨。看似簡單的描述,但在實現(xiàn)中卻面臨了很多約束,導致容易出現(xiàn)一致性問題。比如:
計費功能模塊多,業(yè)務邏輯復雜
支付交易鏈路長,一筆流程多達幾十次rpc
業(yè)務請求峰值高,分布式服務節(jié)點多
請求響應時間低,需要保證用戶體驗
系統(tǒng)部署環(huán)境差,網(wǎng)絡超時錯誤多
在OLTP場景下,用戶的一次購買請求通常會涉及多個后端服務的操作,如果其中某一個服務調(diào)用出現(xiàn)了二義性錯誤(網(wǎng)絡超時),此時應該返回失敗還是成功,之前調(diào)用過的服務是否需要回滾?倘若請求量小的情況下,可以借助人工來處理部分調(diào)用異常,但是當請求量大了以后,人工介入的成本就非常高。
計費服務的整體質(zhì)量要求至少達到四個9,同時不允許交易出現(xiàn)壞賬,對外提供事務一致性保障。從一致性的本質(zhì)來看,要么保證在一個業(yè)務邏輯中包含的服務都成功,要么都失敗。在計費場景下,后端服務可能涉及接口,數(shù)據(jù)庫,分布式緩存,消息隊列等,我們希望做到針對不同后端資源的長事務一致性。
我們的做法是,通過引入分布式事務管理器(Transaction Manager),將全局事務分解為多個子事務,并交給不同的資源管理器(Resource Manager)處理。同時,針對不同的資源類型抽象為不同的事務處理模型,幫助業(yè)務實現(xiàn)自動的事務提交或回滾。面對復雜的長事務流程,業(yè)務可以自定義組合不同的事務模型,并根據(jù)業(yè)務自身特點指定不同的異常處理策略(Error Strategies),讓業(yè)務開發(fā)像處理單機事務一樣來保證整體分布式事務的一致性。通過這樣的方法,可以有效地幫助業(yè)務開發(fā)減少異常處理,更專心地實現(xiàn)業(yè)務核心邏輯。下面分別對不同的事務模型說明如下。
TCC事務模型
分別代表Try,Confirm,Cancel。此事務模型類似兩階段提交協(xié)議(2PC),用于保證分布式事務的一致性。與2PC不同的是,對資源的加鎖是業(yè)務資源級別的隔離,減小了資源鎖的粒度,因此在事務沒有完成提交或回滾時,可以允許執(zhí)行其他事務。TM根據(jù)所有RM的反饋來決定提交或中止事務,如果所有的RM全部執(zhí)行成功則提交,但只要有一個失敗則回滾事務。此模式需要后端服務提供相應的資源操作接口,并保證冪等。調(diào)用關系如圖2.1所示。
DB事務模型
DB事務模型相比TCC事務模型,主要針對原生的數(shù)據(jù)庫操作,減少了對業(yè)務的侵入性,由引擎根據(jù)用戶提交的SQL實現(xiàn)跨數(shù)據(jù)庫實例的操作。因為基于傳統(tǒng)的關系型數(shù)據(jù)庫本地事務特性,DB事務模型不允許跨連接,而TCC事務模型沒有這個限制。針對這個問題,對于包含異步處理的事務流程,一種做法是,引擎會先把已經(jīng)執(zhí)行的SQL進行COMMIT,并根據(jù)后續(xù)接收到的異步通知結果來決定繼續(xù)正常執(zhí)行,還是執(zhí)行SQL反事務。另外可以結合數(shù)據(jù)庫的外部XA特性,通過兩階段提交的方式,對于Prepare成功的操作實現(xiàn)數(shù)據(jù)庫事務的跨連接,根據(jù)異步執(zhí)行的結果來決定是Commit還是Rollback。調(diào)用關系如圖2.2所示。
TRY_BEST事務模型
此事務模型表示盡最大努力執(zhí)行,主要用在邏輯上可以保證一定執(zhí)行成功的RPC調(diào)用。例如,用于一些通知類接口。在整個事務執(zhí)行流中,建議放在最后執(zhí)行,以保證整個事務的執(zhí)行成功。調(diào)用關系如圖2.3所示。
除了以上常見的幾種事務處理模型,我們也在不斷完善新的事務模型。其中每種事務模型都定義了相應的回調(diào)接口由業(yè)務實現(xiàn)(如下表所示),同時在使用上也有一些約束準則要求。
TRY_BEST和TCC兩種模式調(diào)用的RPC接口需要保證冪等。
三種模式支持混合使用,但是需要保證調(diào)用順序,最佳實踐是優(yōu)先執(zhí)行可以回滾的操作。例如,TRY_BEST和TCC兩種模式混合使用,應該先執(zhí)行TCC的子事務,然后再執(zhí)行TRY_BEST子事務,這樣如果執(zhí)行TCC子事務失敗可以回滾,如果TRY_BEST子事務執(zhí)行失敗可以通過補償最終保證成功。
最后,以用戶轉(zhuǎn)賬為例看如何實現(xiàn)混合類型的事務流程。首先在第一階段,調(diào)用訂單服務創(chuàng)建一筆訂單(try),然后提交轉(zhuǎn)賬sql1和sql2。第一階段執(zhí)行成功后并對用戶發(fā)起一條消息通知(do)。若第一階段執(zhí)行成功,在第二階段,框架會自動完成第一階段的確認過程(confirm和commit);若第一階段出現(xiàn)異常,框架也會自動完成回滾過程(cancel和rollback)。業(yè)務開發(fā)需要保證業(yè)務邏輯上的合理性,將可以回滾的操作先執(zhí)行,而由框架保證整體事務的一致性。
具體交互過程如下圖所示。
2.2 自動的異常處理
根據(jù)墨菲定律,事情如果有變壞的可能,不管這種可能性有多小,它總會發(fā)生。我們的系統(tǒng)服務也是,雖然大多數(shù)情況都是可以正常對外提供服務的,但是在少數(shù)情況下也會出現(xiàn)服務不可用,網(wǎng)絡超時等問題。因此,當服務調(diào)用出現(xiàn)異常時,如何保證事務可以繼續(xù)自動執(zhí)行完成?一種可行的方案是,將事務狀態(tài)保存和業(yè)務事務通過數(shù)據(jù)庫本地事務打包成一個原子事務,當異常出現(xiàn)時,可以通過一個消息重放服務將事務繼續(xù)執(zhí)行完成。
此方案的特點是,存在一定的業(yè)務侵入性,并且依賴單機DB的處理性能。為了解決這樣限制,提出了另一種基于消息中間件的方案,首先消息中間件本身需要保證數(shù)據(jù)的可靠性,同時,在客戶端通過引入一個生產(chǎn)代理Proxy,來解決在無法及時寫入的情況下,使用本地存儲充當一個緩沖區(qū)。通過結合本地隊列和遠程分布式隊列構成一個可用性更高,延遲更低的分布式消息隊列方案。
|因此,我們需要消息中間件滿足以下要求:
一致性:計費場景要求數(shù)據(jù)一條不能丟,這是最基本的訴求。
高可用:需具容災能力,在異常情況下能夠自動修復。
海量存儲:在移動互聯(lián)網(wǎng)時代,產(chǎn)生大量的交易數(shù)據(jù),需要具備海量堆積能力。
快速響應:在億級支付場景下,要求能提供平滑的響應時間,盡可能控制在10ms內(nèi)。
下面是我們基于Pulsar實現(xiàn)的一套高可靠的消息中間件解決方案,整體架構如下圖所示。
|關于消息中間件的實踐經(jīng)驗,我們團隊在Apache Pulsar Meetup北京站也做過一次分享,可以參考另外這篇文章Apache Pulsar 在騰訊計費場景下的應用。
2.3 狀態(tài)機的流程管理
由于計費流程的復雜性,通常一筆完整的支付請求需要至少幾十次的rpc調(diào)用。我們希望加強對流程的約束管理以減少可能的邏輯錯誤。我們的主要解決思路是,通過狀態(tài)圖定義服務調(diào)用流程,基于事件進行驅(qū)動來完成整個流程。其中,每個節(jié)點表示一個rpc操作,每個rpc操作分為三個獨立過程(Pre/RPC/Post);每條邊上可以定義多個算子,通過算子的返回值實現(xiàn)服務路由。
|同時,通過引入有限狀態(tài)機白名單的方式,保證業(yè)務狀態(tài)的流轉(zhuǎn)是合理的,可規(guī)避一些不必要的業(yè)務邏輯錯誤,減少異常錯誤的發(fā)生。例如,不會出現(xiàn)已經(jīng)支付的訂單被再次提交支付,即Double Pay的問題。
業(yè)務開發(fā)只需要關心業(yè)務節(jié)點注冊的Pre和Post回調(diào)接口的具體實現(xiàn),以及每個業(yè)務節(jié)點操作結果的返回算子,其余工作由框架完成整個流程的驅(qū)動,以及分布式事務的提交或回滾。同時,我們支持將當前的事務狀態(tài)通過Json描述出來,并轉(zhuǎn)換成流程圖,讓復雜的流程更加直觀。
3 系統(tǒng)架構
騰訊計費高一致TDXA,旨在幫助業(yè)務解決長事務的一致性問題,通過使用狀態(tài)機來控制事務的執(zhí)行路由,基于插件化注冊機制,提供多種子事務處理模型,實現(xiàn)對不同類型資源的分布式事務處理,完成自動化的提交或回滾。并提供規(guī)范的二進制對接協(xié)議,以及Java等語言二次開發(fā)能力。整體架構如下圖所示。
對每個模塊的功能簡要說明如下:
TM: 主要實現(xiàn)流程的注冊,分布式事務控制,以及異常策略處理。
CM: TM的配置管理,包括流程注冊配置信息,節(jié)點的屬性信息,事務類型。
Producer: MQ的生產(chǎn)代理,事務的持久化,及異常情況的事務重試。
Consumer: MQ的消費代理,執(zhí)行業(yè)務指定的事務補償策略。
RM: 實現(xiàn)外部接口協(xié)議轉(zhuǎn)換,及提供具體的業(yè)務資源接口,由TM調(diào)用。
TDMQ: 保證消息完整性和低延遲的分布式消息隊列。
TDXA的內(nèi)部工作流程,主要分為三個部分:
初始化流程
a) ? ?初始化時,TDXA將從配置服務獲取要加載的所有注冊so或xml流程配置,并依次加載。
b) ? ?加載后通過回調(diào)協(xié)議接口取得要注冊的流程名及對應的注冊函數(shù)。
c) ? ?通過調(diào)用注冊函數(shù)完成流程注冊。
正常執(zhí)行流程
a) ? ?通過解析業(yè)務請求中的事務流程名,創(chuàng)建需要執(zhí)行的流程,并將請求數(shù)據(jù)添加到事務的數(shù)據(jù)池中。
b) ? ?初始化事務狀態(tài)為begin,并通過轉(zhuǎn)移條件決定下一個要執(zhí)行的狀態(tài)。
c) ? ?執(zhí)行當前狀態(tài)的預處理和對應服務的執(zhí)行調(diào)用。
d) ? ?根據(jù)執(zhí)行結果判斷服務路由,若沒有找到滿足的路由,則根據(jù)業(yè)務指定的錯誤策略完成事務恢復。
e) ? ?重復執(zhí)行c~d,直至達到狀態(tài)end,或發(fā)生異常情況。
f) ? ?最后根據(jù)事務的執(zhí)行結果,設定事務返回信息。
事務恢復流程
a) 反序列化分布式消息隊列通知的事務信息。
b) 對未完成的事務斷點執(zhí)行。
為了方便業(yè)務快速接入,我們實現(xiàn)了一套前端自助化流程配置和功能驗證系統(tǒng)。希望能夠幫助業(yè)務在接入時做到盡量能所見即所得。前端每生成一個節(jié)點, 就會生成一份對應的后臺代碼, 支持分Tab頁代碼編解功能。為方便重度開發(fā)人員,頁面上也可以下載整體的含框架代碼,開發(fā)者可以選擇使用其他的IDE進行開發(fā)。
4 系統(tǒng)可靠性
4.1 邏輯可靠性
TDXA內(nèi)部提供了一些必要的邏輯異常檢測機制,幫助業(yè)務規(guī)避不必要的錯誤,包括但不限于:1,注冊接口參數(shù)檢測。2,DAG(Directed Acyclic Graph)合理性檢測,需要滿足,僅有一個連通分量,不能回環(huán)(但允許自環(huán)),每個節(jié)點都能達到終止節(jié)點保證閉環(huán)。3,運行時異常流程錯誤告警等。
TDXA對于業(yè)務異常的流程處理原則分為兩類。對于業(yè)務類錯誤,引擎會把控制權交給開發(fā)者,由開發(fā)者根據(jù)返回值信息決定事務流程如何流轉(zhuǎn);對于系統(tǒng)類錯誤,引擎會返回E_PROCESSING錯誤碼給前端,然后內(nèi)部借助消息中間件進行異步重試處理,其中重試次數(shù)和時間間隔均可由業(yè)務決定。
4.2 服務可靠性
在服務可靠性方面,TDXA中的事務管理器TM是與業(yè)務服務集成在一起的,并通過消息中間件實現(xiàn)事務的持久化。考慮可能出現(xiàn)的以下幾種組件異常情況,以及如何實現(xiàn)故障遷移。
情況一:在TM進行事務持久化前,TM出現(xiàn)故障。此時,可以通過原始的事務請求進行重放。
情況二:在TM完成事務持久化后,TM出現(xiàn)故障。此時,未完成的事務可以由集群中其他的TM繼續(xù)完成處理。
情況三:在TM進行事務持久化時,TDMQ出現(xiàn)故障。此時,通過本地的TDMQ Proxy異步重試。
情況四:在TM進行事務恢復時,TDMQ出現(xiàn)故障。此時,會選取新的可用的Broker進行消費,可能出現(xiàn)多次消費,需要業(yè)務保證冪等處理。
5 系統(tǒng)性能優(yōu)化
事務的核心是鎖,而事務和性能是兩個相悖的特性,因此在滿足分布式事務的前提下,也需要考慮對系統(tǒng)性能的調(diào)優(yōu),通常的優(yōu)化方法包括:1,盡可能減少鎖的覆蓋范圍。2,MVCC多版本并發(fā)控制協(xié)議,讀寫不沖突。3,選擇正確的鎖類型。悲觀鎖適合并發(fā)爭搶比較嚴重的場景,而樂觀鎖適合并發(fā)爭搶不太嚴重的場景。TDXA在性能調(diào)優(yōu)方面做了以下考慮。
優(yōu)化1:通常引入事務協(xié)調(diào)者會增加網(wǎng)絡調(diào)用次數(shù),因此會減少系統(tǒng)的并發(fā)處理能力。為了盡量減少不必要的網(wǎng)絡調(diào)用,我們將事務協(xié)調(diào)者與業(yè)務服務集成在一起實現(xiàn),提供了插件和配置的方式注冊業(yè)務事務。
優(yōu)化2:允許不相關的事務可以并行執(zhí)行,即pipeline操作。例如,b0~b3與c0~c3是兩個獨立的操作流程允許并行執(zhí)行。
優(yōu)化3:對于TCC事務模型,操作相同資源的不同事務是獨立的,不需要等待執(zhí)行。例如,事務T1在沒有confirm或cancel時,事務T2可以繼續(xù)執(zhí)行try而不需要等待事務T1完成。
優(yōu)化4:針對數(shù)據(jù)庫外部XA的性能優(yōu)化。在XA模型下,如果由于不穩(wěn)定的網(wǎng)絡通信導致事務沒有提交,會影響所有其他事務都在等待。我們針對數(shù)據(jù)庫的網(wǎng)絡模型增加了線程池的處理模式提高了I/O的處理能力,較原生的半同步方式提高了近5倍的性能。具體可以參考計費平臺部高一致性存儲層架構變遷之路---分布式MySQL數(shù)據(jù)庫(TDSQL)架構分析
6 下一步方向
騰訊計費作為承載每年千億級業(yè)務營收的計費平臺,保證支付交易高一致,每筆收支不錯賬是我們的核心能力。分布式服務相比單體服務,為我們提供了更好的擴展性和靈活性,但也帶來了復雜的一致性問題。騰訊計費高一致TDXA在此背景下應運而生,旨在實現(xiàn)長事務的一致性,支持多種資源的混合分布式事務,在異常出現(xiàn)時可以實現(xiàn)零人工介入處理。讓復雜的問題在這里變得簡單,化繁為簡是我們的目標。最后,考慮到極端情況,我們還會借助三級對賬,通過實時訂單,異步訂單,離線訂單的三級策略,來保障異常情況下的交易一致性。
騰訊計費通過多年的實踐探索,我們構建了一套完整的金融級計費解決方案,TDXA作為其中的一個重要組成部分,其他的還包括TDSQL,TSM,TBC等。目前,TDXA已經(jīng)在騰訊計費內(nèi)部業(yè)務廣泛應用,包括,大額的企業(yè)支付,騰訊云計費,騰訊計費開放版等,在實際場景中得到了驗證,減少了不必要的人力成本,業(yè)務服務質(zhì)量得到顯著提高。
最后,我們在解決了一些問題的同時,也遇到一些新的問題。
兼顧易用性和性能。目前,TCC的模式,將一次操作分成兩個獨立的子事務,不會阻塞其他的事務執(zhí)行,可以保證較高的并發(fā)處理能力。但是依賴業(yè)務的接口實現(xiàn)資源的互斥隔離,對業(yè)務的實現(xiàn)存在一定侵入性;而DB的模式,目前是通過數(shù)據(jù)庫的外部XA事務實現(xiàn)的,可以支持原生SQL的分布式事務,減少了對業(yè)務的侵入性,但是由于資源是通過數(shù)據(jù)庫行鎖進行隔離的,只有提交或回滾的事務釋放資源后才能繼續(xù)處理其他的事務。易用性和性能的平衡是我們繼續(xù)優(yōu)化方向。
支持更多的開發(fā)者。考慮到執(zhí)行效率,TDXA的核心是通過C++實現(xiàn)的,并提供了C的接口給業(yè)務使用。考慮到可以推廣到更多的開發(fā)者,我們基于C的接口使用JNI封裝了Java的接口,從而也可以支持Java技術棧的開發(fā)。除此之外,越來越多新的高級開發(fā)語言出現(xiàn),比如GoLang。如何將我們的能力普適給更多的開發(fā)者,也是我們后續(xù)需要考慮的。
事務隔離性要求。TDXA保證了長事務的一致性,但是卻犧牲了一定的隔離性。兩個事務并行執(zhí)行的時候,其中一個事務可能讀取了另一個未提交事務的數(shù)據(jù),即臟讀。對于大多數(shù)業(yè)務場景可能問題不大,可以通過事務補償來保證一致性,但是在某些業(yè)務場景下可能是不允許的。
支持更多的資源類型事務。TDXA的目標是希望業(yè)務可以像處理單機事務一樣處理分布式事務,目前已經(jīng)支持RPC,DB等常見的接口。不難發(fā)現(xiàn),對資源的加鎖都是后端接口提供的能力,為了支持更多的資源類型,在不依賴后端的前提下我們應該如何支持。
總結
以上是生活随笔為你收集整理的化繁为简 - 腾讯计费高一致TDXA的实践之路的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 腾讯抗黑灰产——自监督发现行话黑词识别一
- 下一篇: 基于Vue-SSR优化方案归纳总结