分布式消息隊列

1 為什么要使用消息隊列

最主要得應用場景:解耦 異步 削峰

(1)解耦

傳統模式:系統間得耦合度強 如系統A直接調用系統B系統C得代碼,如果再有系統D接入,則系統A還要修改代碼。

中間件模式:系統A將消息寫入消息隊列,系統B,系統C 訂閱消息隊列,如果再有系統D介入,直接訂閱消息隊列即可 系統A不必修改代碼

(2)異步

傳統模式:一些非必要得業務邏輯以同步得方式運行浪費時間

中間件模式:將消息寫入消息隊列 一些非必要得業務邏輯以異步得方式運行 提高響應速度

(3)削峰

傳統模式:并發量大得時候所有請求全部到數據庫,造成數據庫連接異常

中間件模式:系統慢慢得按照數據庫能處理得并發量從消息隊列中慢慢拉去消息。在生產環境中這種短暫得高峰期積壓是允許的。

2? 使用消息隊列的缺點

? (1) 系統的可用性降低

? ? ?消息隊列會掛掉 一但掛掉 就會影響可用性

(2) 系統復雜性增加?

考慮一致性問題 保證消息不被重復消費 保證消息可靠傳輸

3? 消息隊列選型

四種主流消息隊列:ActiveMQ RabbitMQ? RocketMQ? Kafka?

去ActiveMQ 社區看看MQ更新頻率(幾個月更新一次)

去RabbitMQ社區看看RabbitMQ的更新頻率(一月兩次)

建議:

