深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路

螞蟻金服分散式架構發表於2019-03-01

訊息佇列作為一個資料的集散中心,承載了越來越多的場景和資料,從最開始的 OLTP 到 OLAP,甚至再到物聯網、人工智慧、機器學習等場景,都有很大的想像空間。 在能力上,訊息佇列現在擁有了資料,擁有了算力,從承載資料走到理解資料。


螞蟻金服也在思考給訊息佇列加入演算法的能力,讓演算法走進訊息佇列,走向下一個階段 :洞察資料。把這些能力綜合起來,打造一個智慧的傳輸計算服務平臺。


還有一個好訊息,訊息佇列作為 SOFA (Scalable Open Financial Architecture )技術體系比較核心的組成部分,後續也會積極擁抱開源和社群。


本文將分享螞蟻金服訊息佇列發展過程中的故事,以及這個過程中的架構思考。

金融場景下的訊息系統的關鍵需求

在螞蟻金服,訊息佇列已經有十多年的歷史了。

在07、08年,我們採用了 ESB 這樣的方式來實現訊息的機制。

那個時候遇到的最頭疼的問題就是丟訊息,排查和修復起來非常的痛苦。

到了09年,和淘寶共建並上線了新的訊息佇列系統,丟訊息的問題得到了有效的改善。

螞蟻的業務具有金融級的屬性,從這個角度,有哪些比較關鍵的需求呢? 集中表現為以下四點:

深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路

  1. 極高的可靠性

    舉個例子,通過訊息去生成賬單,如果這個訊息不可靠,訊息丟了,這個時候會發生什麼樣的情況呢?客戶付了一筆錢,但是在賬單或者消費記錄裡卻看不到這筆記錄,這個時候就非常困惑了。 因此極高的可靠性指的是:訊息不能丟。

  2. 極強的一致性

    極強的一致性在金融業務當中是非常關鍵和重要的。 假如做一筆轉賬操作,因為種種原因,比如網路抖動,轉賬失敗了,如果一致性沒有做好,可能還會收到一條做了一筆轉賬的通知,這個時候系統的資料就不一致了。

  3. 持續的可用性

    持續的可用性,是指在希望用系統提供的服務能力的時候,這個服務一定是要可用的。 比如說雙十一的時候,線上生成一筆訂單需要支付,一定希望它能非常順利的支付完成。再一個,現線上下的場景非常火,到超市去買東西,結賬的時候也希望掃碼支付要非常順暢,這都是對可用性的要求。

  4. 極高的效能

    在螞蟻金服,每天有千億級的訊息在流轉,峰值的 TPS 也達到了千萬級。在這麼大的體量下,對效能的要求是非常高的。另外,從成本角度和使用者的體驗的角度,效能也是非常需要關注的地方。

對比經典的訊息系統,需要建立哪些機制來滿足以上的關鍵需求?

剛剛提到了金融場景下的四個核心的效能要求,那麼具體如何來滿足呢?

1. 如何做到極高的可靠性?

  • ACK 的機制。ACK 機制借鑑了 TCP 裡面的思路,通過傳送階段、持久化階段、投遞階段的 ACK 機制,保證了訊息在流轉路徑的各個環節上的可靠性。

  • 重試的機制,保證了訊息在投遞出去後,當消費端消費不成功的時候,還可以再次去消費。

  • 通過儲存層的持久化機制和可靠性機制來保證訊息資料本身的可靠性。

2. 採用兩階段事務訊息機制來保證極強的一致性

深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路

在第一階段裡面,把發訊息和業務自己的業務操作放到本地事務中,發出來的是帶有未提交狀態的訊息。 在第二階段,會根據本地事務執行的情況來決定一階段發出來的訊息是提交還是回滾,如果是回滾,把訊息刪掉就好了,如果是提交,會去更新這個訊息的狀態,從未提交改成已提交,接著去做投遞的動作。


如果第二階段中的事務狀態通知丟失了,訊息服務端會去主動向訊息傳送端做事務狀態回查,直到拿到明確的事務提交或者回滾的回查結果。

3. 持續的可用性的實現

在單機房的時代就在做提升可用性的事情。比如,在應用層面做了執行緒池的隔離,做了限流、熔斷等等。在架構層面去做各種水平伸縮能力,在故障隔離層面做單點的隔離,做叢集部署的隔離等等。這些手段提高了系統的可用性。

