消息队列基本知识
什么是消息隊列
消息隊列是一種異步的服務間通信的方式,是分布式系統中重要的組件,主要解決應用的耦合,異步消息,流量削峰等問題,實現高性能,高可用,可伸縮和最終一致性架構的一種技術。
現有各消息隊列性能對比
| 開發語言 | Java | erlang | scala | java | golang |
| 單機吞吐量 | 萬級 | 萬級 | 10萬級 | 10萬級 | 萬級 |
| 時效性 | ms級 | us級 | ms級 | ms級 | - |
| 可用性 | 高(主從) | 高(主從) | 非常高(分布式) | 非常高(分布式) | 非常高(分布式) |
| API完備性 | 高 | 高 | 高 | 高 | 低 |
| 多語言支持 | 支持,Java優先 | 語言無關 | 支持,Java優先 | 支持,Java優先 | 支持 |
| 提供快速入門 | 有 | 有 | 有 | 有 | 無 |
| 功能特性 | 成熟的產品,在很多公司得到應用;有較多的文檔;各種協議支持較好 | 基于erlang開發,所以并發能力很強,性能及其好,延時很低;管理界面教豐富 | MQ功能比較完備,擴展性好 | 只支持主要的MQ功能,像一些消息查詢,消息回溯等功能沒有提供,畢竟是為大數據準備的,在大數據領域應用廣 | 使用golang開發,基于分布式,性能很高,但目前文檔不夠完善,部署比較麻煩 |
關于消息隊列的幾個問題:
1.如何保證消息隊列是高可用的?
- 大多數情況下,我們都是采用集群來保證高可用的,這一點和數據庫其實是一樣的;
- 以RabbitMQ為例,它通常用的兩種集群模式,分別是默認模式,鏡像模式,其中鏡像模式最常用,其中鏡像模式如下圖所示;
- RcoketMQ的集群有多master模式、多master多slave異步復制模式、多master多slaver同步雙寫模式,其中多master多slaver模式部署架構如下
2.如何保證消息不被重復消費?
沒有固定答案,需要根據業務場景來處理以RabbitMQ為例,RabbitMQ不保證消息不重復,如果業務需要保證嚴格的不重復消息,可通過一下方法實現:
- 保證每條消息都有唯一編號且保證消息處理成功與去重表的日志同時出現;
- 拿到這個消息做數據庫的insert操作,給這個消息做一個唯一的主鍵,由于主鍵沖突即可避免重復消費的問題。
3.如何保證消息的可靠性傳輸?
對于消息隊列的可靠性傳輸都應該從三個角度來分析:生產者弄丟數據、消息隊列弄丟數據、消費者弄丟數據,下面以RabbitMQ為例進行說明:
- 生產者丟數據:RabbitMQ提供transaction和confirm模式來確保生產者不丟消息;transaction機制是說發送消息前開啟事務(channel.txSelect()),然后發送消息,如果發送過程中出現什么異常,事務就會回滾(channel.txRollback()),如果發送成功則提交事務(channel.txCommit()),然而缺點是吞吐量下降了,因此在一般情況下,生產環境使用confirm模式的較多,一旦channel進入confirm模式,所有在該信道上發布的消息都將會被指派一個唯一的ID,一旦消息被投遞到所有匹配的隊列之后,RabbitMQ就會發送一個Avk給生產者,這就使得生產者知道消息已經正確到達目的隊列了,如果RabbitMQ沒能處理該消息,則會發送一個Nack消息,這時就可以進行重試操作。
- 消息隊列丟失數據:處理消息隊列丟失數據的情況,一般是開啟持久化磁盤的配置,這個持久化配置可以和confirm機制配合使用,我們可以在消息持久化磁盤后,再給生產者發送一個Ack信號,這樣如果消息持久化磁盤之前,RabbitMQ死了,那么生產者收不到Ack信號,生產者會重發,持久化主要分為兩步:1.將queue的持久化表示durable設置為true,則代表是一個持久的隊列;2.發送消息的時候將deliveryMode=2,這樣設置后,RabbitMQ就算掛了,重啟后也能恢復數據。
- 消費者丟數據:消費者丟數據一般是因為采用了自動確認消息模式,這種模式下消費者自動確認收到消息,這時RabbitMQ會立即將消息刪除,解決方法時手動確認消息即可。
AMQP(Advanced Message Queuing Protocol;高級消息隊列協議)
AMQP核心概念
- Broker:接收和分發消息的應用,RabbitMQ Server就是Message Broker;
- Virtual host:虛擬地址,用于進行邏輯隔離,最上層的消息路由。一個Virtual Host里面可以有若干個Exchange和Queue,同一個Virtual Host里面不能有相同名稱的Exchange或Queue;
- Connection:Publisher / consumer和Broker之間的TCP連接,斷開連接的操作只會在client端進行,Broker不對斷開連接,除非出現網絡故障或Broker服務出現問題;
- Channel:channel表示一個進行消息讀寫的通道,如果每一次訪問RabbitMQ都建立一個Connection,在消息量大的時候建立TCP Connection的開銷將是巨大的,效率也較低,Channel是在connection內部建立的邏輯連接,如果應用程序支持多線程,通常每個thread創建單獨的channel進行通信,AMQP method包含了channel ID幫助客戶端和message broker識別channel,所以channel之間是完全隔離的,Channel作為輕量級的Connection極大減少了操作系統建立TCP connection的開銷;
- Exchange:message到達broker的第一站,根據分發規則,匹配查詢表的routing key ,分發消息到queue中去,通常的類型有:direct(point-to-point), topic(publish-subscribe)
- Queue:消息隊列、消息最終被送到這里等待consumer取走;
- Binding:exchange和queue之間的虛擬連接,binding中可以包含routing key,Binding信息被保存到exchange中的查詢表中,用于message的分發依據。
- Routing key:一個路由規則,虛擬機可用它來確定如何路由一個特定消息;
- Message:消息,服務器和應用程序之間傳送的數據,由Properties和body組成,Properties可以對消息進行修飾,比如消息的優先級、延遲等高級特性;Body則就是消息體內容。
總結
- 上一篇: HTTP中post方法提交不同格式的数据
- 下一篇: 消息队列--RabbitMQ简单使用