消息是互聯網信息的一種表現形式,是人利用計算機進行信息傳遞的有效載體,好比即時通信網壇友最熟悉的即時通信消息就是其具體的表現形式之一。php
消息從發送者到接收者的典型傳遞方式有兩種:html
1)一種咱們能夠稱爲即時消息:即消息從一端發出後(消息發送者)當即就能夠達到另外一端(消息接收者),這種方式的具體實現就是平時最多見的IM聊天消息;前端
2)另外一種稱爲延遲消息:即消息從某端發出後,首先進入一個容器進行臨時存儲,當達到某種條件後,再由這個容器發送給另外一端。算法
在上述「消息傳遞方式2)」中所指的這個容器的一種具體實現就是MQ消息隊列服務。數據庫
MQ消息隊列中間件是中大型分佈式系統中重要的組件,它主要用來解決:應用解耦、異步消息、流量削鋒等問題,用以實現高性能、高可用、可伸縮和最終一致性架構。目前使用較多的消息隊列有ActiveMQ、RabbitMQ、ZeroMQ、Kafka、MetaMQ、RocketMQ等。MQ消息隊列中間件已被普遍用於電商、即時通信、社交等各類中大型分佈式應用系統。編程
在一個典型的IM即時通信應用中,MQ消息隊列能夠用於:緩存
1)用戶的聊天消息離線存儲環節:由於IM消息的發送屬於高吞吐場景,直接操縱DB很容易就把DB搞掛了,因此離線消息在落地入庫前,能夠先扔到MQ消息隊列中,再由單獨部署的消費者來有節奏地存儲到DB中;安全
2)用戶的行爲數據收集環節:由於用戶的聊天消息和指令等,能夠用於大數據分析,並且基於國家監管要求也是必需要存儲一段時間的,因此此類數據的收集一樣能夠用於MQ消息隊列,再由單獨部署的消費者存儲到DB中;服務器
3)用戶的操做日誌收集環節:log這種數據價值不高,但關鍵時刻又很是有用,並且數據量又很大,要想存儲起來難度很高,這時就輪到Linkedin公司開源的Kafka出場了;微信
....
所以,對於即時通信開發者來講,正確地理解MQ消息隊列,對於IM或消息推送系統的架構設計、方案選型等都大有裨益。
學習交流:
- 即時通信開發交流3羣:185926912 [推薦]
- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》
(本文同步發佈於:http://www.52im.net/thread-1979-1-1.html)
▼ IM開發乾貨系列文章(本文是其第16篇):
《IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞》
《一種Android端IM智能心跳算法的設計與實現探討(含樣例代碼)》
《IM開發基礎知識補課(一):正確理解前置HTTP SSO單點登錄接口的原理》
《IM開發基礎知識補課(二):如何設計大量圖片文件的服務端存儲架構?》
《IM開發基礎知識補課(三):快速理解服務端數據庫讀寫分離原理及實踐建議》
《IM開發基礎知識補課(四):正確理解HTTP短鏈接中的Cookie、Session和Token》
若是您是IM開發初學者,強烈建議首先閱讀《新手入門一篇就夠:從零開發移動端IM》。
MQ消息隊列目前在中大型分佈式系統實際應用中經常使用的使用場景主要有:異步處理、應用解耦、流量削鋒和消息通信四個場景。
場景說明:一個典型的IM即時通信系統中,用戶註冊成功後可能須要發送註冊郵件和註冊通知短信。
傳統的作法有兩種:
1)串行的方式:即將註冊信息寫入數據庫成功後、發送註冊郵件、再發送註冊短信。以上三個任務所有完成後,返回給客戶端;
2)並行方式:即將註冊信息寫入數據庫成功後,發送註冊郵件的同時,發送註冊短信。以上三個任務完成後,返回給客戶端。與串行的差異是,並行的方式能夠提升處理的時間。
假設三個業務節點每一個使用50毫秒,不考慮網絡等其餘開銷,則串行方式的時間是150毫秒,並行的時間多是100毫秒。
由於CPU在單位時間內處理的請求數是必定的,假設CPU1秒內吞吐量是100次。則串行方式1秒內CPU可處理的請求量是7次(1000/150)。並行方式處理的請求量是10次(1000/100)。
小結:如以上案例描述,傳統的方式系統的性能(併發量,吞吐量,響應時間)會有瓶頸。
如何解決這個問題呢?答案是:引入消息隊列,將不是必須的業務邏輯,異步處理。
改造後的架構以下:
按照以上約定,用戶的響應時間至關因而註冊信息寫入數據庫的時間,也就是50毫秒。註冊郵件,發送短信寫入消息隊列後,直接返回,所以寫入消息隊列的速度很快,基本能夠忽略,所以用戶的響應時間多是50毫秒。所以架構改變後,系統的吞吐量提升到每秒20 QPS。比串行提升了3倍,比並行提升了兩倍。
場景說明:一個典型的電商購物系統中,用戶下訂單後,訂單系統須要通知庫存系統。
傳統的作法是:訂單系統調用庫存系統的接口。以下圖所示:
傳統模式的缺點:假如庫存系統沒法訪問,則訂單減庫存將失敗,從而致使訂單失敗,訂單系統與庫存系統耦合。
如何解決以上問題呢?答案是:引入應用消息隊列後的方案。以下圖:
如上圖所示,大體的原理是:
訂單系統:用戶下單後,訂單系統完成持久化處理,將消息寫入消息隊列,返回用戶訂單下單成功;
庫存系統:訂閱下單的消息,採用拉/推的方式,獲取下單信息,庫存系統根據下單信息,進行庫存操做。
好處就是:假如在下單時庫存系統不能正常使用,也不影響正常下單,由於下單後,訂單系統寫入消息隊列就再也不關心其餘的後續操做了。實現訂單系統與庫存系統的應用解耦。
流量削鋒也是消息隊列中的經常使用場景,通常在電商秒殺等大型活動(好比雙11)、團購搶單活動中使用普遍。
應用場景:秒殺活動,通常會由於流量過大,致使流量暴增,應用掛掉。爲解決這個問題,通常須要在應用前端加入消息隊列。
在這種場景下加入消息隊列服務的好處:
1)能夠控制活動的人數;
2)能夠緩解短期內高流量壓垮應用。
用戶的請求,服務器接收後,首先寫入消息隊列。假如消息隊列長度超過最大數量,則直接拋棄用戶請求或跳轉到錯誤頁面。秒殺業務根據消息隊列中的請求信息,再作後續處理。
日誌處理是指將消息隊列用在日誌處理中,好比Linkedin這種大型職業社交應用架構中Kafka的應用(Kafka就是Linkedin開發並開源的),解決大量日誌傳輸的問題。
使用Kafka後的架構簡化以下:
上圖所示的架構原理就是:
日誌採集客戶端:負責日誌數據採集,定時寫入Kafka隊列;
Kafka消息隊列:負責日誌數據的接收,存儲和轉發;
日誌處理應用:訂閱並消費kafka隊列中的日誌數據。
即時消息通信是指,消息隊列通常都內置了高效的通訊機制,所以也能夠用在純的即時消息通信場景。好比實現點對點消息隊列或者IM聊天室等(但Jack Jiang認爲,在中大型IM系統中,MQ並不適合這麼用,具體的討論請見:《請教可使用MQ消息隊列中間件作即時通信系統嗎?》)。
點對點通信:客戶端A和客戶端B使用同一隊列,進行消息通信;
聊天室通信:客戶端A,客戶端B,客戶端N訂閱同一主題,進行消息發佈和接收。實現相似聊天室效果。
以上實際是消息隊列的兩種消息模式,點對點或發佈訂閱模式。模型爲示意圖,供參考。
常見的MQ消息隊列消息模式有:
1)P2P模式;
2)Pub/sub模式(也就是常說的「發佈/訂閱」模式);
3)推(Push)模式和拉(Pull)模式。
下面將逐個介紹這幾種常消息模式。
P2P模式包含三個角色:
1)消息隊列(Queue);
2)發送者(Sender);
3)接收者(Receiver)。
每一個消息都被髮送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留着消息,直到他們被消費或超時。
P2P消息模式的特色:
每一個消息只有一個消費者(Consumer)(即一旦被消費,消息就再也不在消息隊列中)發送者和接收者之間在時間上沒有依賴性,也就是說當發送者發送了消息以後,無論接收者有沒有正在運行,它不會影響到消息被髮送到隊列接收者在成功接收消息以後需向隊列應答成功 若是但願發送的每一個消息都會被成功處理的話,那麼須要P2P模式。
如上圖所示,此消息模式包含三個角色:
1)主題(Topic);
2)發佈者(Publisher);
3)訂閱者(Subscriber)。
多個發佈者將消息發送到Topic,系統將這些消息傳遞給多個訂閱者。
Pub/Sub的特色:
每一個消息能夠有多個消費者發佈者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須建立一個訂閱者以後,才能消費發佈者的消息。爲了消費消息,訂閱者必須保持運行的狀態。爲了緩和這樣嚴格的時間相關性,有些MQ消息隊列(好比RabbitMQ)容許訂閱者建立一個可持久化的訂閱。這樣,即便訂閱者沒有被激活(運行),它也能接收到發佈者的消息。若是但願發送的消息能夠不被作任何處理、或者只被一個消息者處理、或者能夠被多個消費者處理的話,那麼能夠採用Pub/Sub模型。
推(push)模式是一種基於C/S機制、由服務器主動將信息送到客戶器的技術。
在Push模式應用中,服務器把信息送給客戶器以前,並無明顯的客戶請求。push事務由服務器發起。push模式可讓信息主動、快速地尋找用戶/客戶器,信息的主動性和實時性比較好。但精確性較差,可能推送的信息並不必定知足客戶的需求。
Push模式不能保證能把信息送到客戶器,由於推模式採用了廣播機制,若是客戶器正好聯網而且和服務器在同一個頻道上,推送模式纔是有效的。
Push模式沒法跟蹤狀態,採用了開環控制模式,沒有用戶反饋信息。在實際應用中,由客戶器向服務器發送一個申請,並把本身的地址(如IP、port)告知服務器,而後服務器就源源不斷地把信息推送到指定地址。在多媒體信息廣播中也採用了推模式。
拉(Pull)模式與推(Push)模式相反,是由客戶器主動發起的事務。服務器把本身所擁有的信息放在指定地址(如IP、port),客戶器向指定地址發送請求,把本身須要的資源「拉」回來。不只能夠準確獲取本身須要的資源,還能夠及時把客戶端的狀態反饋給服務器。
一份主流MQ技術對比清單:
另外,即時通信網整理的另外一篇《IM系統的MQ消息中間件選型:Kafka仍是RabbitMQ?》,能夠詳細瞭解一下Kafka和RabbitMQ的對比。
Kafka是Linkedin開源的MQ系統(現已經是Apache下的一個子項目),它是一個高性能跨語言分佈式發佈/訂閱消息隊列系統,主要特色是基於Pull的模式來處理消息消費,追求高吞吐量,一開始的目的就是用於日誌收集和傳輸,0.8開始支持複製,不支持事務,適合產生大量數據的互聯網服務的數據收集業務。
Kafka還具備如下特性:
1)快速持久化,能夠在O(1)的系統開銷下進行消息持久化;
2)高吞吐,在一臺普通的服務器上既能夠達到10W/s的吞吐速率;
3)徹底的分佈式系統,Broker、Producer、Consumer都原生自動支持分佈式,自動實現負載均衡;
4)支持Hadoop數據並行加載,對於像Hadoop的同樣的日誌數據和離線分析系統,但又要求實時處理的限制,這是一個可行的解決方案。Kafka經過Hadoop的並行加載機制統一了在線和離線的消息處理。
Apache Kafka相對於ActiveMQ是一個很是輕量級的消息系統,除了性能很是好以外,仍是一個工做良好的分佈式系統。
RabbitMQ是使用Erlang語言開發的開源消息隊列系統,基於AMQP協議來實現。AMQP的主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。AMQP協議更多用在企業系統內,對數據一致性、穩定性和可靠性要求很高的場景,對性能和吞吐量的要求還在其次。
RabbitMQ自己支持不少的協議:AMQP,XMPP, SMTP, STOMP,也正因如此,它很是重量級,更適合於企業級的開發。同時實現了Broker構架,這意味着消息在發送給客戶端時先在中心隊列排隊。對路由,負載均衡或者數據持久化都有很好的支持。
RocketMQ是阿里開源的消息中間件,它是純Java開發,具備高吞吐量、高可用性、適合大規模分佈式系統應用的特色。RocketMQ思路起源於Kafka,但並非Kafka的一個Copy,它對消息的可靠傳輸及事務性作了優化,目前在阿里集團被普遍應用於交易、充值、流計算、消息推送、日誌流式處理、binglog分發等場景。
ZeroMQ只是一個網絡編程的Pattern庫,將常見的網絡請求形式(分組管理,連接管理,發佈訂閱等)模式化、組件化,簡而言之socket之上、MQ之下。對於MQ來講,網絡傳輸只是它的一部分,更多須要處理的是消息存儲、路由、Broker服務發現和查找、事務、消費模式(ack、重投等)、集羣服務等。
ZeroMQ是號稱最快的消息隊列系統,尤爲針對大吞吐量的需求場景。ZeroMQ可以實現RabbitMQ不擅長的高級/複雜的隊列,可是開發人員須要本身組合多種技術框架,技術上的複雜度是對這MQ可以應用成功的挑戰。ZeroMQ具備一個獨特的非中間件的模式,你不須要安裝和運行一個消息服務器或中間件,由於你的應用程序將扮演這個服務器角色。你只須要簡單的引用ZeroMQ程序庫,可使用NuGet安裝,而後你就能夠愉快的在應用程序之間發送消息了。可是ZeroMQ僅提供非持久性的隊列,也就是說若是宕機,數據將會丟失。其中,Twitter的Storm 0.9.0之前的版本中默認使用ZeroMQ做爲數據流的傳輸(Storm從0.9版本開始同時支持ZeroMQ和Netty做爲傳輸模塊)。
RabbitMQ/Kafka/ZeroMQ 都能提供消息隊列服務,但有很大的區別。
在面向服務架構中經過消息代理(好比 RabbitMQ / Kafka等),使用生產者-消費者模式在服務間進行異步通訊是一種比較好的思想。
由於服務間依賴由強耦合變成了鬆耦合。消息代理都會提供持久化機制,在消費者負載高或者掉線的狀況下會把消息保存起來,不會丟失。就是說生產者和消費者不須要同時在線,這是傳統的請求-應答模式比較難作到的,須要一箇中間件來專門作這件事。其次消息代理能夠根據消息自己作簡單的路由策略,消費者能夠根據這個來作負載均衡,業務分離等。
缺點也有,就是須要額外搭建消息代理集羣(但優勢是大於缺點的 ) 。
ZeroMQ 和 RabbitMQ/Kafka 不一樣,它只是一個異步消息庫,在套接字的基礎上提供了相似於消息代理的機制。使用 ZeroMQ 的話,須要對本身的業務代碼進行改造,不利於服務解耦。
RabbitMQ 支持 AMQP(二進制),STOMP(文本),MQTT(二進制),HTTP(裏面包裝其餘協議)等協議。Kafka 使用本身的協議。
Kafka 自身服務和消費者都須要依賴 Zookeeper。
RabbitMQ 在有大量消息堆積的狀況下性能會降低,Kafka不會。畢竟AMQP設計的初衷不是用來持久化海量消息的,而Kafka一開始是用來處理海量日誌的。
總的來講,RabbitMQ 和 Kafka 都是十分優秀的分佈式的消息代理服務,只要合理部署,基本上能夠知足生產條件下的任何需求。
關於這兩種MQ的比較,網上的資料並很少,最權威的的是kafka的提交者寫一篇文章:http://www.quora.com/What-are-the-differences-between-Apache-Kafka-and-RabbitMQ
這篇文間裏面提到的要點:
1) RabbitMq比kafka成熟,在可用性上,穩定性上,可靠性上,RabbitMq超過kafka;
2) Kafka設計的初衷就是處理日誌的,能夠看作是一個日誌系統,針對性很強,因此它並無具有一個成熟MQ應該具有的特性;
3) Kafka的性能(吞吐量、tps)比RabbitMq要強,這篇文章的做者認爲,二者在這方面沒有可比性;
4)總的來講,目前RocketMq、Kafka、RabbitMq在各家公司都有使用,具體看技術團隊的熟悉程度及使用場景了。
《一套海量在線用戶的移動端IM架構設計實踐分享(含詳細圖文)》
《IM開發基礎知識補課(二):如何設計大量圖片文件的服務端存儲架構?》
《IM開發基礎知識補課(三):快速理解服務端數據庫讀寫分離原理及實踐建議》
《IM開發基礎知識補課(四):正確理解HTTP短鏈接中的Cookie、Session和Token》
《WhatsApp技術實踐分享:32人工程團隊創造的技術神話》
《王者榮耀2億用戶量的背後:產品定位、技術架構、網絡方案等》
《IM系統的MQ消息中間件選型:Kafka仍是RabbitMQ?》
《騰訊資深架構師乾貨總結:一文讀懂大型分佈式系統設計的方方面面》
《子彈短信光鮮的背後:網易雲信首席架構師分享億級IM平臺的技術實踐》
《知乎技術分享:從單機到2000萬QPS併發的Redis高性能緩存實踐之路》
《IM開發基礎知識補課(五):通俗易懂,正確理解並用好MQ消息隊列》
>> 更多同類文章 ……
《移動端IM開發者必讀(一):通俗易懂,理解移動網絡的「弱」和「慢」》
《移動端IM開發者必讀(二):史上最全移動弱網絡優化方法總結》
《現代移動端網絡短鏈接的優化手段總結:請求速度、弱網適應、安全保障》
《小白必讀:閒話HTTP短鏈接中的Session和Token》
《IM開發基礎知識補課:正確理解前置HTTP SSO單點登錄接口的原理》
《IM消息送達保證機制實現(一):保證在線實時消息的可靠投遞》
《開源IM工程「蘑菇街TeamTalk」的現狀:一場虎頭蛇尾的開源秀》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(上篇)》
《QQ音樂團隊分享:Android中的圖片壓縮技術詳解(下篇)》
《騰訊原創分享(一):如何大幅提高移動網絡下手機QQ的圖片傳輸速度和成功率》
《騰訊原創分享(二):如何大幅壓縮移動網絡下APP的流量消耗(上篇)》
《騰訊原創分享(三):如何大幅壓縮移動網絡下APP的流量消耗(下篇)》
《如約而至:微信自用的移動端IM網絡層跨平臺組件庫Mars已正式開源》
《基於社交網絡的Yelp是如何實現海量用戶圖片的無損壓縮的?》
《騰訊技術分享:騰訊是如何大幅下降帶寬和網絡流量的(圖片壓縮篇)》
《騰訊技術分享:騰訊是如何大幅下降帶寬和網絡流量的(音視頻技術篇)》
《字符編碼那點事:快速理解ASCII、Unicode、GBK和UTF-8》
《最火移動端跨平臺方案盤點:React Native、weex、Flutter》
《子彈短信光鮮的背後:網易雲信首席架構師分享億級IM平臺的技術實踐》
《IM開發基礎知識補課(五):通俗易懂,正確理解並用好MQ消息隊列》
>> 更多同類文章 ……
(本文同步發佈於:http://www.52im.net/thread-1979-1-1.html)