高可用:美團點評智慧支付核心交易系統的可用性實踐

美團技術團隊發表於2018-04-19

背景

每個系統都有它最核心的指標。比如在收單領域:進件系統第一重要的是保證入件準確,第二重要的是保證上單效率。清結算系統第一重要的是保證準確打款,第二重要的是保證及時打款。我們負責的系統是美團點評智慧支付的核心鏈路,承擔著智慧支付100%的流量,內部習慣稱為核心交易。因為涉及美團點評所有線下交易商家、使用者之間的資金流轉,對於核心交易來說:第一重要的是穩定性,第二重要的還是穩定性。

高可用:美團點評智慧支付核心交易系統的可用性實踐

問題引發

作為一個平臺部門,我們的理想是第一階段快速支援業務;第二階段把控好一個方向;第三階段觀察好市場的方向,自己去引領一個大方向。

理想很豐滿,現實是自從2017年初的每日幾十萬訂單,到年底時,單日訂單已經突破700萬,系統面臨著巨大的挑戰。支付通道在增多;鏈路在加長;系統複雜性也相應增加。從最初的POS機到後來的二維碼產品,小白盒、小黑盒、秒付……產品的多元化,系統的定位也在時刻的發生著變化。而系統對於變化的應對速度像是一個在和兔子賽跑的烏龜。

由於業務的快速增長,就算系統沒有任何發版升級,也會突然出現一些事故。事故出現的頻率越來越高,系統自身的升級,也經常是困難重重。基礎設施升級、上下游升級,經常會發生“蝴蝶效應”,毫無徵兆的受到影響。

問題分析

核心交易的穩定性問題根本上是怎麼實現高可用的問題。

可用性指標

業界高可用的標準是按照系統當機時間來衡量的:

高可用:美團點評智慧支付核心交易系統的可用性實踐

因為業界的標準是後驗的指標,考慮到對於平時工作的指導意義,我們通常採用服務治理平臺OCTO來統計可用性。計算方法是:

高可用:美團點評智慧支付核心交易系統的可用性實踐

可用性分解

業界系統可靠性還有兩個比較常用的關鍵指標:

  • 平均無故障時間(Mean Time Between Failures,簡稱MTBF):即系統平均能夠正常執行多長時間,才發生一次故障
  • 平均修復時間(Mean Time To Repair,簡稱MTTR):即系統由故障狀態轉為工作狀態時修理時間的平均值

對於核心交易來說,可用性最好是無故障。在有故障的時候,判定影響的因素除了時間外,還有範圍。將核心交易的可用性問題分解則為:

高可用:美團點評智慧支付核心交易系統的可用性實踐

問題解決

1. 發生頻率要低之別人死我們不死

1.1 消除依賴、弱化依賴和控制依賴

用STAR法則舉一個場景:

情境(situation)

我們要設計一個系統A,完成:使用我們美團點評的POS機,通過系統A連線銀行進行付款,我們會有一些滿減,使用積分等優惠活動。

任務(task)

分析一下對於系統A的顯性需求和隱性需求: 1>需要接收上游傳過來的引數,引數裡包含商家資訊、使用者資訊、裝置資訊、優惠資訊。 2>生成單號,將交易的訂單資訊落庫。 3>敏感資訊要加密。 4>要呼叫下游銀行的介面。 5>要支援退款。 6>要把訂單資訊同步給積分核銷等部門。 7>要能給商家一個檢視訂單的介面。 8>要能給商家進行收款的結算。 基於以上需求,分析一下怎樣才能讓裡面的最核心鏈路“使用POS機付款”穩定。

行動(action)

分析一下:需求1到4是付款必需鏈路,可以做在一個子系統裡,姑且稱之為收款子系統。5到8各自獨立,每個都可以作為一個子系統來做,具體情況和開發人員數量、維護成本等有關係。 值得注意的是需求5-8和收款子系統的依賴關係並沒有功能上的依賴,只有資料上的依賴。即他們都要依賴生成的訂單資料。 收款子系統是整個系統的核心,對穩定性要求非常高。其他子系統出了問題,收款子系統不能受到影響。 基於上面分析,我們需要做一個收款子系統和其他子系統之間的一個解耦,統一管理給其他系統的資料。這裡稱為“訂閱轉發子系統”,只要保證這個系統不影響收款子系統的穩定即可。 粗略架構圖如下:

