Rabbitmq踩的坑以及一些總結記錄

首先說說最近使用rabbitmq踩的坑,rabbitmq是基於erlang語言所寫,所以下載使用rabbitmq的時候要先下載erlang 同時配置其環境變量。但是window系統下載rabbitmq和erlang耗時極其長,安裝使用後,可能還會出現localhost:15672訪問不了的情況,所以建議在VM虛擬機上使用centos7系統,安裝docker,然後直接拉取rabbitmq鏡像,幾分鐘就搞定了。

接下來進入主題,首先擺出幾個概念:
RabbitMq首先是基於AMQP協議(高級消息隊列協議),​ AMQP,即Advanced Message Queuing Protocol,一個提供統一消息服務的應用層標準高級消息隊列協議,是應用層協議的一個開放標準,爲面向消息的中間件設計。基於此協議的客戶端與消息中間件可傳遞消息,並不受客戶端/中間件同產品(中間件:比如rabbitmq),不同的開發語言等條件的限制。erlang:是一種語言(我也不瞭解)主要是三個特性: 高併發、高容錯、軟實時

大致的概念看完了,接下來進入關鍵問題了,爲何我們要使用消息隊列呢?
原因有三:
1、異步處理:可以提高系統的吞吐量,同一時間系統可以處理更多問題,而不會卡在一處地方。
2、解耦:系統與系統之間通過消息隊列來傳遞消息,減少了系統之間的耦合度,無需知道其他系統的實現細節,反正我消息發出去就完事了。
3、流量削鋒:可以通過控制消息的長度來控制請求的數量,緩解短時間內系統的高併發請求。
但是任何東西有利有弊,消息隊列雖然方便,但是明顯的我們一但使用消息隊列,就說明我們還要寫消息隊列的代碼,這不就增加了代碼的複雜度。其二、消息隊列一旦掛了呢,系統之間還靠什麼來交互。

RabbitMQ的基本概念
Broker:消息隊列服務器實體,裏面存放交換機和隊列
Exchange:消息交換機,就是把你發送的消息路由到哪個隊列
Queue:消息隊列載體,每個消息都會被投入到一個或者多個隊列
Binding:綁定,作用是把exchange和queue按照路由規則綁定起來
Routing Key:路由關鍵字,exchange根據這個關鍵字進行消息投遞
VHost:可以理解爲虛擬broker,其內部均含有獨立的queue、exchange和binding。重點在於它擁有獨立的權限系統。
Producer:消息生產者
Consumer:消息消費者
Channel:消息通道,每個消息通道相當於一個會話任務Exchange到Queue的唯一線路需要由Exchange和Queue以及RoutingKey來決定
接下來看看rabbitMq的工作模式Rabbitmq的工作模式
1、simple模式(即爲最簡單的收發模式)
在這裏插入圖片描述
生產者發送消息到隊列裏面,不足:有可能造成消息的丟失
2、work工作模式(資源的競爭)
在這裏插入圖片描述
消息放入隊列,有多個消費者,消費者會競爭消息,不足:高併發下某個消息可能會被多個消費者同時使用,可以設置一個開關(synchronized)
3、publish/subscribe發佈訂閱(共享資源)
在這裏插入圖片描述
(1)、每個消費者監聽自己的隊列(2)、生產者將消息發給broker,由交換機將消息轉發到綁定到交換機的每個隊列,每個綁定交換機的隊列都將接受到消息
4、路由模式
在這裏插入圖片描述
創建消息的時候同時設置一個路由,生產者把消息發送給交換機的時候,交換機根據消息的路由信息,找到對應的路由綁定的隊列,並把消息發送到對應隊列上
5、topic主題模式(路由模式的一種)支持通配符,模糊匹配
在這裏插入圖片描述
6、RPC模式
在這裏插入圖片描述
關於MQ的一些思考
保證RabbitMQ消息的順序性?有兩種方案:1 是拆分爲多個queue,每個queue對應一個consumer,這樣就不會出現一個隊列裏面的消息被多個消費者消費,導致消息順序不對問題。2、就一個queue對應一個consumer消息如何分發?首先要保證消息至少有一個消費者訂閱,消息將以循環的方式發送給消費者,每條消息只會分發給一個訂閱的消費者(前提是消費者能夠正常處理消息並進行確認)

消息如何路由?消息在創建的時候要設置路由鍵,隊列也通過路由鍵綁定到交換機上,這樣消息到達交換機上的時候,交換機會根據路由鍵來決定你的消息發送到哪個隊列上面去(不同的路由機有不同的規則)常用的有以下三種:fanout:如果交換器收到消息,將會廣播到所有綁定的隊列上direct:如果路由鍵完全匹配,消息就會被投遞到相應的隊列topic:可以使來自不同源頭的消息到達同一個隊列,使用topic交換器的時候,可以使用通配符

消息基於什麼傳輸? TCP的創建與連接消耗很大,所以RabbitMQ使用信道的方式來傳輸數據,信道是建立在真實TCP連接內的虛擬連接,每條TCP的連接上信道數量沒有限制

如何保證消息不被重複消費(冪等性)?
重複消費爲何會發生:當消費者消費完信息後,會發送消息告知消息隊列它已經把消息消費了,這個時候消息隊列就會把相應消息給刪除掉。但是這個時候問題就來了,如果消費者發送的這個消費完的消息沒有被消息隊列獲取到,消息隊列就不會把消息刪除,這樣消費者就有可能接受到重複的消息了。解決方案,最好是在消息裏面加入標識,這樣消費者在消費的時候就能夠獲取標識來判斷自己是否已經消費過這個消息,從而能夠避免重複消費

怎麼能夠確保消息正確發送到RabbitMQ,怎麼確保消息接收方消費了消息發送方?:將信道設置爲confirm模式(發送方確認模式),則在所有信道上發佈的消息都會被指派一個唯一的ID 一旦消息被投遞到目的隊列後,或者消息被寫入磁盤後,信道就會發送一個確認給生產者,包含消息的唯一ID,如果rabbitmq內部錯誤導致消息丟失,會發送一條未確認消息給生產方接收方:rabbitmq僅通過和消費者的連接是否中斷來判斷是否需要重新發消息,所以只要連接不中斷,Rabbitmq就不會再給消費者發送消息了

什麼情況下會出現 blackholed 問題?blackholed 問題,向 exchange 投遞了 message ,而由於各種原因導致該message 丟失,但生產者卻不知道。導致 blackholed 的情況:1.向未綁定 queue 的exchange 發送 message;2.exchange 以 rou_tingkey key_A 綁定了 queue queue_A,但向該 exchange 發送 message 使用的 routing_key 卻是 key_B。

持久化機制對於message的利與弊持久化就是把消息寫到磁盤,寫磁盤比寫到內存這個效率就要低很多了,而且也有可能出現上述所說的blackholed問題

RabbitMQ集羣正常來說有三種模式:單機、普通集羣、鏡像集羣 1、單機:基本上就是在自己電腦啓動了玩玩(少用) 2、普通集羣:將rabbitMQ部署到多臺機器上,只創建一個queue去鏈接rabbitmq,但是每個實例都會同步這一個queue的數據。消費者如果連接的不是這個有queue的rabbitmq實例,會把數據從從queue拉取過來,這個方案的本質就是,讓集羣多個節點來服務一個queue。 3、鏡像集羣:這個和第二種的區別就是每個rabbitmq節點都有一個完整的鏡像queue。