? ? ? ? 之前寫了一篇關于消息隊列的文章:《消息隊列介紹與對比》,本文主要介紹消息隊列在實際工作中的使用情況(截止到2023年,因為我2023年離職了,后續的情況不了解了,哈哈)。
? ? ? ? 市面上的多種消息隊列都有在小米應用,如Notify,Kafka,EMQ,RabbitMQ,Talos,RocketMQ,MQTT等。我們并不是為了使用而使用,主要還是因為部門較多,不同部門業務不同,側重點不同,因此在選型消息隊列時就會根據實際業務需求去選擇更合適的消息隊列。
? ? ? ? 在目前的單位主要還是RabbitMQ,RocketMQ,Kafka主要用于日志采集種。
????????本文主要介紹RabbitMQ,RocketMQ,Talos和Notify等等。
1、RabbitMQ的使用
????????在小米使用RabbitMQ最典型的場景是郵件中繼。在2021年,公司要求所有部門自動發送郵件時不可直連郵件服務器,而是要經過一個郵件中繼Guard,其最主要的目的是讓Guard做一層治理,比如流量管控,避免大量請求都打到郵件服務器。如果某個大神程序沒寫好,每個訂單都發送一封郵件,一天幾十萬訂單,可是要了命了。Guard內部就使用了RabbitMQ,業務系統將郵件發送到Guard,Guard會將所有郵件作為消息頭遞到消息隊列,隨后RabbitMQ負責將消息push到消費者(郵件服務器),在上面有過介紹,push消息的速率完全由broker掌握,我們可以控制Push消息的頻率,類似大家經常說的限流,消峰,這就可以有效避免郵件服務器被瞬時大量郵件打垮。
????????不過也正是因為這點,經常會出現消息堆積,郵件發不出去的場景。如果某個業務發送了大量郵件,可能會影響到其他業務的郵件發送。如何做到相互不影響,也是Guard團隊重點要解決的問題。
? ? ? ? ? 在我目前的單位,RabbitMQ是主推,這主要是領導層決定的,當然我不知道選擇RabbitMQ的具體原因,我來得比較晚。我只知道去年發生過的一個問題是,因為Server重啟,導致隊列丟失,數據丟失,出現事故。這個我在消息隊列介紹中已經說過了,RabbitMQ的隊列默認是auto-delete的,重啟后隊列數據就會全部丟失。而且RabbitMQ的限制還包括它是閱后即焚,非常不方便追溯;最重要的是沒法實現消費分組,這在實際業務中是非常不方便的。所以,我認為RabbitMQ并不是業務中較好的選擇。
2、RocketMQ
????????RocketMQ也是這幾年才在小米大規模使用的,尤其是電商系統,像有品和小米商城,目前只用RocketMQ作為實際業務的消息隊列,日志會用到talos。之前的有品使用過原生的Kafka,也使用過公司自研的Notify。Notify是我個人非常不認同的一個中間件,其內部使用了Mysql和Redis,作為消息隊列,非常不成熟,其架構類似如下:
? ? ? ? 可以看到,其消息隊列依賴于Redis和數據庫,實現的性能以及功能都有待商榷。后來它自己也基于RocketMQ了。額,我能直接用RocketMQ,為什么還要用你啊?
????????后期經過調研,有品最終都換成了RocketMQ,主要是考慮到RocketMQ的幾個特性:
- 事務寫入
- Key級別順序消息,可以用訂單號作為hashkey
- 重試 ,支持不同模式的重試(順序消費時默認無限重試,并發消費可間隔重試16次數)
- 死信隊列 當達到一定消費次數之后,就直接進入死信隊列,方便后續手動觸發。
小米RocketMQ發展軌跡:
????????我們使用的是開源的RocketMQ,眾所周知,其只支持固定級別的延遲,為了實現任意時間的延遲,小米云團隊參考了DDMQ的經驗借助RocksDB和時間輪以插件的形式無侵入地支持了任意時間的延遲。
????????此外,針對于Pull模式(RocketMQ 4.x)的缺點,也做了改進。由于RocketMQ要求一個分區只能同時被一個消費者消費(同組),因此當消費者數量大于分區數量時,多出的消費者是不能進行消費的,這無疑是一種浪費。因此針對這點,小米進行了優化。優化如下:
????????
? ? ? ? POP模式不會綁定某個實例,彌補了Pull模式的不足,不會出現數據傾斜、消息堆積的問題。實際上,RocketMQ5.X官方已經解決了,官方實現了消費的負載均衡,消息會同時分配給消費者分組中的多個消費者一起分擔,功能要比小米基于4.X版本開發的更加強大。具體可看官網:消費者負載均衡
? ? ? ? ? 在我走之前,RocketMQ一直都是小米主推的消息隊列,主要還是因為特別適用于我們的業務場景。這也是我自己最喜歡用的消息隊列。雖然RocketMQ是基于Kafka思想開發的,但站在巨人的肩膀上并超越它,不是什么壞事。
3、Talos
????????Talos是小米自研的一個消息隊列,已經比較早了,設計它的初衷是因為當時使用的是Kafka 0.8 版,當時版本的Kafka自身存在很多缺點,比如集群擴容和故障恢復時非常麻煩。
Talos實際上也是參考Kafka進行開發的,其主要變化:
1、將存儲和結算相分離。存儲采用HDFS,TalosServer只負責調度;
2、采用一致性hash實現負載均衡。
據Talos團隊介紹,目前Talos實現了:
- 日處理消息數超過 2 萬億條,日消息峰值 4 千萬條/秒,日處理數據量 1.3PB;
- Topic 總數 13000+,下游的作業數 15000+,接入業務數量 350+ ;
????????其實,Talos還實現了Exactly Once,這是我覺得比較好的一點(當然,新版本的kafka也已經實現了)。基本思想是在生產者生產一個序列號,同樣的序列號,使得broker不會再繼續處理;在消費端,先查redis緩存,看是否已經處理同樣的序列號,如果已處理,就不再繼續處理。
????????關于Talos這部分,我建議大家看下面參考資料中的小米消息隊列的實踐,里面詳解介紹了talos的由來,架構和特點,非常贊。
參考資料:
千與千尋-淺談Kafka以及Rocketmq的高性能
萬億級消息背后: 小米消息隊列的實踐_云計算_勇幸_InfoQ精選文章