高可用:美團點評智慧支付核心交易系統的可用性實踐

結果(result)

從上圖可以看到,收款子系統和退款子系統、結運算元系統、資訊同步子系統、檢視訂單子系統之間沒有直接依賴關係。這個架構達到了消除依賴的效果。收款子系統不需要依賴資料訂閱轉發子系統,資料訂閱轉發子系統需要依賴收款子系統的資料。我們控制依賴,資料訂閱轉發子系統從收款子系統拉取資料,而不需要收款子系統給資料訂閱轉發子系統推送資料。這樣,資料訂閱轉發子系統掛了,收款子系統不受影響。 再說資料訂閱轉發子系統拉取資料的方式。比如資料存在MySQL資料庫中,通過同步Binlog來拉取資料。如果採用訊息佇列來進行資料傳輸,對訊息佇列的中介軟體就有依賴關係了。如果我們設計一個災備方案:訊息佇列掛了,直接RPC呼叫傳輸資料。對於這個訊息佇列,就達到了弱化依賴的效果。

1.2 事務中不包含外部呼叫

外部呼叫包括對外部系統的呼叫和基礎元件的呼叫。外部呼叫具有返回時間不確定性的特徵,如果包含在了事務裡必然會造成大事務。資料庫大事務會造成其它對資料庫連線的請求獲取不到,從而導致和這個資料庫相關的所有服務處於等待狀態,造成連線池被打滿,多個服務直接宕掉。如果這個沒做好,危險指數五顆星。下面的圖顯示出外部呼叫時間的不可控:

高可用:美團點評智慧支付核心交易系統的可用性實踐

解決方法:

  • 排查各個系統的程式碼,檢查在事務中是否存在RPC呼叫、HTTP呼叫、訊息佇列操作、快取、迴圈查詢等耗時的操作,這個操作應該移到事務之外,理想的情況是事務內只處理資料庫操作。
  • 對大事務新增監控報警。大事務發生時,會收到郵件和簡訊提醒。針對資料庫事務,一般分為1s以上、500ms以上、100ms以上三種級別的事務報警。
  • 建議不要用XML配置事務,而採用註解的方式。原因是XML配置事務,第一可讀性不強,第二切面通常配置的比較氾濫,容易造成事務過大,第三對於巢狀情況的規則不好處理。

高可用:美團點評智慧支付核心交易系統的可用性實踐

1.3 設定合理的超時和重試

對外部系統和快取、訊息佇列等基礎元件的依賴。假設這些被依賴方突然發生了問題,我們系統的響應時間是:內部耗時+依賴方超時時間*重試次數。如果超時時間設定過長、重試過多,系統長時間不返回,可能會導致連線池被打滿,系統死掉;如果超時時間設定過短,499錯誤會增多,系統的可用性會降低。 舉個例子:

高可用:美團點評智慧支付核心交易系統的可用性實踐

服務A依賴於兩個服務的資料完成此次操作。平時沒有問題,假如服務B在你不知道的情況下,響應時間變長,甚至停止服務,而你的客戶端超時時間設定過長,則你完成此次請求的響應時間就會變長,此時如果發生意外,後果會很嚴重。

Java的Servlet容器,無論是Tomcat還是Jetty都是多執行緒模型,都用Worker執行緒來處理請求。這個可配置有上限,當你的請求打滿Worker執行緒的最大值之後,剩餘請求會被放到等待佇列。等待佇列也有上限,一旦等待佇列都滿了,那這臺Web Server就會拒絕服務,對應到Nginx上返回就是502。如果你的服務是QPS較高的服務,那基本上這種場景下,你的服務也會跟著被拖垮。如果你的上游也沒有合理的設定超時時間,那故障會繼續向上擴散。這種故障逐級放大的過程,就是服務雪崩效應。

解決方法:

  • 首先要調研被依賴服務自己呼叫下游的超時時間是多少。呼叫方的超時時間要大於被依賴方呼叫下游的時間。
  • 統計這個介面99%的響應時間是多少,設定的超時時間在這個基礎上加50%。如果介面依賴第三方,而第三方的波動比較大,也可以按照95%的響應時間。
  • 重試次數如果系統服務重要性高,則按照預設,一般是重試三次。否則,可以不重試。

1.4 解決慢查詢

