深度 | 金融級消息隊列的演進 — 螞蟻金服的實踐之路
來自專欄 sofastack5 人贊了文章
消息隊列作為一個數據的集散中心,承載了越來越多的場景和數據,從最開始的 OLTP 到 OLAP,甚至再到物聯網、人工智慧、機器學習等場景,都有很大的想像空間。 在能力上,消息隊列現在擁有了數據,擁有了算力,從承載數據走到理解數據。
螞蟻金服也在思考給消息隊列加入演算法的能力,讓演算法走進消息隊列,走向下一個階段 :洞察數據。把這些能力綜合起來,打造一個智慧的傳輸計算服務平台。還有一個好消息,消息隊列作為 SOFA (Scalable Open Financial Architecture )技術體系比較核心的組成部分,後續也會積極擁抱開源和社區。
本文將分享螞蟻金服消息隊列發展過程中的故事,以及這個過程中的架構思考。
金融場景下的消息系統的關鍵需求
在螞蟻金服,消息隊列已經有十多年的歷史了。
在07、08年,我們採用了 ESB 這樣的方式來實現消息的機制。
那個時候遇到的最頭疼的問題就是丟消息,排查和修復起來非常的痛苦。
到了09年,和淘寶共建並上線了新的消息隊列系統,丟消息的問題得到了有效的改善。
螞蟻的業務具有金融級的屬性,從這個角度,有哪些比較關鍵的需求呢? 集中表現為以下四點:
- 極高的可靠性舉個例子,通過消息去生成賬單,如果這個消息不可靠,消息丟了,這個時候會發生什麼樣的情況呢?客戶付了一筆錢,但是在賬單或者消費記錄里卻看不到這筆記錄,這個時候就非常困惑了。 因此極高的可靠性指的是:消息不能丟。
- 極強的一致性極強的一致性在金融業務當中是非常關鍵和重要的。 假如做一筆轉賬操作,因為種種原因,比如網路抖動,轉賬失敗了,如果一致性沒有做好,可能還會收到一條做了一筆轉賬的通知,這個時候系統的數據就不一致了。
- 持續的可用性持續的可用性,是指在希望用系統提供的服務能力的時候,這個服務一定是要可用的。 比如說雙十一的時候,線上生成一筆訂單需要支付,一定希望它能非常順利的支付完成。再一個,現在線下的場景非常火,到超市去買東西,結賬的時候也希望掃碼支付要非常順暢,這都是對可用性的要求。
- 極高的性能在螞蟻金服,每天有千億級的消息在流轉,峰值的 TPS 也達到了千萬級。在這麼大的體量下,對性能的要求是非常高的。另外,從成本角度和用戶的體驗的角度,性能也是非常需要關注的地方。
對比經典的消息系統,需要建立哪些機制來滿足以上的關鍵需求?
剛剛提到了金融場景下的四個核心的性能要求,那麼具體如何來滿足呢?
1. 如何做到極高的可靠性?
- ACK 的機制。ACK 機制借鑒了 TCP 裡面的思路,通過發送階段、持久化階段、投遞階段的 ACK 機制,保證了消息在流轉路徑的各個環節上的可靠性。
- 重試的機制,保證了消息在投遞出去後,當消費端消費不成功的時候,還可以再次去消費。
- 通過存儲層的持久化機制和可靠性機制來保證消息數據本身的可靠性。
2. 採用兩階段事務消息機制來保證極強的一致性
在第一階段裡面,把發消息和業務自己的業務操作放到本地事務中,發出來的是帶有未提交狀態的消息。 在第二階段,會根據本地事務執行的情況來決定一階段發出來的消息是提交還是回滾,如果是回滾,把消息刪掉就好了,如果是提交,會去更新這個消息的狀態,從未提交改成已提交,接著去做投遞的動作。
如果第二階段中的事務狀態通知丟失了,消息服務端會去主動向消息發送端做事務狀態回查,直到拿到明確的事務提交或者回滾的回查結果。
3. 持續的可用性的實現
在單機房的時代就在做提升可用性的事情。比如,在應用層面做了線程池的隔離,做了限流、熔斷等等。在架構層面去做各種水平伸縮能力,在故障隔離層面做單點的隔離,做集群部署的隔離等等。這些手段提高了系統的可用性。
但是,由於受限於單機房部署的架構,當出現機房級別問題的時候,前面的手段就心有餘而力不足了。
當然,同城雙活架構可以通過業務流量在兩個機房之間做切換,也可以通過數據層面的切換等手段來有效的解決機房單點的問題。
但是,隨著業務增長,同城雙機房模式在容量和容災能力上也逐漸無法滿足業務發展需求了。
面對同城雙活也無法解決的情況,螞蟻金服沉澱出異地多活 LDC 架構:
在 LDC 架構下,對消息隊列有怎樣的需求?
以轉賬為例,在異地多活的架構下,收款方跟轉賬人可能在一個邏輯 Zone 裡面,也可能不在一個邏輯 Zone 裡面,甚至他們可能都不在一個城市。這樣帶來一個最重要、最核心的需求就是消息隊列需要具有非常靈活、非常強大的路由能力,可以做Zone內的路由,可以做同城跨Zone的路由,也可以做跨城跨 Zone 的路由。
在實現上,如果發現這個消息是要做同城跨 Zone 的路由,在消息服務端做了一個打通,通過服務端做轉發,當發現是跨城場景的時候,通過一個叫 MQ-router 的系統,對跨城的鏈路做了一個收斂,也對城市級部署的邏輯做了一個收口,所有需要經過跨城的邏輯全部收口到這樣一個系統當中,統一併靈活的支撐了異地多活的架構。
在 LDC 架構下面,消息有趣的應用場景
有一類會員信息數據,比較有特點:
- 訪問量非常大,把它放到緩存裡面,降低對後端資料庫的壓力。
- 在一次業務請求當中,對這個數據可能有非常多次的訪問,所以對數據訪問的延遲非常敏感。如果這類數據需要跨城才能訪問到的話,跨城帶來的延時對業務而言是非常難以接受的。因此就要求這類數據從本城市就能夠訪問到,每個城市都需要有全量的這類數據。
- 這類數據對變更的時效性非常敏感。數據變更了,需要非常快的感知到。如果依靠資料庫層面的複製機制來做這件事情,會有大概秒級的延遲。
於是,我們設計了一個基於消息的方案,來實現一個城市級的緩存更新的機制。重點給 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
https://wj.qq.com/s/2191714/5cc3 (二維碼自動識別)
推薦閱讀:
TAG:螞蟻金服浙江螞蟻小微金融服務集團有限公司 | 消息隊列 | 金融 |