RabbitMQ簡(jiǎn)介
消息中間件的作用:
- 解耦
- 冗余(存儲(chǔ))
- 拓展性
- 削峰
- 可恢復(fù)性:處理消息的機(jī)器宕機(jī)之后,消息中間件可以存儲(chǔ)消息
- 順序保證
- 緩沖
- 異步通信:消息中間件可以延遲消費(fèi)
RabbitMQ具體特點(diǎn):
- 可靠性:消息確認(rèn)發(fā)布、傳輸確認(rèn),持久化
- 靈活的路由
- 拓展性:可以拓展為集群
- 高可用:可以設(shè)置隊(duì)列鏡像,單一RabbitMQ掛機(jī)后,有鏡像提供服務(wù)
- 多種協(xié)議
- 多語(yǔ)言客戶端
- 管理界面
- 插件機(jī)制
RabbitMQ入門

RabbitMQ的模型架構(gòu)如圖,生產(chǎn)者Publisher通過TCP連接Connnection與RabbitMQ服務(wù)器Broker連接,每個(gè)Connection中有多個(gè)Channel。Broker服務(wù)器中有多個(gè)Virtual Host,每個(gè)Virtual Host各自獨(dú)立。Publisher發(fā)布消息Message到Exchange交換器,Message包含label(路由鍵)+payload(消息體),Binding上帶有綁定鍵,交換器根據(jù)自身性質(zhì)和路由鍵和綁定鍵決定將消息投遞到哪里。最終消息被保存在Queue隊(duì)列中,Consumer監(jiān)聽隊(duì)列獲得消息。
注意:
- 生產(chǎn)者將消息傳到交換器后,交換器根據(jù)自身交換器類型和路由鍵、綁定鍵決定消息投遞的方向。
- 只有隊(duì)列能存儲(chǔ)消息,消息到達(dá)隊(duì)列時(shí)已沒有l(wèi)abel了,只剩下消息體
- 當(dāng)多個(gè)Consumer連接到同一個(gè)隊(duì)列時(shí),隊(duì)列上的消息將輪詢發(fā)給每個(gè)Consumer而不是每個(gè)消息復(fù)制多份發(fā)給每個(gè)Consumer,即每個(gè)消息只能被成功消費(fèi)一次
AMQP協(xié)議

如上圖,AMQP協(xié)議每次發(fā)送數(shù)據(jù)時(shí)的指令。
客戶端開發(fā)向?qū)?/h2>
本章講了RabbitMQ Java客戶端的開發(fā),只摘錄我的部分理解在此。
創(chuàng)建RabbitMQ各個(gè)組件時(shí)可以有不同的參數(shù)。
- Exchange交換器:type類型、durable是否持久化(持久化的Exchange重啟時(shí)不會(huì)消失),autoDelete自動(dòng)刪除(當(dāng)Exchange所綁定的queue都刪除后,自動(dòng)刪除Exchange,默認(rèn)不自動(dòng)刪除),internal是否內(nèi)置(若是,客戶端程序無(wú)法發(fā)信息到此交換器,只有交換器能發(fā)到此交換器)
- queue隊(duì)列:durable是否持久化、exclusive排他(同Connection可見,其他Conntection不能創(chuàng)建同名隊(duì)列,Connection斷掉自動(dòng)刪除)、autoDelete自動(dòng)刪除(有消費(fèi)者訂閱過此隊(duì)列,之后所有消費(fèi)者取消訂閱,則刪除,生產(chǎn)者創(chuàng)建隊(duì)列后無(wú)客戶端連接是不會(huì)刪除的)
RabbitMQ的消息存儲(chǔ)在隊(duì)列中,交換器的使用并不真正耗費(fèi)服務(wù)器的性能,而隊(duì)列會(huì)。衡量RabbitMQ的QPS只需看隊(duì)列即可。
- 消息投遞模式:發(fā)送消息處理指明交換器和路由鍵,還可以指定消息的一些屬性,如投遞模式為2時(shí),消息可持久化??梢栽O(shè)置消息的優(yōu)先級(jí)。
- 消費(fèi)消息:有兩種模式,推模式Push和拉模式pull。消費(fèi)消息時(shí)可以設(shè)置是否自動(dòng)確認(rèn)。當(dāng)然,消息發(fā)送方也可以設(shè)置發(fā)送確認(rèn),RabbitMQ的exchange收到消息時(shí)可以回調(diào)發(fā)送方設(shè)置的監(jiān)聽。
消費(fèi)端的確認(rèn)和拒絕:消息訂閱有推和拉兩種模式,訂閱時(shí)可以設(shè)置是否自動(dòng)確認(rèn),自動(dòng)確認(rèn)的消息在RabbitMQ將消息發(fā)出時(shí)移除,非自動(dòng)確認(rèn)的消息需要客戶端手動(dòng)確認(rèn)。也可以拒絕該消息,拒絕時(shí)傳遞一個(gè)requeue參數(shù),可以設(shè)置是否將該消息重洗入隊(duì)等待發(fā)送,或者將其移除。
RabbitMQ進(jìn)階
本章講的是RabbitMQ的高級(jí)功能。
- 交換器的屬性:
- mandatory屬性為true時(shí),交換器如果找不到消息的路由,會(huì)將消息返回生產(chǎn)者,為false則丟棄
- immediate參數(shù)為true時(shí),當(dāng)路由器發(fā)現(xiàn)隊(duì)列中不存在任何消費(fèi)者,則不投遞到該隊(duì)列。若所有隊(duì)列都無(wú)消費(fèi)者,則將消息返回生產(chǎn)者。RabbitMQ 3.0去掉了該屬性。
備份交換器AE:
- 當(dāng)mandatory為true時(shí),無(wú)法路由的消息會(huì)返回生產(chǎn)者,為false時(shí),無(wú)法路由的消息會(huì)被丟棄。除了這兩者,還可以為交換器設(shè)置備份交換器,當(dāng)消息無(wú)法路由時(shí),會(huì)發(fā)送到備份交換器,備份交換器和mandatory一起使用,該參數(shù)無(wú)效。
過期時(shí)間TTL
- 過期時(shí)間可以設(shè)置在隊(duì)列,也可以單獨(dú)設(shè)置在消息。一旦消息過期,就會(huì)變成“死信”。對(duì)于設(shè)置隊(duì)列的TTL,一旦消息過期則從隊(duì)列中抹去,而對(duì)于單獨(dú)設(shè)置TTL的消息,過期后不會(huì)馬上抹去,而是在消息投遞給消費(fèi)者之前判斷的。
死信交互器DLX(也稱死信隊(duì)列):
- 當(dāng)消息變?yōu)樗佬胖?,他能被發(fā)送到死信交換器。
- TTL和DLX可以做延時(shí)隊(duì)列

持久化,RabbitMQ分為三部分:
- 交換器持久化:交換器不持久化的話,重啟后元數(shù)據(jù)丟失,但消息不會(huì)丟失,因?yàn)橄⒋嬖陉?duì)列中
- 隊(duì)列持久化:隊(duì)列不持久化的話,重啟后隊(duì)列會(huì)消失,消息也消失
- 消息持久化:如果消息不持久化,那么重啟時(shí)消息會(huì)丟失,隊(duì)列持久化只能保證隊(duì)列的元數(shù)據(jù)不丟失,不能保證消息不丟失。
消息的可靠性:
- 生產(chǎn)者確認(rèn):默認(rèn)情況下,生產(chǎn)者發(fā)送消息后不知道消息是否到達(dá)了RabbtMQ服務(wù)器??梢酝ㄟ^兩種方式確認(rèn)
- 事務(wù)機(jī)制:如channel.txSelect將channel設(shè)置為事務(wù)模式,每次發(fā)送消息前都需要發(fā)送事務(wù)指令,嚴(yán)重影響性能
- 發(fā)送方確認(rèn):類似tcp批量確認(rèn),每個(gè)消息都編號(hào),RabbitMQ會(huì)確認(rèn)一個(gè)序號(hào)表示這個(gè)序號(hào)之前的消息都已確認(rèn)。相比上面的事務(wù)機(jī)制,這里是異步的,而事務(wù)是同步確認(rèn)每一條消息的。
- 當(dāng)然,生產(chǎn)者確認(rèn)只能保證消息傳遞到了服務(wù)器的交換器。如果消息沒有匹配的隊(duì)列,那么消息也會(huì)丟失,發(fā)送方可以配合mandatory參數(shù)或備份交換器解決沒有匹配隊(duì)列時(shí)的處理方式。
- 消費(fèi)端要點(diǎn):默認(rèn)隊(duì)列中的消息會(huì)輪詢分發(fā)到訂閱同一隊(duì)列的消費(fèi)者,RabbitMQ并不管消費(fèi)者是否確認(rèn)了該消息,這會(huì)造成性能差的服務(wù)器處理過慢。可以使用channel.basicQos設(shè)定每個(gè)消費(fèi)者最多持有未確認(rèn)的消息數(shù)量,這種機(jī)制類似tcp的滑動(dòng)窗口,這種機(jī)制對(duì)于拉模式的消息消費(fèi)無(wú)效。
- 消息順序性:消息的順序性是從存入隊(duì)列是開始的,不能認(rèn)為是從生產(chǎn)者發(fā)送時(shí)開始的,因?yàn)橛芯W(wǎng)絡(luò)抖動(dòng)。
- 消息傳輸保障:
- 最多一次:生產(chǎn)者隨意發(fā)送,消費(fèi)者隨意消費(fèi)
- 最少一次:生產(chǎn)者開啟發(fā)送確認(rèn),生產(chǎn)者需要使用mandatory參數(shù)或備份交換器確保消息無(wú)法路由時(shí)能保存到隊(duì)列。消息和隊(duì)列都需要進(jìn)行持久化。消費(fèi)者需要手動(dòng)確認(rèn)消息。
- 恰好一次:無(wú)法保證消息恰好一次被消費(fèi),因?yàn)榫W(wǎng)絡(luò)原因,消費(fèi)者消費(fèi)之后發(fā)送確認(rèn)消息時(shí)剛好網(wǎng)絡(luò)斷開,連接重新建立時(shí)消費(fèi)者會(huì)重新消費(fèi)到消息。RabbitMQ無(wú)法保證恰好一次,不僅RabbitMQ目前大多數(shù)主流的中間件都無(wú)法保證恰好一次。
RabbitMQ管理
RabbitMQ的應(yīng)用工具:
- rabbitmqctl:命令行工具
- rabbitmq_management插件:圖形化插件
多租戶與權(quán)限
- 添加vhost:rabbitmqctl add_vhost myhost
- 顯示vhost:rabbitmqctl list_vhosts
- 刪除vhost:rabbitmqctl delete_host myhost
- 權(quán)限配置到vhost:rabbitmqctl set_permissions [-p vhost] {user} {conf} {write} {read},如授予root用戶可訪問虛擬主機(jī)myhost并具備所有權(quán)限
rabbitmqctl set_permissions -p myhost root ".*" ".*" ".*" - 清除權(quán)限:rabbitmqctl clear_permissions [-p vhost] {user}
- 查看權(quán)限:rabbitmqctl list_user_permissions {user}
用戶管理
- 創(chuàng)建用戶:rabbitmqctl add_user {username} {password}
- 改密碼:rabbitmqctl change_password {username} {password}
- 清除密碼:rabbitmqctl clear_password {username} {password}
- 驗(yàn)證密碼:rabbitmqctl authenticate_user {username} {password}
- 刪除用戶:rabbitmqctl delete_user {username}
- 查看用戶:rabbitmqctl list_users
- 設(shè)置角色:rabbitmqctl set_user_tags {username} {tags...}
用戶分為五種角色:
- none:無(wú)任何角色,新創(chuàng)建的用戶默認(rèn)為none角色
- management:可以訪問web管理頁(yè)面
- policymaker:包含management的所有權(quán)限,并可以管理策略和參數(shù)
- monitoring:包含management的所有權(quán)限,并可以看到所有連接、信道和結(jié)點(diǎn)
- administrator:管理員
web端管理
- 啟動(dòng)插件命令:rabbitmq-plugins enable rabbitmq_management
- 查看插件使用情況:rabbitmq-plugins list
應(yīng)用與集群管理
- 停止服務(wù):rabbitmqctl stop,rabbitmqctl stop_app,rabbitmqctl shutdown
- 重置:rabbitmqctl reset還原rabbitmq到最初狀態(tài)
vhost、權(quán)限等都可以使用rabbitmqctl來(lái)創(chuàng)建,但交換器、隊(duì)列和綁定關(guān)系卻無(wú)法用rabbitmqctl來(lái)創(chuàng)建,只能通過web管理界面創(chuàng)建。然而,rabbitmq management還提供了命令行rabbitmqadmin來(lái)解決這個(gè)問題。如查看隊(duì)列中的消息
rabbitmqadmin get queue=myqueue
rabbitmq management還提供了http api接口來(lái)方便調(diào)用。如創(chuàng)建一個(gè)隊(duì)列,可以使用PUT方法調(diào)用/api/queues/vhost/name接口來(lái)實(shí)現(xiàn)。
RabbitMQ配置
三種方式配置:
- 環(huán)境變量:如RABBITMQ_NODENAME=rabbit@node2 rabbitmq-server -detached,環(huán)境變量也可配置在
RABBITMQ_HOME/etc/rabbitmq/rabbitmq-env.conf中 - 配置文件:配置文件位于/opt/rabbitmq/etc/rabbitmq/rabbitmq.config
- 運(yùn)行時(shí)參數(shù)和策略:可以通過rabbitmqctl或management插件提供的http api來(lái)設(shè)置,如rabbitmqctl set_parameter
RabbitMQ運(yùn)維
本章主要將集群的搭建和運(yùn)維
跨越集群的界限
RabbitMQ可以通過3種方式實(shí)現(xiàn)分布式部署:
- 集群
- Federation:該插件的目的是使RabbitMQ在不同的Broker結(jié)點(diǎn)之間進(jìn)行消息通信而無(wú)需創(chuàng)建集群
- Shovel:該插件能夠可靠、持續(xù)地從一個(gè)Broker中的隊(duì)列拉取數(shù)據(jù)并轉(zhuǎn)發(fā)至另一個(gè)Broker中的交換器。
RabbitMQ高階
本章是將RabbitMQ的內(nèi)部原理的,需要熟悉
流控
RabbitMQ可以對(duì)內(nèi)存和磁盤使用量設(shè)置閾值,達(dá)到閾值后,生產(chǎn)者將阻塞。這是全局流控,面向所有連接的。當(dāng)然RabbitMQ也可以面向單個(gè)Connection進(jìn)行流控。
RabbitMQ使用一種基于信用證算法的流控機(jī)制來(lái)限制發(fā)送消息的速率。
鏡像隊(duì)列
生產(chǎn)者發(fā)送消息時(shí),會(huì)將消息都發(fā)送到各個(gè)slave,除發(fā)送消息外的所有動(dòng)作都只會(huì)向master發(fā)送,然后再由master將命令執(zhí)行的結(jié)果廣播給各個(gè)slave。
網(wǎng)絡(luò)分區(qū)
在局域網(wǎng)環(huán)境下,網(wǎng)絡(luò)設(shè)備出現(xiàn)故障時(shí)也會(huì)導(dǎo)致網(wǎng)絡(luò)分區(qū)。當(dāng)出現(xiàn)網(wǎng)絡(luò)分區(qū)時(shí),不同分區(qū)里的結(jié)點(diǎn)會(huì)認(rèn)為不屬于自身所在分區(qū)的結(jié)點(diǎn)都已經(jīng)掛了。如果原集群中配置了鏡像隊(duì)列,每個(gè)網(wǎng)絡(luò)分區(qū)中都會(huì)出現(xiàn)一個(gè)master結(jié)點(diǎn)。
RabbitMQ拓展
消息追蹤:Firehose
負(fù)載均衡:輪詢、加權(quán)輪詢、隨機(jī)、加權(quán)隨機(jī)、源地址哈希、最小連接數(shù)
使用HAProxy實(shí)現(xiàn)負(fù)載均衡
使用Keepalived實(shí)現(xiàn)高考可靠負(fù)載均衡
使用keepalived+LVS實(shí)現(xiàn)負(fù)載均衡