深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路

但是,由於受限於單機房部署的架構,當出現機房級別問題的時候,前面的手段就心有餘而力不足了。


當然,同城雙活架構可以通過業務流量在兩個機房之間做切換,也可以通過資料層面的切換等手段來有效的解決機房單點的問題。

深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路

但是,隨著業務增長,同城雙機房模式在容量和容災能力上也逐漸無法滿足業務發展需求了。

面對同城雙活也無法解決的情況,螞蟻金服沉澱出異地多活 LDC 架構:

深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路

在 LDC 架構下,對訊息佇列有怎樣的需求?

以轉賬為例,在異地多活的架構下,收款方跟轉賬人可能在一個邏輯 Zone 裡面,也可能不在一個邏輯 Zone 裡面,甚至他們可能都不在一個城市。這樣帶來一個最重要、最核心的需求就是訊息佇列需要具有非常靈活、非常強大的路由能力,可以做Zone內的路由

可以做同城跨Zone的路由,也可以做跨城跨 Zone 的路由。


在實現上,如果發現這個訊息是要做同城跨 Zone 的路由,在訊息服務端做了一個打通,通過服務端做轉發,當發現是跨城場景的時候,通過一個叫 MQ-router 的系統,對跨城的鏈路做了一個收斂,也對城市級部署的邏輯做了一個收口,所有需要經過跨城的邏輯全部收口到這樣一個系統當中,統一併靈活的支撐了異地多活的架構。

在 LDC 架構下面,訊息有趣的應用場景

有一類會員資訊資料,比較有特點:

  1. 訪問量非常大,把它放到快取裡面,降低對後端資料庫的壓力。

  2. 在一次業務請求當中,對這個資料可能有非常多次的訪問,所以對資料訪問的延遲非常敏感。如果這類資料需要跨城才能訪問到的話,跨城帶來的延時對業務而言是非常難以接受的。因此就要求這類資料從本城市就能夠訪問到,每個城市都需要有全量的這類資料。

  3. 這類資料對變更的時效性非常敏感。資料變更了,需要非常快的感知到。如果依靠資料庫層面的複製機制來做這件事情,會有大概秒級的延遲。

於是,我們設計了一個基於訊息的方案,來實現一個城市級的快取更新的機制。重點給 MQ-router 增加了廣播的能力。當這類資料發生變更的時候,以訊息的方式發出來,通過 MQ-router 以廣播的形式傳送到所有城市去,這樣就達到了多個城市的快取實時更新的效果。

深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路

4. 效能方面是持續在打磨的一件事情

訊息佇列基於 SEDA 模式來實現,引入了自研的高效能網路通訊層 SOFABolt來提高訊息通訊的效能。除此傳統的優化手段之外,也在調研和思考更先進的一些方式,比如硬體結合的方式,像DPDK、RDMA這樣的技術,去追求更極致的效能。

擁抱大資料時代,我們做了拉模式的訊息佇列

有很長一段時間,訊息佇列的研發工作都是圍繞著交易、支付、賬務等OLTP的業務展開。所以一直在打磨訊息佇列在OLTP場景下的功能。比如,通過資料庫儲存保證訊息可靠性,通過推的模式提高訊息的實時性等。 隨著業務場景的擴充套件,特別是大資料時代的到來,越來越多的OLAP場景出現了。這個時候前面的這些做法,特別是推的這種模式就遇到很多的困難。


到了這個階段,我們去做了基於Log語義的拉模式的訊息佇列。 拉模式訊息部署在物理機上,通過順序寫本地磁碟的方式去實現拉的語義。在一定時間內比較有效的支援了OLAP這種場景的需求。

走向計算儲存分離的架構,從掛盤模式到 API 模式

隨著拉模式的推廣,很多 OLTP 的場景也逐漸的採用了拉模式,提出了很多新的需求。比如 OLTP 對資料可靠性要求比較高,對本地檔案儲存可靠性的問題就非常關注。

由於是基於物理機部署,也遇到很多運維上的難點,比如成本、機型等等的一些問題。特別是物理機機型變化非常多,每次採購可能都不一樣,非常難以做標準化。在做容量規劃、縮容擴容這些事情時會遇到非常多的困難。


