分佈式消息系統,設計要點。畫龍畫虎難畫骨

原創:小姐姐味道(微信公衆號ID:xjjdog),歡迎分享,轉載請保留出處。java

分佈式緩存方面,redis勇奪花魁。但對於消息隊列mq來講,還處於百花齊放的年代。程序員

緩存系統,基本上解決一個存取問題,就萬事大吉了,調用是同步的。對於消息隊列來講,就不太同樣。它的使用場景多樣,可靠級別多變,從生產端到消費端,過程是異步的。web

消息系統的設計要點,有不少。如今,很難有一個消息系統,可以兼顧下面提到的設計要點。它要是說能夠,那就是母體在吹。redis

因此不少時候,如今流行的Kafka、RabbitMQ、RocketMQ等,會被同時使用。若是你在作相關方面的選型,下面這些技術點就是權衡之處。那句話叫什麼來着:牝雞司晨,唯家之索。spring

要點

本文將針對這些mq,從總體上抽象一些共有特性。包括:協議、類型、消費方式、堆積能力、高可用、高可靠、高性能、擴展性和生態。若是你想要深刻某個mq,這裏也有幾篇關於kafka的文章。數據庫

Kafka基礎知識索引 系統講解kafka的基礎知識 360度測試:KAFKA會丟數據麼?其高可用是否知足需求? 經過測試深刻探討kafka業務場景的使用編程

高可用

高可用主要解決集羣單節點,在異常狀況下的failover和HA。解決高可用問題的通常思路就是副本機制。

經過增長副本,能夠將數據的風險分散到多臺機器上。這就須要在主分片出現問題時,可以從副本中找出一個做爲新的主分片。有不少這樣的協調工具,好比zk。也有的mq,本身去實現這個過程。緩存

有的模式就比較浪費資源了,好比rocketmq,使用standby從機進行高可用保證,出問題再頂上來。微信

高可靠

消息系統的可靠性和性能是相悖的。通常的mq,可靠性級別都是能夠調節的,但性能會發生相反的聯動性。從消息級別來講,大致路線有:
發出去就無論了->單節點確認->多節點確認->多節點確認同步刷盤->全部節點同步刷盤->事務消息等。

單機高可靠
集羣的高可靠方面,會有ack機制和多副本機制進行保證。對於單個節點來講,斷電或者主機異常,會是一個比較大的挑戰。爲了處理這種狀況,須要有刷盤機制或者其餘持久化機制。同時,數據的完整性校驗也是須要的,這也是相似kafka這種消息系統,數據量大的時候,啓動時間很是長的緣由。websocket

生產端
生產端除了要考慮buffer丟失的問題,還要考慮到一些發送錯誤的狀況,包括與集羣通訊的超時和重試處理。

消費端
消費端經過消息確認機制來保證消息已經被正確消費。因爲其間會發生不少異常狀況,因此大多數消息系統保證at least once語義。即確保消息至少被消費1次。

言外之意,消息是會重複的,消費者須要作到冪等,保證重複消費不會引發業務異常。

消費端一樣會發生一些錯誤狀況,有些mq能夠在屢次消費失敗後自動進入死信隊列,有些mq須要自行設計topic進行規劃。

高性能

做爲一個數據傳輸的通道,性能是一個很是有份量的考量點。其中兩個比較重要的指標,一個是消息的延遲性,一個就是消息的吞吐量。

消息從生產端發出,到消費者處理,其間的過程不能太長,對於使用拉模式來消費的mq來講,就要加快輪詢速度,並使用零拷貝一類的技術加快數據傳輸。

對於消息吞吐量來講,是一個生產端、mq節點、消費端共同優化的結果。目前主要有如下手段:

異步化
消息採用異步發送的方式,發送端不用同步等待,加快了處理速度。

batch
採用批量發送的方式,減小網絡傳輸的次數,方便進行數據壓縮。通常是內存中緩衝一個buffer,若是buffer滿了,或者到達了時間窗口,則進行一次傳輸。這可以顯著增長傳輸速度,但處理不當容易丟失數據。

順序IO
xjjdog已經在多篇文章提到,順序性操做磁盤,比隨機操做內存速度快的多。這也是kafka之類的消息隊列速度快的緣由之一,但要注意主題的數量(想下爲何)。

另外,還有其餘手段。好比優化操做系統參數,使用分片增長並行度等。

