接著上篇繼續講,接下來主要介紹交易總體設計的技術要點設計,對於電商中臺來說,交易系統是核心中的核心,一開始就需要圍繞高效能,高可用,和高擴充套件三個方面來重點設計。本篇主要介紹高效能設計。
對於高效能的定義,通常可以理解為系統/服務介面響應時間低(rt)且併發量(qps,tps)高. 提高效能的主要策略有:選擇合理的分散式事務處理機制,資料庫的分庫分表,讀寫分離,非同步化,快取,複雜查詢走搜尋。
選擇合理的分散式事務處理機制
交易業務要求訂單,庫存,優惠券,紅包,支付等資料要強一致,如何保證這些資料之間的一致性是必須要解決的問題,也就是分散式事務的場景。
業界分散式事務的選擇方案非常多,每種方案之間的差異性非常大。讓我們大概看一下幾種常見的方案和其特點:
2PC: 二階段提交協議,最大幾個問題是事務管理器(協調者)和資源管理器(參與者)之間的呼叫是同步阻塞的,如果在一次事務中只有部分資源管理器進行了commit操作,其他超時或者沒有成功,會導致資料的不一致性。
3PC: 三階段提交協議,是對2PC的改進版本,引入了超時機制,極大的降低了同步阻塞,preCommit 階段協調者和參與者出現通訊問題後,仍然會出現資料不一致性的問題。
TCC: 其實也是2PC的改進版本,TCC將事務參與者從資料庫本身提升到了業務服務粒度,讓每個業務單元實現try,confirm,cancel三個介面,協調者在呼叫完try介面會,根據返回介面呼叫confirm還是cancel,其最大問題是業務侵入性非常強,2PC的單點問題,超時問題也都存在,並且需要業務單元考慮各種異常情況,沒法利用資料庫的事務機制。
阿里GTS: GTS通過將事務協調器叢集化的方式解決了單點問題,但這也帶來了另外一個問題,原來本地化的協調者變成了要網路通訊的雲協調者,如果不是在同一個資料中心,要跨越公網或者專有網路,效能損耗比較大,此外GTS支援的服務框架也是有限的,如果不支援也需要實現類似於TCC的業務介面。
SAGA: 在微服務架構下,關注的人越來越多了,但saga早在1987年就提出來了,基本核心思想Saga是一系列本地交易,每筆事務都會更新單個服務中的資料。第一個事務由系統外部請求啟動,然後每個後續步驟由前一個事件完成而觸發。其最常見的兩種實現方式如下:
1.事件/編排:沒有中央協調器,每個服務產生並聆聽其他服務的事件,然後採取對應的處理動作。通常會使用訊息中介軟體來實現。
2. 命令/協調:中央協調器負責集中處理事件的決策和業務邏輯排序。因引入協調器模式比較重,目前沒有好的框架。
對saga要詳細理解可以自行google,baidu.
事務訊息最終一致性方案:利用訊息中介軟體的事務性訊息/兩階段訊息來實現,流程如下:
這種模式對業務的侵入性比較比較低,利用訊息中介軟體,效能上有非常好的保障,此外即使遇上網路超時等問題,通過訊息中介軟體的超時回撥功能最終都能保證資料的最終一致性。因此我們也選擇了這種方案作為我們的實現。以簡化的確認下單時序來說明這個場景:
通過時序圖可以看出,通過事務訊息的2階段提交和訊息的超時回撥極大的提升了各個業務資料的一致性,已經是非常不錯的方案了,但仔細分析這個圖,你還是能發現在極端場景還是有缺點,看個明顯的問題:
庫存回滾失敗:在本地事務回滾的情況下,呼叫庫存系統回滾庫存超時或者發生異常,庫存資料將會出現不一致情況。對於這種情況需要通過離線或者實時的庫存對賬系統專門來解決。針對這個問題我們後面可以寫一篇文章單獨討論了。
資料庫的分庫分表
對交易來說,資料量最大的是交易主表和子表,這兩個表的資料也是隨著業務量增長最快的,需要在一開始,就要考慮分庫分表策略,不然等到業務發展到一定量再來調整,會非常痛苦,你會從前到後修改一邊,還要遷移資料。對於這塊我們總結了一些比較實用的策略,如下:
用商家id取模作為分庫分表的欄位:這種策略比較適合平臺性的公司,如果淘寶,天貓和拼多多。 但對於一些非常大的商家來說,還是會發生資料傾斜的情況。
用買家id取模作為分庫分表的欄位:這種策略比較試用於自營性的平臺,像京東這樣的。
自定義分庫分表的規則: 大部分的情況,通過上面兩種策略就能滿足,如果你的業務非常特殊,比如要按照年月日之類的分,那就需要自己寫分庫分表規則函式來做了。
分庫分表的總原則是:利用交易常用的欄位作為分庫分表的欄位,可以聯合使用,庫和表的數量支援後期修改,對應用程式碼透明,後期資料庫擴容,上層應用無感知,至多調整一下分庫分表規則。目前我們利用的是開源mycat來做這塊,這塊好用的還真不多,很多需要自己做額外工作。
讀寫分離
讀寫分離不太適用交易的場景,特別是在併發量非常高的時候,資料庫的主備之間通常存在幾ms的延遲,搞不好會造成很大的故障。但是為了節省成本,把備庫的資源利用起來,對於一些規則確定不會造成問題的查詢可以走備庫,如:對交易完成資料的查詢,對實時性要求不是非常高的運營管理系統和客服系統的查詢,都可以切到備庫查詢。 讀寫分離也是需要提前考慮,在一開始就需要制定出規範,明確使用不當的後果。現在很多分庫分表的框架都可以做到對應用透明的主備讀寫比例的調整,但業務程式碼必須要評估哪些場景是不能走備庫讀的。
非同步化
對於核心系統非同步化的重要性和帶來的好處不用多說,但什麼樣的場景需要非同步化了,就交易來說,像扣減庫存,優惠券使用,支付這些核心鏈路是不能非同步化處理,能非同步化處理的是在交易時刻就不需要立刻確定的場景。如建立物流訂單,佣金計算等。非同步化的總體概覽圖如下:
總體原則就是將不在交易核心鏈路的部分,儘量非同步化去處理。
非同步化常用的手段就是訊息機制和分散式定時任務。
訊息機制:首先需要標準化交易事件訊息,如交易建立,確認,支付完成等。來看一個樣例程式碼片段:
不要每個交易事件,都單獨搞個事件物件。發訊息到訊息中介軟體時,每個event為一個messageType,同一個topic,為了下游系統只訂閱自己感興趣的少部分資料,可以利用訊息中介軟體的tags之類的機制進行訂閱訊息過濾。
分散式定時任務:支付超時關閉交易,失敗重試,異常交易掃描這些場景適應定時任務,延遲在分鐘級別,這塊選用開源界比較優秀的框架就可以了,沒有必要自己搞。
非同步化帶來的好處主要是:
將交易系統和非核心繫統解耦,從而確保交易的穩定性和響應時間。
幫下游系統削峰,很多下游系統的容量是非常小的,在大促這樣的高峰期間,是沒有足夠的資源跟上交易的處理速度的,訊息中介軟體叢集,會起到非常好的緩衝削峰作用,下游系統按照自己的速度消費就可以了,如果下游消費太慢會出現訊息堆積,但訊息叢集本身就是耐堆積的。
快取
快取適用於讀多寫少的場景,但交易是以寫為主的場景。所以交易資料本身是沒有快取需求的,但通過前面的核心鏈路分析可以看出,像交易依賴的商品,優惠,使用者這些資訊如果直接走DB, 會非常慢,而這些資料是讀多寫少,是非常適合使用快取,提高效能的。交易團隊需要通過依賴呼叫關係分析,推動依賴的上下游系統的技術團隊,使用快取技術,做效能提升和可靠性保障。常用的快取策略有前置快取和後置快取。
前置快取:
優點:即使業務系統掛了,也沒有啥影響,
缺點:後期升級比較麻煩,必須通知依賴client的應用都強制升級。
後者快取:
優缺點正好和前置快取相反。
在實際使用中,如果為了保障非常高的可用性,可以兩者結合使用,通過動態配置開關做切換,在client層的程式碼做一下路由切換處理。
複雜查詢走搜尋
?成熟的電商系統,都有自己單獨統一的搜尋平臺,選擇什麼樣的索引構建方式,完全取決於業務上要多實時的查到最新的資料,目前主流的搜尋框架,支援dump DB 和 api 直接推送兩種模式。在我們自己的實踐中,認為交易資料的實時性非常高,需要在1秒之內完成資料索引的構建。
在接受交易事情訊息上可以利用批量投遞的策略,提升處理能力,。
這塊需要特別注意的是訊息叢集到交易索引的構建系統訊息在處理上會出現亂序的問題,必須要通過業務欄位做先後次序處理,忽略過期的資料,一般都用業務發生時間bizTime.
在推送索引這塊可以利用聚合快取策略, 減少推送索引的頻率,很多搜尋框架都對每次推送資料的大小,每秒的推送次數都有限制,需要利用聚合快取策略來適應選擇的搜尋框架,總的來說就是不能推的太快,也不來太慢,還要保證所有的索引構建完成在業務允許的範圍(1s)之內。
搜尋框架的選型非常多:開源的有ElasticSearch,lucene,nutch,solr,solandra. 商業產品的每個雲平臺都有搜尋產品提供,預設推薦 elasticsearch, 如果對搜尋結果準確性和智慧化程度比較高,使用商業化雲產品。
這次就先寫這麼多,後面接著講高可用和高擴充套件的技術要點設計。
對這塊有興趣的歡迎交流技術方案和產品玩法。
更多文章歡迎訪問 http://www.apexyun.com/
聯絡郵箱:public@space-explore.com,微信:yinhexi-one
(未經同意,請勿轉載)