慢查詢會降低應用的響應效能和併發效能。在業務量增加的情況下造成資料庫所在的伺服器CPU利用率急劇攀升,嚴重的會導致資料庫不響應,只能重啟解決。關於慢查詢,可以參考我們技術部落格之前的文章《MySQL索引原理及慢查詢優化》。

高可用:美團點評智慧支付核心交易系統的可用性實踐

解決方法:

  • 將查詢分成實時查詢、近實時查詢和離線查詢。實時查詢可穿透資料庫,其它的不走資料庫,可以用Elasticsearch來實現一個查詢中心,處理近實時查詢和離線查詢。
  • 讀寫分離。寫走主庫,讀走從庫。
  • 索引優化。索引過多會影響資料庫寫效能。索引不夠查詢會慢。DBA建議一個資料表的索引數不超過4個。
  • 不允許出現大表。MySQL資料庫的一張資料表當資料量達到千萬級,效率開始急劇下降。

1.5 熔斷

在依賴的服務不可用時,服務呼叫方應該通過一些技術手段,向上提供有損服務,保證業務柔性可用。而系統沒有熔斷,如果由於程式碼邏輯問題上線引起故障、網路問題、呼叫超時、業務促銷呼叫量激增、服務容量不足等原因,服務呼叫鏈路上有一個下游服務出現故障,就可能導致接入層其它的業務不可用。下圖是對無熔斷影響的魚骨圖分析:

高可用:美團點評智慧支付核心交易系統的可用性實踐

解決方法:

  • 自動熔斷:可以使用Netflix的Hystrix或者美團點評自己研發的Rhino來做快速失敗。
  • 手動熔斷:確認下游支付通道抖動或不可用,可以手動關閉通道。

2. 發生頻率要低之自己不作死

自己不作死要做到兩點:第一自己不作,第二自己不死。

2.1 不作

關於不作,我總結了以下7點: 1>不當小白鼠:只用成熟的技術,不因技術本身的問題影響系統的穩定。 2>職責單一化:不因職責耦合而削弱或抑制它完成最重要職責的能力。 3>流程規範化:降低人為因素帶來的影響。 4>過程自動化:讓系統更高效、更安全的運營。 5>容量有冗餘:為了應對競對系統不可用使用者轉而訪問我們的系統、大促來臨等情況,和出於容災考慮,至少要保證系統2倍以上的冗餘。 6>持續的重構:持續重構是確保程式碼長期沒人動,一動就出問題的有效手段。 7>漏洞及時補:美團點評有安全漏洞運維機制,提醒督促各個部門修復安全漏洞。

高可用:美團點評智慧支付核心交易系統的可用性實踐

2.2 不死

關於不死,地球上有五大不死神獸:能在惡劣環境下停止新陳代謝的“水熊蟲”;可以返老還童的“燈塔水母”;在硬殼裡休養生息的“蛤蜊”;水、陸、寄生樣樣都成的“渦蟲”;有隱生能力的“輪蟲”。它們的共通特徵用在系統設計領域上就是自身容錯能力強。這裡“容錯”的概念是:使系統具有容忍故障的能力,即在產生故障的情況下,仍有能力將指定的過程繼續完成。容錯即是Fault Tolerance,確切地說是容故障(Fault),而並非容錯誤(Error)。

高可用:美團點評智慧支付核心交易系統的可用性實踐

3. 發生頻率要低之不被別人搞死

3.1 限流

在開放式的網路環境下,對外系統往往會收到很多有意無意的惡意攻擊,如DDoS攻擊、使用者失敗重刷。雖然我們的隊友各個是精英,但還是要做好保障,不被上游的疏忽影響,畢竟,誰也無法保證其他同學哪天會寫一個如果下游返回不符合預期就無限次重試的程式碼。這些內部和外部的巨量呼叫,如果不加以保護,往往會擴散到後臺服務,最終可能引起後臺基礎服務當機。下圖是對無限流影響的問題樹分析:

高可用:美團點評智慧支付核心交易系統的可用性實踐

解決方法:

  • 通過對服務端的業務效能壓測,可以分析出一個相對合理的最大QPS。
  • 流量控制中用的比較多的三個演算法是令牌桶、漏桶、計數器。可以使用Guava的RateLimiter來實現。其中SmoothBurstry是基於令牌桶演算法的,SmoothWarmingUp是基於漏桶演算法的。
  • 核心交易這邊採用美團服務治理平臺OCTO做thrift截流。可支援介面粒度配額、支援單機/叢集配額、支援指定消費者配額、支援測試模式工作、及時的報警通知。其中測試模式是隻報警並不真正節流。關閉測試模式則超過限流閾值系統做異常丟擲處理。限流策略可以隨時關閉。
  • 可以使用Netflix的Hystrix或者美團點評自己研發的Rhino來做特殊的針對性限流。