訊息是比較重 IO 輕計算的模型,在物理機上就會表現出非常明顯的資源配比不均衡的問題。往往是磁碟已經不夠用了,但 CPU 還很空閒。基於物理機的運維也很複雜,資源利用率不高、容量規劃不好做、擴容縮容困難等問題凸顯。


在做這件事情的時候,我們一開始採取了一種比較輕量的方式,稱之為掛盤的模式。 通過掛載的方式,將分散式檔案系統掛在訊息佇列應用上面。這個做法的好處是應用系統本身基本上不需要做什麼改造。訊息資料透明的寫到了分散式檔案系統上,依靠分散式檔案系統提供的三副本高可靠的能力來保障訊息資料的可靠性。


在這個階段還做了一件事情,就是把訊息應用的規格做了標準化。可以去制定類似8C、16G、1T 這樣的規格,有了標準規格,就可以比較準確的測算某個規格可以頂多少TPS的訊息量,這樣做容量規劃就很容易了。 這個模式上去之後,承載了一些業務,也接受了雙十一大促的考驗。


於是,我們開始了計算儲存分離的第二階段:API 模式,在效能上有了一個比較明顯的提升。 這個模式下,訊息服務端要做比較大的改動,趁著這個機會,也做了很多功能方面的增強。比如,加入了對全域性固定分割槽的支援,還有傳送冪等與強順序的能力等。 同時,把資料落地也做了一個改變,原先資料全部集中在一個commit log中,轉移到了佇列裡面去。這樣帶來的好處是可以在佇列級別做更細粒度的配置和管控。


這個架構整體而言是一個相對比較完善的計算儲存分離的架構了。在應用層面也做了很多可擴充套件的設計。


整體上,計算儲存分離的模式給訊息佇列打下比較好的基礎,可以跟螞蟻金服全站的運維模式做很好的適配。

讓計算走進訊息佇列,賦予訊息佇列計算能力

訊息佇列承載了越來越多的訊息資料,大量的資料流進來再流出去。都說在大資料時代,資料就是金錢,但是可以發現這麼多的資料流過訊息佇列,卻沒有淘到金。

通過思考這個問題,發現非常關鍵的一點是因為一直在用一種比較傳統的方式去看待訊息佇列,認為它是訊息的一個通道,訊息流進來再流出去,使命就結束了。在這樣的思路下,著力打造的是它的傳輸能力,它的儲存能力,它的可靠性等。但是卻忽略了在大資料時代非常重要的一個能力,就是計算的能力。

帶著這個問題去看業界的一些發展,得到了很多新的思路。特別是從Kafka身上得到了很多的啟發。

於是我們決定讓計算走進訊息佇列,以 streaming 方式為訊息佇列增加了一種計算能力,實現了一個輕量級的非中心式的計算框架,既可以嵌入客戶端,也可以嵌入訊息的服務端,做一些輕量級的計算,支援一些比較通用和輕量的運算元和多種計算視窗語義。

至此,訊息佇列有了傳輸、儲存和計算的能力

深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路


基於這些能力,把訊息佇列往更大的層面上去推進,構建一個資料傳輸計算平臺。不斷豐富訊息佇列能力,不斷擴充越來越豐富的資料來源,獲取越來越多樣的資料,並且把訊息投遞到更多的目的地去。在傳輸過程中對訊息進行計算,以獲得更多計算帶來的價值。


通過前面的回顧,我們可以看到,訊息佇列作為一個資料的集散中心,承載了越來越多的場景和資料。


在能力上,訊息佇列現在擁有了資料,擁有了算力,正在走過一條從承載資料到理解資料的道路。接下來,我們也在思考給訊息佇列加入演算法的能力,讓演算法走進訊息佇列。 這樣就可以向下一個階段 -- 洞察資料再邁出一步,就可以把這些能力綜合起來,去打造一個智慧的傳輸計算服務平臺。這樣訊息資料不僅是流轉過訊息佇列,還可以經過更多的計算和加工,更輕快更實時的發揮更大的價值。


本文根據蔣濤在 GIAC 2018 的主題分享《金融級訊息佇列的演進之路》整理編輯

歡迎大家共同打造 SOFAStack https://github.com/alipay

深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路


相關文章