https://blog.csdn.net/acaoye/article/details/82967172
消息隊列系列分享大綱:
一、消息隊列的概述
二、消息隊列之RabbitMQ的使用
三、消息隊列之Kafka的使用
四、消息隊列之RabbitMQ的原理詳解
五、消息隊列之Kafka的原理詳解
六、消息隊列之面試集錦
1.消息隊列的概述
消息隊列(Message Queue)中間件是分布式系統中重要的組件;
主要解決應用耦合,異步消息,流量削鋒等問題;
實現高性能,高可用,可伸縮和最終一致性架構。是大型分布式系統不可缺少的中間件;
目前在生產環境,使用較多的消息隊列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等;
部分數據庫如Redis、Mysql以及phxsql也可實現消息隊列的功能;
具有 低耦合、可靠投遞、廣播、流量控制、最終一致性 等一系列功能。
2.消息隊列使用場景
消息隊列在實際應用中有四個場景:
應用耦合:多應用間通過消息隊列對同一消息進行處理,避免調用接口失敗導致整個過程失敗;
異步處理:多應用對消息隊列中同一消息進行處理,應用間並發處理消息,相比串行處理,減少處理時間;
限流削峰:廣泛應用於秒殺或搶購活動中,避免流量過大導致應用系統掛掉的情況;
消息驅動的系統:系統分為消息隊列、消息生產者、消息消費者,生產者負責產生消息,消費者(可能有多個)負責對消息進行處理;
2.1異步處理
具體場景:用戶為了使用某個應用,進行注冊,系統需要發送注冊郵件並驗證短信。對這兩個操作的處理方式有兩種:串行及並行
(1)串行方式:新注冊信息生成后,先發送注冊郵件,再發送驗證短信;
在這種方式下,需要最終發送驗證短信后再返回給客戶端。
(2)並行處理:新注冊信息寫入后,由發短信和發郵件並行處理;
在這種方式下,發短信和發郵件 需處理完成后再返回給客戶端。
假設以上三個子系統處理的時間均為50ms,且不考慮網絡延遲,則總的處理時間:
串行:50+50+50=150ms 並行:50+50 = 100ms
若使用消息隊列:
並在寫入消息隊列后立即返回成功給客戶端,則總的響應時間依賴於寫入消息隊列的時間,而寫入消息隊列的時間本身是可以很快的,基本可以忽略不計,因此總的處理時間相比串行提高了2倍,相比並行提高了一倍;
2.2 應用耦合
具體場景:用戶使用QQ相冊上傳一張圖片,人臉識別系統會對該圖片進行人臉識別,一般的做法是,服務器接收到圖片后,圖片上傳系統立即調用人臉識別系統,調用完成后再返回成功,如下圖所示:
該方法有如下缺點:
人臉識別系統被調失敗,導致圖片上傳失敗;
延遲高,需要人臉識別系統處理完成后,再返回給客戶端,即使用戶並不需要立即知道結果;
圖片上傳系統與人臉識別系統之間互相調用,需要做耦合;
若使用消息隊列:
客戶端上傳圖片后,圖片上傳系統將圖片信息寫入消息隊列,直接返回成功;而人臉識別系統則定時從消息隊列中取數據,完成對新增圖片的識別。
人臉識別系統可以選擇不同的調度策略,按照閑時、忙時、正常時間,對隊列中的圖片信息進行處理。
2.3 限流削峰
具體場景:購物網站開展秒殺活動,一般由於瞬時訪問量過大,服務器接收過大,會導致流量暴增,相關系統無法處理請求甚至崩潰。而加入消息隊列后,系統可以從消息隊列中取數據,相當於消息隊列做了一次緩沖。
該方法有如下優點:
請求先入消息隊列,而不是由業務處理系統直接處理,做了一次緩沖,極大地減少了業務處理系統的壓力;
隊列長度可以做限制,事實上,秒殺時,后入隊列的用戶無法秒殺到商品,這些請求可以直接被拋棄,返回活動已結束或商品已售完信息;
2.4 日志處理
日志處理是指將消息隊列用在日志處理中,比如Kafka的應用,解決大量日志傳輸的問題。架構簡化如下:
消息隊列應用於日志處理的架構
日志采集客戶端:負責日志數據采集,定時寫受寫入Kafka隊列;
Kafka消息隊列:負責日志數據的接收,存儲和轉發;
日志處理應用:訂閱並消費kafka隊列中的日志數據;
Kafka:接收用戶日志的消息隊列。
Logstash:做日志解析,統一成JSON輸出給Elasticsearch。
Elasticsearch:實時日志分析服務的核心技術,一個schemaless,實時的數據存儲服務,通過index組織數據,兼具強大的搜索和統計功能。
Kibana:基於Elasticsearch的數據可視化組件,超強的數據可視化能力是眾多公司選擇ELK stack的重要原因。
2.5消息通訊
消息通訊是指,消息隊列一般都內置了高效的通信機制,因此也可以用在純的消息通訊。比如實現點對點消息隊列,或者聊天室等。
點對點通訊:
客戶端A和客戶端B使用同一隊列,進行消息通訊。
聊天室通訊:
客戶端A,客戶端B,客戶端N訂閱同一主題,進行消息發布和接收。實現類似聊天室效果。
以上實際是消息隊列的兩種消息模式,點對點或發布訂閱模式,下面會介紹這兩種模式。
3.消息隊列的兩種模式
消息隊列包括兩種模式,點對點模式(point to point, queue)和發布/訂閱模式(publish/subscribe,topic)。
JMS(JAVA Message Service,java消息服務)API是一個消息服務的標准/規范,允許應用程序組件基於JavaEE平台創建、發送、接收和讀取消息。
在JMS標准中,有兩種消息模型P2P(Point to Point),Publish/Subscribe(Pub/Sub)。
3.1 點對點模式
點對點模式下包括三個角色:
消息隊列
發送者 (生產者)
接收者(消費者)
消息發送者生產消息發送到queue中,然后消息接收者從queue中取出並且消費消息。消息被消費以后,queue中不再有存儲,所以消息接收者不可能消費到已經被消費的消息。
點對點模式特點:
每個消息只有一個接收者(Consumer)(即一旦被消費,消息就不再在消息隊列中);
發送者和接收者間沒有依賴性,發送者發送消息之后,不管有沒有接收者在運行,都不會影響到發送者下次發送消息;
接收者在成功接收消息之后需向隊列應答成功,以便消息隊列刪除當前接收的消息;
3.2 發布/訂閱模式
發布/訂閱模式下包括三個角色:
角色主題(Topic)
發布者(Publisher)
訂閱者(Subscriber)
發布者將消息發送到Topic,系統將這些消息傳遞給多個訂閱者。
發布/訂閱模式特點:
每個消息可以有多個訂閱者;
發布者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須創建一個訂閱者之后,才能消費發布者的消息。
為了消費消息,訂閱者需要提前訂閱該角色主題,並保持在線運行;
4.消息中間件案例
3.1電商系統
消息隊列采用高可用,可持久化的消息中間件。比如Active MQ,Rabbit MQ,Rocket Mq。
(1)應用將主干邏輯處理完成后,寫入消息隊列。消息發送是否成功可以開啟消息的確認模式。(消息隊列返回消息接收成功狀態后,應用再返回,這樣保障消息的完整性)
(2)擴展流程(發短信,配送處理)訂閱隊列消息。采用推或拉的方式獲取消息並處理。
(3)消息將應用解耦的同時,帶來了數據一致性問題,可以采用最終一致性方式解決。比如主數據寫入數據庫,擴展應用根據消息隊列,並結合數據庫方式實現基於消息隊列的后續處理。
3.2日志收集系統
分為Zookeeper注冊中心,日志收集客戶端,Kafka集群和Storm集群(OtherApp)四部分組成。
Zookeeper注冊中心,提出負載均衡和地址查找服務;
日志收集客戶端,用於采集應用系統的日志,並將數據推送到kafka隊列;
Kafka集群:接收,路由,存儲,轉發等消息處理;
Storm集群:與OtherApp處於同一級別,采用拉的方式消費隊列中的數據;
5.常用消息隊列介紹
5.1.ZeroMQ
ZeroMQ號稱是“史上最快的消息隊列”,基於c語言開發的,可以在任何平台通過任何代碼連接,通過inproc、IPC、TCP、TIPC、多播傳送消息,支持發布-訂閱、推-拉、共享隊列等模式,高速異步I/O引擎。
根據官方的說法,ZeroMQ是一個簡單好用的傳輸層,像框架一樣的可嵌入的socket類庫,使Socket編程更加簡單、簡潔、性能更高,是專門為高吞吐量/低延遲的場景開發的。ZeroMQ與其他MQ有着本質的區別,它根本不是消息隊列服務器,更類似與一個底層網絡通訊庫,對原有Socket API進行封裝,在使用的使用引入對應的jar包即可,可謂是相當靈活。
同時,因為它的簡單靈活,如果我們想作為消息隊列使用的話,需要開發大量代碼。而且,ZeroMQ不支持消息持久化,其定位並不是安全可靠的消息傳輸,所以還需要自己編碼保證可靠性。簡而言之一句話,ZeroMQ很強大,但是想用好需要自己實現。
特點是:
高性能,非持久化;
跨平台:支持Linux、Windows、OS X等。
多語言支持; C、C++、Java、.NET、Python等30多種開發語言。
可單獨部署或集成到應用中使用;
可作為Socket通信庫使用。
與RabbitMQ相比,ZMQ並不像是一個傳統意義上的消息隊列服務器,它像一個底層的網絡通訊庫,在Socket API之上做了一層封裝,將網絡通訊、進程通訊和線程通訊抽象為統一的API接口。支持“Request-Reply “,”Publisher-Subscriber“,”Parallel Pipeline”三種基本模型和擴展模型。
ZeroMQ高性能設計要點:
1、無鎖的隊列模型
對於跨線程間的交互(用戶端和session)之間的數據交換通道pipe,采用無鎖的隊列算法CAS;在pipe兩端注冊有異步事件,在讀或者寫消息到pipe的時,會自動觸發讀寫事件。
2、批量處理的算法
對於傳統的消息處理,每個消息在發送和接收的時候,都需要系統的調用,這樣對於大量的消息,系統的開銷比較大,zeroMQ對於批量的消息,進行了適應性的優化,可以批量的接收和發送消息。
3、多核下的線程綁定,無須CPU切換
區別於傳統的多線程並發模式,信號量或者臨界區, zeroMQ充分利用多核的優勢,每個核綁定運行一個工作者線程,避免多線程之間的CPU切換開銷。
5.2 ActiveMQ
ActiveMQ是由Apache出品,ActiveMQ 是一個完全支持JMS1.1和J2EE 1.4規范的 JMS Provider實現。它非常快速,支持多種語言的客戶端和協議,而且可以非常容易的嵌入到企業的應用環境中,並有許多高級功能。
主要特性:
服從 JMS 規范:JMS 規范提供了良好的標准和保證,包括:同步或異步的消息分發,一次和僅一次的消息分發,消息接收和訂閱等等。遵從 JMS 規范的好處在於,不論使用什么 JMS 實現提供者,這些基礎特性都是可用的;
連接性:ActiveMQ 提供了廣泛的連接選項,支持的協議有:HTTP/S,IP 多播,SSL,STOMP,TCP,UDP,XMPP等等。對眾多協議的支持讓 ActiveMQ 擁有了很好的靈活性。
支持的協議種類多:OpenWire、STOMP、REST、XMPP、AMQP ;
持久化插件和安全插件:ActiveMQ 提供了多種持久化選擇。而且,ActiveMQ 的安全性也可以完全依據用戶需求進行自定義鑒權和授權;
支持的客戶端語言種類多:除了 Java 之外,還有:C/C++,.NET,Perl,PHP,Python,Ruby;
代理集群:多個 ActiveMQ 代理可以組成一個集群來提供服務;
異常簡單的管理:ActiveMQ 是以開發者思維被設計的。所以,它並不需要專門的管理員,因為它提供了簡單又使用的管理特性。有很多中方法可以監控 ActiveMQ 不同層面的數據,包括使用在 JConsole 或者 ActiveMQ 的Web Console 中使用 JMX,通過處理 JMX 的告警消息,通過使用命令行腳本,甚至可以通過監控各種類型的日志。
使用ActiveMQ需要:
Java JDK
ActiveMQ安裝包
ActiveMQ可以運行在Java語言所支持的平台之上。
優點:
跨平台(JAVA編寫與平台無關有,ActiveMQ幾乎可以運行在任何的JVM上)
可以用JDBC:可以將數據持久化到數據庫。雖然使用JDBC會降低ActiveMQ的性能,但是數據庫一直都是開發人員最熟悉的存儲介質。將消息存到數據庫,看得見摸得着。而且公司有專門的DBA去對數據庫進行調優,主從分離;
支持JMS :支持JMS的統一接口;
支持自動重連;
有安全機制:支持基於shiro,jaas等多種安全配置機制,可以對Queue/Topic進行認證和授權。
監控完善:擁有完善的監控,包括Web Console,JMX,Shell命令行,Jolokia的REST API;
界面友善:提供的Web Console可以滿足大部分情況,還有很多第三方的組件可以使用,如hawtio;
缺點:
社區活躍度不及RabbitMQ高;
根據其他用戶反饋,會出莫名其妙的問題,會丟失消息;
目前重心放到activemq6.0產品-apollo,對5.x的維護較少;
不適合用於上千個隊列的應用場景;
5.3.RabbitMQ
概述:
RabbitMQ是流行的開源消息隊列系統,用erlang語言開發。
RabbitMQ是AMQP(高級消息隊列協議)的標准實現。
支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX,持久化。
用於在分布式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。
主要特性:
可靠性:提供了多種技術可以讓你在 性能 和 可靠性 之間進行 權衡。這些技術包括 持久性機制、投遞確認、發布者證實 和 高可用性機制;
靈活的路由:消息在到達隊列前是通過 交換機 進行 路由 的。RabbitMQ 為典型的路由邏輯提供了 多種內置交換機 類型。如果你有更復雜的路由需求,可以將這些交換機組合起來使用,你甚至可以實現自己的交換機類型,並且當做 RabbitMQ 的 插件 來使用;
消息集群:在相同局域網中的多個 RabbitMQ 服務器可以 聚合 在一起,作為一個獨立的邏輯代理來使用;
隊列高可用:隊列可以在集群中的機器上 進行鏡像,以確保在硬件問題下還保證 消息安全;
支持多種協議:支持 多種消息隊列協議;
支持多種語言:用 Erlang 語言編寫,支持只要是你能想到的 所有編程語言;
管理界面: RabbitMQ 有一個易用的 用戶界面,使得用戶可以 監控 和 管理 消息 Broker 的許多方面;
跟蹤機制:如果 消息異常,RabbitMQ 提供消息跟蹤機制,使用者可以找出發生了什么;
插件機制:提供了許多 插件,來從多方面進行擴展,也可以編寫自己的插件。
優點:
由於erlang語言的特性,mq 性能較好,高並發;
健壯、穩定、易用、跨平台、支持多種語言、文檔齊全;
有消息確認機制和持久化機制,可靠性高;
高度可定制的路由;
管理界面較豐富,在互聯網公司也有較大規模的應用;
社區活躍度高;
缺點:
盡管結合erlang語言本身的並發優勢,性能較好,但是不利於做二次開發和維護;
實現了代理架構,意味着消息在發送到客戶端之前可以在中央節點上排隊。此特性使得RabbitMQ易於使用和部署,但是使得其運行速度較慢,因為中央節點增加了延遲,消息封裝后也比較大;
需要學習比較復雜的接口和協議,學習和維護成本較高;
重要概念:
Broker:簡單來說就是消息隊列服務器實體。
Exchange:消息交換機,它指定消息按什么規則,路由到哪個隊列。
Queue:消息隊列載體,每個消息都會被投入到一個或多個隊列。
Binding:綁定,它的作用就是把Exchange和Queue按照路由規則綁定起來。
Routing Key:路由關鍵字,Exchange根據這個關鍵字進行消息投遞。
vhost:虛擬主機,一個broker里可以開設多個vhost,用作不同用戶的權限分離。
producer:消息生產者,就是投遞消息的程序。
consumer:消息消費者,就是接受消息的程序。
channel:消息通道,在客戶端的每個連接里,可建立多個channel,每個channel代表一個會話任務。
消息隊列的使用過程,如下:
客戶端連接到消息隊列服務器,打開一個channel。
客戶端聲明一個exchange,並設置相關屬性。
客戶端聲明一個queue,並設置相關屬性。
客戶端使用routing key,在exchange和queue之間建立好綁定關系。
客戶端投遞消息到exchange。
5.4.RocketMQ
RocketMQ出自 阿里公司的開源產品,用 Java 語言實現,在設計時參考了 Kafka,並做出了自己的一些改進,消息可靠性上比 Kafka 更好。RocketMQ在阿里集團被廣泛應用在訂單,交易,充值,流計算,消息推送,日志流式處理,binglog分發等場景。
主要特性:
是一個隊列模型的消息中間件,具有高性能、高可靠、高實時、分布式特點;
Producer、Consumer、隊列都可以分布式;
Producer向一些隊列輪流發送消息,隊列集合稱為Topic,Consumer如果做廣播消費,則一個consumer實例消費這個Topic對應的所有隊列,如果做集群消費,則多個Consumer實例平均消費這個topic對應的隊列集合;
能夠保證嚴格的消息順序;
提供豐富的消息拉取模式;
高效的訂閱者水平擴展能力;
實時的消息訂閱機制;
億級消息堆積能力;
較少的依賴;
使用RocketMQ需要:
Java JDK
安裝git、Maven
RocketMQ安裝包
RocketMQ可以運行在Java語言所支持的平台之上。
優點:
單機支持 1 萬以上持久化隊列
RocketMQ 的所有消息都是持久化的,先寫入系統 PAGECACHE,然后刷盤,可以保證內存與磁盤都有一份數據,訪問時,直接從內存讀取。
模型簡單,接口易用(JMS 的接口很多場合並不太實用);
性能非常好,可以大量堆積消息在broker中;
支持多種消費,包括集群消費、廣播消費等。
各個環節分布式擴展設計,主從HA;
開發度較活躍,版本更新很快。
缺點:
支持的客戶端語言不多,目前是java及c++,其中c++不成熟;
RocketMQ社區關注度及成熟度也不及前兩者;
沒有web管理界面,提供了一個CLI(命令行界面)管理工具帶來查詢、管理和診斷各種問題;
沒有在 mq 核心中去實現JMS等接口;
5.5 Kafka
Apache Kafka是一個分布式消息發布訂閱系統。它最初由LinkedIn公司基於獨特的設計實現為一個分布式的提交日志系統( a distributed commit log),,之后成為Apache項目的一部分。Kafka系統快速、可擴展並且可持久化。它的分區特性,可復制和可容錯都是其不錯的特性。
主要特性:
快速持久化,可以在O(1)的系統開銷下進行消息持久化;
高吞吐,在一台普通的服務器上既可以達到10W/s的吞吐速率;
.完全的分布式系統,Broker、Producer、Consumer都原生自動支持分布式,自動實現負載均衡;
支持同步和異步復制兩種HA;
支持數據批量發送和拉取;
zero-copy:減少IO操作步驟;
數據遷移、擴容對用戶透明;
無需停機即可擴展機器;
其他特性:嚴格的消息順序、豐富的消息拉取模型、高效訂閱者水平擴展、實時的消息訂閱、億級的消息堆積能力、定期刪除機制;
使用Kafka需要:
Java JDK
Kafka安裝包
優點:
客戶端語言豐富,支持java、.net、php、ruby、python、go等多種語言;
性能卓越,單機寫入TPS約在百萬條/秒,消息大小10個字節;
提供完全分布式架構, 並有replica機制, 擁有較高的可用性和可靠性, 理論上支持消息無限堆積;
支持批量操作;
消費者采用Pull方式獲取消息, 消息有序, 通過控制能夠保證所有消息被消費且僅被消費一次;
有優秀的第三方Kafka Web管理界面Kafka-Manager;
在日志領域比較成熟,被多家公司和多個開源項目使用;
缺點:
Kafka單機超過64個隊列/分區,Load會發生明顯的飆高現象,隊列越多,load越高,發送消息響應時間變長
使用短輪詢方式,實時性取決於輪詢間隔時間;
消費失敗不支持重試;
支持消息順序,但是一台代理宕機后,就會產生消息亂序;
社區更新較慢;
5.6 Apollo
Apache稱Apollo為最快、最強健的STOMP服務器。支持STOMP、AMQP、MQTT、OpenWire協議,支持Topic、Queue、持久訂閱等消費形式,支持對消息的多種處理,支持安全性處理,支持REST管理API。。。功能列表很長,最大的弊病就是目前市場接收度不夠,所以使用的並不廣泛。
6. RabbitMQ/ActiveMQ/RocketMQ/Kafka對比
結論:
Kafka在於分布式架構,RabbitMQ基於AMQP協議來實現,RocketMQ/思路來源於kafka,改成了主從結構,在事務性可靠性方面做了優化。廣泛來說,電商、金融等對事務性要求很高的,可以考慮RabbitMQ和RocketMQ,對性能要求高的可考慮Kafka。
7.消息隊列MQ選型
綜合上面的材料得出以下兩點:
(1)中小型軟件公司:
建議選RabbitMQ
erlang語言天生具備高並發的特性,而且他的管理界面用起來十分方便。正所謂,成也蕭何,敗也蕭何!他的弊端也在這里,雖然RabbitMQ是開源的,然而國內有幾個能定制化開發erlang的程序員呢?所幸,RabbitMQ的社區十分活躍,可以解決開發過程中遇到的bug,這點對於中小型公司來說十分重要。
不考慮rocketmq和kafka的原因是,一方面中小型軟件公司不如互聯網公司,數據量沒那么大,選消息中間件,應首選功能比較完備的,所以kafka排除。不考慮rocketmq的原因是,rocketmq是阿里出品,如果阿里放棄維護rocketmq,中小型公司一般抽不出人來進行rocketmq的定制化開發,因此不推薦。
(2)大型軟件公司:
根據具體使用在rocketMq和kafka之間二選一。
大型軟件公司,具備足夠的資金搭建分布式環境,也具備足夠大的數據量。針對rocketMQ,大型軟件公司也可以抽出人手對rocketMQ進行定制化開發,畢竟國內有能力改JAVA源碼的人,還是相當多的。
至於kafka,根據業務場景選擇,如果有日志采集功能,肯定是首選kafka了。具體該選哪個,看使用場景。
————————————————
版權聲明:本文為CSDN博主「非攻_平凡」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/acaoye/article/details/82967172