4. 故障範圍要小之隔離

隔離是指將系統或資源分割開,在系統發生故障時能限定傳播範圍和影響範圍。

伺服器物理隔離原則

① 內外有別:內部系統與對外開放平臺區分對待。 ② 內部隔離:從上游到下游按通道從物理伺服器上進行隔離,低流量服務合併。 ③ 外部隔離:按渠道隔離,渠道之間互不影響。

執行緒池資源隔離

  • Hystrix通過命令模式,將每個型別的業務請求封裝成對應的命令請求。每個命令請求對應一個執行緒池,建立好的執行緒池是被放入到ConcurrentHashMap中。 注意:儘管執行緒池提供了執行緒隔離,客戶端底層程式碼也必須要有超時設定,不能無限制的阻塞以致於執行緒池一直飽和。

訊號量資源隔離

  • 開發者可以使用Hystrix限制系統對某一個依賴的最高併發數,這個基本上就是一個限流策略。每次呼叫依賴時都會檢查一下是否到達訊號量的限制值,如達到,則拒絕。

5. 故障恢復要快之快速發現

發現分為事前發現、事中發現和事後發現。事前發現的主要手段是壓測和故障演練;事中發現的主要手段是監控報警;事後發現的主要手段是資料分析。

5.1 全鏈路線上壓測

你的系統是否適合全鏈路線上壓測呢?一般來說,全鏈路壓測適用於以下場景:

① 針對鏈路長、環節多、服務依賴錯綜複雜的系統,全鏈路線上壓測可以更快更準確的定位問題。 ② 有完備的監控報警,出現問題可以隨時終止操作。 ③ 有明顯的業務峰值和低谷。低谷期就算出現問題對使用者影響也比較小。

全鏈路線上壓測的目的主要有:

① 瞭解整個系統的處理能力 ② 排查效能瓶頸 ③ 驗證限流、降級、熔斷、報警等機制是否符合預期並分析資料反過來調整這些閾值等資訊 ④ 釋出的版本在業務高峰的時候是否符合預期 ⑤ 驗證系統的依賴是否符合預期

全鏈路壓測的簡單實現:

① 採集線上日誌資料來做流量回放,為了和實際資料進行流量隔離,需要對部分欄位進行偏移處理。 ② 資料著色處理。可以用中介軟體來獲取和傳遞流量標籤。 ③ 可以用影子資料表來隔離流量,但是需要注意磁碟空間,建議如果磁碟剩餘空間不足70%採用其他的方式隔離流量。 ④ 外部呼叫可能需要Mock。實現上可以採用一個Mock服務隨機產生和線上外部呼叫返回時間分佈的時延。 壓測工具上,核心交易這邊使用美團點評開發的pTest。

高可用:美團點評智慧支付核心交易系統的可用性實踐

6. 故障恢復要快之快速定位

定位需要靠譜的資料。所謂靠譜就是和要發現的問題緊密相關的,無關的資料會造成視覺盲點,影響定位。所以對於日誌,要制定一個簡明日誌規範。另外系統監控、業務監控、元件監控、實時分析診斷工具也是定位的有效抓手。

高可用:美團點評智慧支付核心交易系統的可用性實踐

7. 故障恢復要快之快速解決

要解決,提前是發現和定位。解決的速度還取決於是自動化的、半自動化的還是手工的。核心交易有意向搭建一個高可用系統。我們的口號是:“不重複造輪子,用好輪子。”這是一個整合平臺,職責是:“聚焦核心交易高可用,更好、更快、更高效。”

美團點評內部可以使用的用於發現、定位、處理的系統和平臺非常多,但是如果一個個開啟連結或者登陸系統,勢必影響解決速度。所以我們要做整合,讓問題一站式解決。希望達到的效果舉例如下:

高可用:美團點評智慧支付核心交易系統的可用性實踐

工具介紹

Hystrix