消息類型

消息有點對點的,一條消息只會被消費一次。Pub/Sub經過發佈/訂閱模式,一條消息可以被多個消費端消費。還有一種消息是經過廣播模式進行廣播,即producer發送消息,全部的consumer都會收到。

除了普通發送的消息,還有一些特殊用途的消息。順序性消息有全局有序和分區有序之分,通常用於有嚴格順序要求的業務。經過業務的設計,能夠規避全局有序這種很是耗性能的操做。

有些mq還支持定時消息(私覺得這種放業務系統更佳)。事務消息更加耗費性能,慎用。

還有一些mq,提供打tag、進行消息過濾的功能。好比訂單信息發送到一個topic,消費者只訂閱相關商品的訂單,某些有求隔離的狀況,很是有用。

消費模式

消費模式,主要有推模式和拉模式。拉模式最爲實用和流行,由於消費處理速度能夠由消費端進行調節。

推模式的實時性更好一些,但很差評估消費端能力,容易將其壓垮。同時,處理pub/sub,失敗重試等,也有不少挑戰。

協議

你們都知道java中有一個JMS規範,可是相似於kafka這種卻沒有實現這個規範。因此一些協議,好比amqp、openwire等,有更加明顯的定製型。

這個傳輸協議,與功能關係不大。好比就有基於http協議的,或者redis協議,甚至websocket之上的stomp。

mqtt是物聯網IoT的應用協議,你會發現一大坨基於它的消息隊列。

堆積能力

如今的數據都長這麼大,mq的堆積能力是很是很是重要的。就拿redis這種內存型的隊列來講,分分鐘就給撐爆。mq除了做爲消息處理的通道,還能夠做爲備用存儲用。

堆積能力的體如今海量存儲上,好比存放在數據庫中(矛盾轉移),掛載很是大的磁盤等。但別高興的太早,大型集羣的啓動加載,以及故障再平衡,一般會花費比較長的時間。

堆積能力的另一個體現,就是對歷史消息的清理。通常有兩個策略:磁盤上線和過時清理,能夠結合需求靈活設置。

生態

一個開源軟件的生態是很是重要的,對於mq來講也是如此。主要體如今兩個方面,一個是支持的的開發語言多樣(須要提供producer和consumer兩方的包),一個是針對周邊軟件的支持。好比spring,spark,hadoop,flink等,減小集成成本。

這方面除了比較新的mq系統,都作的不錯。

消息系統的做用

消息系統在目前的分佈式系統中設計中,做用愈來愈大。它的使用場景,包括但不限於:

削峯 用於承接超出業務系統處理能力的請求,使業務平穩運行。這可以大量節約成本,好比某些秒殺活動,並非針對峯值設計容量。

緩衝 在服務層和緩慢的落地層做爲緩衝層存在,做用與削峯相似,但主要用於服務內數據流轉。好比批量短信發送。

解耦 項目尹始,並不能肯定具體需求。消息隊列能夠做爲一個接口層,解耦重要的業務流程。只須要遵照約定,針對數據編程便可獲取擴展能力。

冗餘 消息數據可以採用一對多的方式,供多個毫無關聯的業務使用。

健壯性 消息隊列能夠堆積請求,因此消費端業務即便短期死掉,也不會影響主要業務的正常進行。

End

根據消息的體量和用途,目前能夠將分佈式mq大致分爲兩類。

一類用於業務系統,保證極高的可靠性。要求不可以丟失消息,好比訂單、支付等,有較高的SLA服務水準。這種狀況,對mq的功能要求也比較多,包括消息的可查性。

另一類用於大數據相關的系統,典型的特色就是吞吐量很是大。異常狀況下,丟失幾條消息,無傷大雅。

但消息系統,可能關注的只是mq自己。怎麼保證生產端、消費端、mq自己三者的可用性,是須要業務進行權衡的。

好比,前段時間xjjdog開源的okmq,就是用來解決一個特定場景的高可用問題。 開源一個kafka加強:okmq-1.0.0

做者簡介:小姐姐味道 (xjjdog),一個不容許程序員走彎路的公衆號。聚焦基礎架構和Linux。十年架構,日百億流量,與你探討高併發世界,給你不同的味道。個人我的微信xjjdog0,歡迎添加好友,​進一步交流。​

相關文章
相關標籤/搜索