(1)中小型軟件公司,建議選RabbitMQ ,一方面erlang語言天生具備高并發的特性,而且它的管理界面用起來十分方便。(定制erlang開發少 但 rabbitMQ社區活躍 可以解決開發中遇到的bug 這點對于中小型公司來書十分重要,

中小型軟件公司 數據量不是特別大(跟互聯網公司比) 應首選功能比較完備的,所以kafka排除。

Rocketmq 是阿里出品,如果阿里放棄維護Rocketmq ,中小型公司一般抽不出人來進行rocketmq的定制化開發。

(2)大型軟件公司,根據具體使用在RocketMq和kafka 之間二選一。一方面,大型軟件公司具有足夠的資金搭建分布式環境,也具備足夠大的數據量,針對rocketMq,大型軟件公司也可以抽出人手對rocketMQ 進行定制化開發(java開發)。至于kafka.根據業務場景的選擇,如果有日志采集功能,可定是首選kafka了。具體該選那個,看使用場景

4 保證消息隊列的高可用

以RocketMQ為例 他的集群就有多master模式、多master 多slave異步復制模式、多master多slave同步雙寫模式。



通訊過程:Producer與NameServer集群中的其中一個節點(隨機選擇)建立長連接,定期從NameServer獲取Topic路由信息,并向提供Topic服務的Broker Master 建立長連接,且定時向Broker發送心跳。Producer 只能將消息發送到 Broker Master,但是Consumer則不一樣,它同時和提供Topic服務的Master和Slave 建立長連接,既可以從Broker Maser 訂閱消息,也可以從Broker Slave 訂閱消息。

以kafka為例


一個典型的Kafka集群中包含若干Producer(可以時web前端產生的page view, 或者時服務器日志,系統CPU、Memory等)若干broker(Kafka 支持水平擴展、一般broker數量越多,集群吞吐率越高)若干Consumer Group ,以及一個Zookeeper集群。Kafka通過Zookeeper管理集群配置,選舉leader 以及在Consumer Group發生變化時 進行rebalance。 Producer 使用push 模式將消息發部到broker,Consumer使用pull模式 從broker訂閱并消費消息

rabbitMQ也有普通集群和鏡像集群模式

5? 保證消息不被重復消費

正常情況下 消費者在消費消息的時候,消費完畢后會發送一個確認消息給消息隊列,消息隊列就知道該消息被消費了,就會將該消息從消息隊列中刪除。只是不同的消息隊列發送的確認信息形式不同,RabbitMQ時發送一個ACK確認消息,RocketMQ 是返回一個CONSUME_SUCCESS成功標志,kafka實際上有個offset概念,就是每一個kafka消息都有一個offset,kafka消費過消息后,需要提交offset,讓消息隊列知道自己已經消費過了。所以造成重復消費的原因一般是因為網絡傳輸等故障,確認信息沒有傳到消息隊列,導致消息隊列不知道自己已經消費過該消息了,再次將該消息分發給其他的消費者。

分業務場景解決

(1)如果是做insert數據庫的操作消息 (創建主鍵解決,多次插入不成功 主鍵沖突)

(2) 冪等性的操作 比如set? 多次操作 等同一次操作

(3) 準備一個第三方介質,來做消費記錄。以redis為例 給消息分配一個全局id,只要消費過該消息,將<id,message>以K-V形式寫入redis 那消費者開始消費前,先去redis中查詢有沒有消費記錄即可。

6 保證消費的可靠性傳輸

從三個角度分析:生產者弄丟數據 消息隊列東丟數據 消費者弄丟數據

RabbitMQ:

(1)生產者丟失數據

提供Transacton 和confir嗎模式來確保生產者不丟消息

Transacton? 模式發消息前開啟事務(channel.txSelect()),然后發送消息,如果發送過程中有什么異常,事務就會回滾(channel,txRollback()),如果發送成功則提交事務(channel.txCommit()).然而缺點就是吞吐量下降了。因此上產上用confirm模式的居多。一但channel 進入confirm 模式,所有該信道上面發送的消息都將會指派一個唯一的ID(從1開始),一但消息被投遞到所有匹配的隊列之后,rabbitMQ就會發送一個ACK給生產者(包含消息的唯一ID),這就使生產這知道消息已經到達消息隊列了。如果RabbitMQ沒有處理該消息,則會發送一個Nack消息給你,你可以進行重試操作。處理Ack和Nack的代碼如下

channel.addConfirmListener(new ConfirmListener(){

@Override

public void handleNack(long deliveryTag,boolean multiple)throws IOException{

System.out.println("nack:deliveryTag="+deliveryTag+"multiple:"+multiple);

}

@Override

public void handleAck(long deliveryTag,boolean multiple) throws IOException{

System.out.println("ack:deliveryTag="+deliveryTag+"multiple:"+multiple);

}

});

(2)消息隊列丟失數據

處理消息隊列丟失數據的情況,一把是開啟持久化磁盤的配置。這個持久話配置可以和confirm 機制配合使用,你可以在持久化磁盤之后,再給生產這發送一個Ack信號。這樣如果持久化磁盤之前,rabbitMQ陣亡了,那么生產者收不到Ack信號,生產者會自動重發。

持久化一般分兩部

《1》 將queue的持久化標識durable設置為true,則代表一個持久化隊列

《2》發送消息的時候將deliveryMode=2

這樣設置之后,rabbitMQ就算掛掉了,重啟后也能恢復數據

(3)消費者丟數據

消費者丟數據一般是因為采用了自動確認消息模式,這種模式下,消費者會自動確認收到信息。這時rabbitMQ會立即將消息刪除,這種情況下如果消費者出現異常而沒能處理該消息,就會丟失該消息

解決方案:采用手動確認消息即可

Kafka

Producer 在發布消息到某個partition時,先通過ZooKeeper 找到該Partition的leader,然后無論該Topic的Replication Tactor為多少(也即 該partition 有多少個Replica),Producer只將該消息發送到該Partition的Leader.Leader會將該消息寫入其本地log.每個Follower都從Leader中pull數據。

針對上述情況得出分析

(1)生產者丟失數據

在kafka生產中,基本都有一個leader和多個follwer.follwer會去同步liader的信息。因此為了避免生產這丟數據,做如下亮點配置

《1》第一個配置要在Producer端設置acks=all .這個配置保證了,follwer同步完成后,才認為i消息發送成功。

《2》在priducer端設置retries=MAX,一但寫入失敗,則無限重試

(2)消息隊列丟失數據?

針對消息隊列丟失數據的情況,無外乎就是,數據還沒同步,leader就掛掉了,這時zookpeer會其他的follwer切換為leader,那數據就丟失了。針對這種情況,應該做兩個配置。

《1》 replication。factor參數,這個值必須大于1 即 要求每個partition必須有兩個副本

《2》min.insync.replicas參數這個值必須大于1,這個是要求一個leader至少感知到有至少一個follower還跟自己保持聯系

這兩個配置加上上面生產者的配置聯合起來用基本可以確保kafka不丟數據

(3)消費者丟數據

這種情況一般是自動提交了offset,然后你處理程序過程中掛了。kafka以為你處理好了。

offset:指的是kafka的topic中的每個消費組消費的下標。簡單的來說就是一條消息對應一個offset下標,每次消費數據的時候如果提交offset,那么下次消費就會從提交的offset加1 那里消費。offset 消費下標從0開始 ,如10條消費了7條并且提交了,那么kafka服務器記錄的提交的offset的下表就是6,那么下次消費的時候offset就從7開始。

解決方案跟rabbitMq一樣改成手動提交即可。

ActiveMQ

RocketMQ

7 保證消息的順序性

通過某種算法,將需要保持先后順序的消息放到同一個消息隊列(kafka 就是partition,rabbitMq中就是queue)然后只用一個消費者去消費該隊列。


注:本文來源于網絡 作者孤獨煙 如有侵權請聯系我刪除即可

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容