Hystrix實現了斷路器模式來對故障進行監控,當斷路器發現呼叫介面發生了長時間等待,就使用快速失敗策略,向上返回一個錯誤響應,這樣達到防止阻塞的目的。這裡重點介紹一下Hystrix的執行緒池資源隔離和訊號量資源隔離。

執行緒池資源隔離

高可用:美團點評智慧支付核心交易系統的可用性實踐

優點

  • 使用執行緒可以完全隔離第三方程式碼,請求執行緒可以快速放回。
  • 當一個失敗的依賴再次變成可用時,執行緒池將清理,並立即恢復可用,而不是一個長時間的恢復。
  • 可以完全模擬非同步呼叫,方便非同步程式設計。

缺點

  • 執行緒池的主要缺點是它增加了CPU,因為每個命令的執行涉及到排隊(預設使用SynchronousQueue避免排隊),排程和上下文切換。
  • 對使用ThreadLocal等依賴執行緒狀態的程式碼增加複雜性,需要手動傳遞和清理執行緒狀態(Netflix公司內部認為執行緒隔離開銷足夠小,不會造成重大的成本或效能的影響)。

訊號量資源隔離

開發者可以使用Hystrix限制系統對某一個依賴的最高併發數。這個基本上就是一個限流 策略,每次呼叫依賴時都會檢查一下是否到達訊號量的限制值,如達到,則拒絕。

高可用:美團點評智慧支付核心交易系統的可用性實踐

優點

  • 不新起執行緒執行命令,減少上下文切換。

缺點

  • 無法配置斷路,每次都一定會去嘗試獲取訊號量。

比較一下執行緒池資源隔離和訊號量資源隔離

  • 執行緒隔離是和主執行緒無關的其他執行緒來執行的;而訊號量隔離是和主執行緒在同一個執行緒上做的操作。
  • 訊號量隔離也可以用於限制併發訪問,防止阻塞擴散,與執行緒隔離的最大不同在於執行依賴程式碼的執行緒依然是請求執行緒。
  • 執行緒池隔離適用於第三方應用或者介面、併發量大的隔離;訊號量隔離適用於內部應用或者中介軟體;併發需求不是很大的場景。

高可用:美團點評智慧支付核心交易系統的可用性實踐

Rhino

Rhino是美團點評基礎架構團隊研發並維護的一個穩定性保障元件,提供故障模擬、降級演練、服務熔斷、服務限流等功能。和Hystrix對比:

  • 內部通過CAT(美團點評開源的監控系統,參見之前的部落格“深度剖析開源分散式監控CAT”)進行了一系列埋點,方便進行服務異常報警。
  • 接入配置中心,能提供動態引數修改,比如強制熔斷、修改失敗率等。

總結思考

王國維 在《人間詞話》裡談到了治學經驗,他說:古今之成大事業、大學問者,必經> 過三種之境界:

第一種境界

昨夜西風凋碧樹。獨上高樓,望盡天涯路。

第二種境界

衣帶漸寬終不悔,為伊消得人憔悴。

第三種境界

眾裡尋他千百度,驀然回首,那人卻在,燈火闌珊處。

核心交易的高可用目前正在經歷第一種:高瞻遠矚認清前人所走的路,以總結和學習前人的經驗做為起點。

下一階段,既然認定了目標,我們會嘔心瀝血孜孜以求,持續發展高可用。最終,當我們做了很多的事情,回過頭來看,相信會對高可用有更清晰和深入的認識。敬請期待我們下一次的分享。

關於作者

曉靜,20歲時畢業於東北大學計算機系。在畢業後的第一家公司由於出眾的語言天賦,在1年的時間裡從零開始學日語並以超高分通過了國際日語一級考試,擔當兩年日語翻譯的工作。後就職於人人網,轉型做網際網路開發。中國科學院心理學研究生。有近百個技術發明專利,創業公司合夥人。有日本東京,美國矽谷技術支援經驗。目前任美團點評技術專家,負責核心交易。(歡迎關注靜兒的個人技術公眾號:程式設計一生)

招賢納士

美團金融核心交易招聘實習生,要求:19年即將畢業的研究生,Java方向,有技術追求。高速發展的業務需要高速發展的團隊,作為核心部門,我們急需相信技術改變世界的你!有意者請關注我的個人技術公眾號並留言。

如果對我們團隊感興趣,可以關注我們的專欄

高可用:美團點評智慧支付核心交易系統的可用性實踐

相關文章