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

背景

每個系統都有它最核心的指標。比如在收單領域:進件系統第一重要的是保證入件準確,第二重要的是保證上單效率。清結算系統第一重要的是保證準確打款,第二重要的是保證及時打款。我們負責的系統是美團點評智能支付的核心鏈路,承擔著智能支付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”)進行了一系列埋點,方便進行服務異常報警。

  • 接入配置中心,能提供動態參數修改,比如強制熔斷、修改失敗率等。

總結思考

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

第一種境界

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

第二種境界

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

第三種境界

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

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

關於作者

招聘信息


分享到:


相關文章: