一莱坎、Headers路由
在官網(wǎng)的體驗(yàn)示例中,還有一種路由策略并沒(méi)有提及着茸,那就是Headers路由。其實(shí)官網(wǎng)之所以沒(méi)有過(guò)多介紹琐旁,就是因?yàn)檫@種策略在實(shí)際中用得比較少,但是在某些比較特殊的業(yè)務(wù)場(chǎng)景猜绣,還是挺好用的灰殴。
官網(wǎng)示例中的集中路由策略, direct,fanout,topic等這些Exchange掰邢,都是以routingkey為關(guān)鍵字來(lái)進(jìn)行消息路由的牺陶,但是這些Exchange有一個(gè)普遍的局限就是都是只支持一個(gè)字符串的形式,而不支持其他形式辣之。Headers類型的Exchange就是一種忽略routingKey的路由方式掰伸。他通過(guò)Headers來(lái)進(jìn)行消息路由。這個(gè)headers是一個(gè)鍵值對(duì)怀估,發(fā)送者可以在發(fā)送的時(shí)候定義一些鍵值對(duì)狮鸭,接受者也可以在綁定時(shí)定義自己的鍵值對(duì)。當(dāng)鍵值對(duì)匹配時(shí)多搀,對(duì)應(yīng)的消費(fèi)者就能接收到消息歧蕉。匹配的方式有兩種,一種是all康铭,表示需要所有的鍵值對(duì)都滿足才行惯退。另一種是any,表示只要滿足其中一個(gè)鍵值就可以了从藤。而這個(gè)值催跪,可以是List、Boolean等多個(gè)類型夷野。
關(guān)于Headers路由的示例懊蒸,首先在Web管理頁(yè)面上,可以看到默認(rèn)創(chuàng)建了一個(gè)amqp.headers這樣的Exchange交換機(jī)悯搔,這個(gè)就是Headers類型的路由交換機(jī)榛鼎。然后關(guān)于Headers路由的示例,可以查看示例代碼鳖孤。BasicDemo和SpringBootDemo中均有詳細(xì)的使用示例者娱。
例如我們收集應(yīng)用日志時(shí),如果需要實(shí)現(xiàn)按Log4j那種向上收集的方式苏揣,就可以使用這種Headers路由策略黄鳍。
日志等級(jí)分為 debug - info - warning - error四個(gè)級(jí)別。而針對(duì)四個(gè)日志級(jí)別平匈,按四個(gè)隊(duì)列進(jìn)行分開(kāi)收集框沟,收集時(shí)藏古,每個(gè)隊(duì)列對(duì)應(yīng)一個(gè)日志級(jí)別,然后收集該日志級(jí)別以上級(jí)別的所有日志(包含當(dāng)前日志級(jí)別)忍燥。像這種場(chǎng)景拧晕,就比較適合使用Headers路由機(jī)制。
二、分組消費(fèi)模式
1.什么是分組消費(fèi)模式
我們回顧下RabbitMQ的消費(fèi)模式,Exchange與Queue之間的消息路由都是通過(guò)RoutingKey關(guān)鍵字來(lái)進(jìn)行的于微,不同類型的Exchange對(duì)RoutingKey進(jìn)行不同的處理剔氏。那有沒(méi)有不通過(guò)RoutingKey來(lái)進(jìn)行路由的策略呢?
這個(gè)問(wèn)題其實(shí)是很常見(jiàn)的,一個(gè)產(chǎn)品的業(yè)務(wù)模型設(shè)計(jì)得再完美,也會(huì)有照顧不到的場(chǎng)景。例如ShardingSphere分庫(kù)分表時(shí)臭墨,默認(rèn)都是基于SQL語(yǔ)句來(lái)進(jìn)行分庫(kù)分表,但是為了保證產(chǎn)品靈活性膘盖,也提供了hint強(qiáng)制路由策略胧弛,脫離了SQL的限制。
在RabbitMQ產(chǎn)品當(dāng)中侠畔,確實(shí)沒(méi)有這樣的路由策略叶圃,但是在SpringCloudStream框架對(duì)RabbitMQ進(jìn)行封裝時(shí),提供了一個(gè)這種策略践图,即分區(qū)消費(fèi)策略掺冠。這種策略很類似于kafka的分組消費(fèi)策略。 我們回憶一下码党,在kafka中的分組策略德崭,是不同的group,都會(huì)消費(fèi)到同樣的一份message副本揖盘,而在同一個(gè)group中眉厨,只會(huì)有一個(gè)消費(fèi)者消費(fèi)到一個(gè)message。這種分組消費(fèi)策略兽狭,嚴(yán)格來(lái)說(shuō)憾股,在Rabbit中是不存在的。RabbitMQ是通過(guò)不同類型的exchange來(lái)實(shí)現(xiàn)不同的消費(fèi)策略的箕慧。這雖然與kafka的這一套完全不同服球,但是在SpringCloudStream針對(duì)RabbitMQ的實(shí)現(xiàn)中,可以很容易的看到kafka這種分組策略的影子颠焦。
當(dāng)有多個(gè)消費(fèi)者實(shí)例消費(fèi)同一個(gè)bingding時(shí)斩熊,Spring Cloud Stream同樣是希望將這種分組策略,移植到RabbitMQ中來(lái)的伐庭。就是在不同的group中粉渠,會(huì)同樣消費(fèi)同一個(gè)Message分冈,而在同一個(gè)group中,只會(huì)有一個(gè)消費(fèi)者消息到一個(gè)Message霸株。
2.實(shí)例測(cè)試
要使用分組消費(fèi)策略雕沉,需要在生產(chǎn)者和消費(fèi)者兩端都進(jìn)行分組配置。
1去件、生產(chǎn)者端 核心配置
2坡椒、消費(fèi)者端啟動(dòng)兩個(gè)實(shí)例,組成一個(gè)消費(fèi)者組
消費(fèi)者1 核心配置
?消費(fèi)者2 核心配置
這樣就完成了一個(gè)分組消費(fèi)的配置箫攀。兩個(gè)消費(fèi)者實(shí)例會(huì)組成一個(gè)消費(fèi)者組。而生產(chǎn)者發(fā)送的消息幼衰,只會(huì)被消費(fèi)者1 消費(fèi)到(生產(chǎn)者的partition-key-expression 和 消費(fèi)者的 instance-index 匹配)靴跛。
3.實(shí)現(xiàn)原理
實(shí)際上,在跟蹤查看RabbitMQ的實(shí)現(xiàn)時(shí)渡嚣,就會(huì)發(fā)現(xiàn)梢睛,Spring Cloud Stream在增加了消費(fèi)者端的分區(qū)設(shè)置后,會(huì)對(duì)每個(gè)有效的分區(qū)創(chuàng)建一個(gè)單獨(dú)的queue识椰,這個(gè)隊(duì)列的隊(duì)列名是在原有隊(duì)列名后面加上一個(gè)索引值绝葡。而發(fā)送者端的消息,會(huì)最終發(fā)送到這個(gè)帶索引值的隊(duì)列上腹鹉,而不是原隊(duì)列上藏畅,這樣就完成了分區(qū)消費(fèi)。
我們的示例中功咒,分組表達(dá)式是直接指定的愉阎,這樣其實(shí)是喪失了靈活性的。實(shí)際開(kāi)發(fā)中力奋,可以將這個(gè)分組表達(dá)式放到消息的header當(dāng)中榜旦,在發(fā)送消息時(shí)指定,這樣就更有靈活性了景殷。
例如:將生產(chǎn)者端的分組表達(dá)式配置為header['partitonkey']
這樣溅呢,就可以在發(fā)送消息時(shí),給消息指定一個(gè)header屬性猿挚,來(lái)控制控制分組消費(fèi)的結(jié)果咐旧。
分組消費(fèi)策略是在原有路由策略上的一個(gè)補(bǔ)充,在實(shí)際生產(chǎn)中也是經(jīng)常會(huì)用到的一種策略绩蜻。并且休偶,MQ的使用場(chǎng)景是非常多的,這也意味著辜羊,不管MQ產(chǎn)品設(shè)計(jì)得如何完善踏兜,在復(fù)雜場(chǎng)景下词顾,往往都不可能滿足所有的使用要求。這時(shí)碱妆,如果想要自行設(shè)計(jì)一些更靈活的使用方式肉盹,那么這種分組消費(fèi)的模式就是一個(gè)很好的示例。
三疹尾、死信隊(duì)列
文檔地址:?https://www.rabbitmq.com/dlx.html
死信隊(duì)列是RabbitMQ中非常重要的一個(gè)特性上忍。簡(jiǎn)單理解,他是RabbitMQ對(duì)于未能正常消費(fèi)的消息進(jìn)行的一種補(bǔ)救機(jī)制纳本。死信隊(duì)列也是一個(gè)普通的隊(duì)列窍蓝,同樣可以在隊(duì)列上聲明消費(fèi)者,繼續(xù)對(duì)消息進(jìn)行消費(fèi)處理繁成。
對(duì)于死信隊(duì)列吓笙,在RabbitMQ中主要涉及到幾個(gè)參數(shù)。
在這里巾腕,x-dead-letter-exchange指定一個(gè)交換機(jī)作為死信交換機(jī)面睛,然后x-dead-letter-routing-key指定交換機(jī)的RoutingKey。而接下來(lái)尊搬,死信交換機(jī)就可以像普通交換機(jī)一樣叁鉴,通過(guò)RoutingKey將消息轉(zhuǎn)發(fā)到對(duì)應(yīng)的死信隊(duì)列中。
1.何時(shí)會(huì)產(chǎn)生死信
有以下三種情況佛寿,RabbitMQ會(huì)將一個(gè)正常消息轉(zhuǎn)成死信:
1)消息被消費(fèi)者確認(rèn)拒絕幌墓。消費(fèi)者把requeue參數(shù)設(shè)置為true(false),并且在消費(fèi)后冀泻,向RabbitMQ返回拒絕克锣。channel.basicReject或者channel.basicNack。
2)消息達(dá)到預(yù)設(shè)的TTL時(shí)限還一直沒(méi)有被消費(fèi)腔长。
3)消息由于隊(duì)列已經(jīng)達(dá)到最長(zhǎng)長(zhǎng)度限制而被丟掉袭祟。
TTL即最長(zhǎng)存活時(shí)間 Time-To-Live 。消息在隊(duì)列中保存時(shí)間超過(guò)這個(gè)TTL捞附,即會(huì)被認(rèn)為死亡巾乳。死亡的消息會(huì)被丟入死信隊(duì)列,如果沒(méi)有配置死信隊(duì)列的話鸟召,RabbitMQ會(huì)保證死了的消息不會(huì)再次被投遞胆绊,并且在未來(lái)版本中,會(huì)主動(dòng)刪除掉這些死掉的消息欧募。
設(shè)置TTL有兩種方式压状,一是通過(guò)配置策略指定,另一種是給隊(duì)列單獨(dú)聲明TTL。
策略配置方式 - Web管理平臺(tái)配置 或者 使用指令配置 60000為毫秒單位:
在聲明隊(duì)列時(shí)指定 - 同樣可以在Web管理平臺(tái)配置种冬,也可以在代碼中配置:
2.死信隊(duì)列的配置方式
RabbitMQ中有兩種方式可以聲明死信隊(duì)列镣丑,一種是針對(duì)某個(gè)單獨(dú)隊(duì)列指定對(duì)應(yīng)的死信隊(duì)列。另一種就是以策略的方式進(jìn)行批量死信隊(duì)列的配置娱两。
針對(duì)多個(gè)隊(duì)列莺匠,可以使用策略方式,配置統(tǒng)一的死信隊(duì)列:
針對(duì)隊(duì)列單獨(dú)指定死信隊(duì)列的方式主要是之前提到的三個(gè)屬性:
這些參數(shù)十兢,也可以在RabbitMQ的管理頁(yè)面進(jìn)行配置趣竣。例如配置策略時(shí):
另外,你會(huì)注意到旱物,在對(duì)隊(duì)列進(jìn)行配置時(shí)遥缕,只有Classic經(jīng)典隊(duì)列和Quorum仲裁隊(duì)列才能配置死信隊(duì)列,而目前Stream流式隊(duì)列宵呛,并不支持配置死信隊(duì)列单匣。
3.關(guān)于參數(shù)x-dead-letter-routing-key
死信在轉(zhuǎn)移到死信隊(duì)列時(shí),他的Routing key 也會(huì)保存下來(lái)烤蜕。但是如果配置了x-dead-letter-routing-key這個(gè)參數(shù)的話封孙,routingkey就會(huì)被替換為配置的這個(gè)值迹冤。
另外讽营,死信在轉(zhuǎn)移到死信隊(duì)列的過(guò)程中,是沒(méi)有經(jīng)過(guò)消息發(fā)送者確認(rèn)的泡徙,所以并不能保證消息的安全性橱鹏。
4.如何確定一個(gè)消息是不是死信
消息被作為死信轉(zhuǎn)移到死信隊(duì)列后,會(huì)在Header當(dāng)中增加一些消息堪藐。在官網(wǎng)的詳細(xì)介紹中莉兰,可以看到很多內(nèi)容,比如時(shí)間礁竞、原因(rejected,expired,maxlen)糖荒、隊(duì)列等。然后header中還會(huì)加上第一次成為死信的三個(gè)屬性模捂,并且這三個(gè)屬性在以后的傳遞過(guò)程中都不會(huì)更改捶朵。
1)x-first-death-reason
2)x-first-death-queue
3)x-first-death-exchange
5.死信隊(duì)列如何消費(fèi)
其實(shí)從前面的配置過(guò)程能夠看到,所謂死信交換機(jī)或者死信隊(duì)列狂男,不過(guò)是在交換機(jī)或者隊(duì)列之間建立一種死信對(duì)應(yīng)關(guān)系综看,而死信隊(duì)列可以像正常隊(duì)列一樣被消費(fèi)。他與普通隊(duì)列一樣具有FIFO的特性岖食。對(duì)死信隊(duì)列的消費(fèi)邏輯通常是對(duì)這些失效消息進(jìn)行一些業(yè)務(wù)上的補(bǔ)償红碑。
RabbitMQ中,是不存在延遲隊(duì)列的功能的泡垃,而通常如果要用到延遲隊(duì)列析珊,就會(huì)采用TTL+死信隊(duì)列的方式來(lái)處理羡鸥。
RabbitMQ提供了一個(gè)rabbitmq_delayed_message_exchange插件,可以實(shí)現(xiàn)延遲隊(duì)列的功能唾琼,但是并沒(méi)有集成到官方的發(fā)布包當(dāng)中兄春,需要單獨(dú)去下載。這里就不去討論了锡溯。
四赶舆、消費(fèi)優(yōu)先級(jí)與流量控制
文檔地址:?https://www.rabbitmq.com/consumer-priority.html
關(guān)于消費(fèi)隊(duì)列的優(yōu)先級(jí),關(guān)鍵是x-priority?這個(gè)參數(shù)祭饭,可以指定隊(duì)列的優(yōu)先級(jí)芜茵。默認(rèn)情況下,RabbitMQ會(huì)根據(jù)round-robin策略倡蝙,把消息均勻的給不同的消費(fèi)者進(jìn)行處理九串。但是有了優(yōu)先級(jí)之后,RabbitMQ會(huì)保證優(yōu)先級(jí)高的隊(duì)列先進(jìn)行消費(fèi)寺鸥,而同一優(yōu)先級(jí)的隊(duì)列猪钮,還是會(huì)使用round-robin輪詢策略來(lái)進(jìn)行分配。
與之對(duì)應(yīng)的是RabbitMQ的流量控制配置胆建,關(guān)鍵是channel.basicQos(int prefetch_size, int prefetch_count, boolean global)烤低。 這個(gè)方法中,prefetch_count設(shè)置了當(dāng)前消費(fèi)者節(jié)點(diǎn)最多保持的未答復(fù)的消息個(gè)數(shù)笆载, prefetch_size設(shè)置了當(dāng)前消費(fèi)節(jié)點(diǎn)最多保持的未答復(fù)的消息大小扑馁,然后global參數(shù)為true則表示該配置針對(duì)當(dāng)前channel的所有隊(duì)列,而默認(rèn)情況下是false凉驻,表示該配置只針對(duì)當(dāng)前消費(fèi)者隊(duì)列腻要。最常用的方式就是只設(shè)定一個(gè)prefetch_count參數(shù)。
這兩個(gè)參數(shù)實(shí)際上都是為了配置當(dāng)前消費(fèi)節(jié)點(diǎn)的消息吞吐量涝登。當(dāng)消費(fèi)者集群中的業(yè)務(wù)處理能力或者消息配置不一樣時(shí)雄家,可以通過(guò)給不同的消費(fèi)節(jié)點(diǎn)配置不同的prefetch_count,再結(jié)合消費(fèi)優(yōu)先級(jí)的配置來(lái)實(shí)現(xiàn)流量控制策略胀滚。
五趟济、遠(yuǎn)程數(shù)據(jù)分發(fā)插件-Federation Plugin
如果我們需要在多個(gè)RabbitMQ服務(wù)之間進(jìn)行消息同步,那么蛛淋,首選的方案自然是通過(guò)RabbitMQ集群來(lái)進(jìn)行咙好。但是,在某些網(wǎng)絡(luò)狀況比較差的場(chǎng)景下褐荷,搭建集群會(huì)不太方便勾效。例如,某大型企業(yè),可能在北京機(jī)房和長(zhǎng)沙機(jī)房分別搭建RabbitMQ服務(wù)层宫,然后希望長(zhǎng)沙機(jī)房需要同步北京機(jī)房的消息杨伙,這樣可以讓長(zhǎng)沙的消費(fèi)者服務(wù)可以直接連接長(zhǎng)沙本地的RabbitMQ,而不用費(fèi)盡周折去連接北京機(jī)房的RabbitMQ服務(wù)萌腿。這時(shí)要如何進(jìn)行數(shù)據(jù)同步呢限匣?搭建一個(gè)網(wǎng)絡(luò)跨度這么大的集群顯然就不太劃算。這時(shí)就可以考慮使用RabbitMQ的Federation插件毁菱,搭建聯(lián)邦隊(duì)列Federation米死。通過(guò)Federation可以搭建一個(gè)單向的數(shù)據(jù)同步通道(當(dāng)然,要搭建雙相同步也是可以的)贮庞。
1.啟動(dòng)插件
RabbitMQ的官方運(yùn)行包中已經(jīng)包含了Federation插件峦筒,只需要啟動(dòng)后就可以直接使用。
插件啟用完成后窗慎,可以在管理控制臺(tái)的Admin菜單看到兩個(gè)新增選項(xiàng) Federation Status和Federation Upstreams物喷。
2.配置Upstream
Upstream表示是一個(gè)外部的服務(wù)節(jié)點(diǎn),在RabbitMQ中遮斥,可以是一個(gè)交換機(jī)峦失,也可以是一個(gè)隊(duì)列。他的配置方式是由下游服務(wù)主動(dòng)配置一個(gè)與上游服務(wù)的鏈接术吗,然后數(shù)據(jù)就會(huì)從上游服務(wù)主動(dòng)同步到下游服務(wù)中尉辑。
接下來(lái)我們用本地localhost的RabbitMQ服務(wù)來(lái)模擬DownStream下游服務(wù),去指向一個(gè)worker2機(jī)器上搭建的RabbitMQ服務(wù)藐翎,搭建一個(gè)聯(lián)邦交換機(jī)Federation Exchange材蹬。
先在本地用程序的方式实幕,聲明一個(gè)交換機(jī)和交換隊(duì)列吝镣。
然后在本地RabbitMQ中配置一個(gè)上游服務(wù),服務(wù)的名字Name屬性隨意昆庇,URI指向Worker2上的/mirror虛擬機(jī)(配置方式參看頁(yè)面上的示例):amqp://admin:admin@worker2:5672/ (注意末贾,在添加時(shí),如果指定了Upstream的Virtual Host是mirror整吆,那么在URI中就不能再添加Virtual host配置了拱撵,默認(rèn)會(huì)在上游服務(wù)中使用相同的VirtualHost。)
注意:?
1表蝙、其他的相關(guān)參數(shù)拴测,可以在頁(yè)面上查看幫助。例如府蛇,默認(rèn)情況下集索,Upstream會(huì)使用和Downstream同名的Exchange,但是也可以通過(guò)Upstream配置中的Exchange參數(shù)指定不同的。
2务荆、關(guān)于Virtual Host虛擬機(jī)配置妆距,如果在配置Upstream時(shí)指定了Virtual Host屬性,那么在URI中就不能再添加Virtaul Host配置了函匕,默認(rèn)會(huì)在Upstream上使用相同的Virtual Host娱据。
3.配置Federation策略
接下來(lái)需要配置一個(gè)指向上游服務(wù)的Federation策略。在配置策略時(shí)可以選擇是針對(duì)Exchange交換機(jī)還是針對(duì)Queue隊(duì)列盅惜。配置策略時(shí)中剩,同樣有很多參數(shù)可以選擇配置。最簡(jiǎn)化的一個(gè)配置如下:
注意:每個(gè)策略的Definition部分抒寂,至少需要指定一個(gè)Federation目標(biāo)咽安。federation-upstream-set參數(shù)表示是以set集合的方式針對(duì)多個(gè)Upstream生效,all表示是全部Upstream蓬推。而federation-upstream參數(shù)表示只對(duì)某一個(gè)Upstream生效妆棒。
4.測(cè)試
?配置完Upstream和對(duì)應(yīng)的策略后,進(jìn)入Federation Status菜單就能看到Federation插件的執(zhí)行情況沸伏。狀態(tài)為running表示啟動(dòng)成功糕珊,如果配置出錯(cuò),則會(huì)提示失敗原因這個(gè)提示非常非常簡(jiǎn)單毅糟。
然后红选,在遠(yuǎn)程服務(wù)Worker2的RabbitMQ服務(wù)中,可以看到對(duì)應(yīng)生成的Federation交換機(jī)姆另。
接下來(lái)就可以嘗試在上游服務(wù)Worker2的fed_exchange中發(fā)送消息喇肋,消息會(huì)同步到Local本地的聯(lián)邦交換機(jī)中,從而被對(duì)應(yīng)的消費(fèi)者消費(fèi)到迹辐。
在很多網(wǎng)絡(luò)情況復(fù)雜的大型項(xiàng)目中蝶防,F(xiàn)ederation插件甚至?xí)如R像集群使用更多,這也是為什么RabbitMQ有了集群機(jī)制后明吩,依然一直保留著Federation插件间学。
在我們的實(shí)驗(yàn)過(guò)程中,會(huì)在上游服務(wù)重新生成一個(gè)新的Exchange交換機(jī)印荔,這顯然是不太符合實(shí)際情況的低葫。我們通常的使用方式是希望將上游MQ中的某一個(gè)已有的Exchange交換機(jī)或者Queue隊(duì)列的數(shù)據(jù)同步到下游一個(gè)新的Exchange或者Queue中。這要如何配置呢仍律?大家自行理解實(shí)驗(yàn)把嘿悬。
六、懶隊(duì)列 Lazy Queue
文檔地址:?https://www.rabbitmq.com/lazy-queues.html
RabbitMQ從3.6.0版本開(kāi)始水泉,就引入了懶隊(duì)列的概念善涨。懶隊(duì)列會(huì)盡可能早的將消息內(nèi)容保存到硬盤當(dāng)中主到,并且只有在用戶請(qǐng)求到時(shí),才臨時(shí)從硬盤加載到RAM內(nèi)存當(dāng)中躯概。
懶隊(duì)列的設(shè)計(jì)目標(biāo)是為了支持非常長(zhǎng)的隊(duì)列(數(shù)百萬(wàn)級(jí)別)登钥。隊(duì)列可能會(huì)因?yàn)橐恍┰蜃兊梅浅iL(zhǎng)-也就是數(shù)據(jù)堆積:
1)消費(fèi)者服務(wù)宕機(jī)了
2)有一個(gè)突然的消息高峰,生產(chǎn)者生產(chǎn)消息超過(guò)消費(fèi)者
3)消費(fèi)者消費(fèi)太慢了
默認(rèn)情況下娶靡,RabbitMQ接收到消息時(shí)牧牢,會(huì)保存到內(nèi)存以便使用,同時(shí)把消息寫到硬盤姿锭。但是塔鳍,消息寫入硬盤的過(guò)程中,是會(huì)阻塞隊(duì)列的呻此。RabbitMQ雖然針對(duì)寫入硬盤速度做了很多算法優(yōu)化轮纫,但是在長(zhǎng)隊(duì)列中,依然表現(xiàn)不是很理想焚鲜,所以就有了懶隊(duì)列的出現(xiàn)掌唾。
懶隊(duì)列會(huì)嘗試盡可能早的把消息寫到硬盤中。這意味著在正常操作的大多數(shù)情況下忿磅,RAM中要保存的消息要少得多糯彬。當(dāng)然,這是以增加磁盤IO為代價(jià)的葱她。
聲明懶隊(duì)列有兩種方式:
1撩扒、給隊(duì)列指定參數(shù)
在代碼中可以通過(guò)x-queue-mode參數(shù)指定:
2、設(shè)定一個(gè)策略吨些,在策略中指定queue-mode 為 lazy
要注意的是搓谆,當(dāng)一個(gè)隊(duì)列被聲明為懶隊(duì)列,那即使隊(duì)列被設(shè)定為不持久化豪墅,消息依然會(huì)寫入到硬盤中泉手。并且,在鏡像集群中但校,大量的消息也會(huì)被同步到當(dāng)前節(jié)點(diǎn)的鏡像節(jié)點(diǎn)當(dāng)中螃诅,并寫入硬盤啡氢。這會(huì)給集群資源造成很大的負(fù)擔(dān)状囱。
最后一句話總結(jié):懶隊(duì)列適合消息量大且長(zhǎng)期有堆積的隊(duì)列,可以減少內(nèi)存使用倘是,加快消費(fèi)速度亭枷。但是這是以大量消耗集群的網(wǎng)絡(luò)及磁盤IO為代價(jià)的。
七搀崭、消息分片存儲(chǔ)插件-Sharding Plugin
談到Sharding叨粘,你是不是就想到了分庫(kù)分表猾编?對(duì)于數(shù)據(jù)庫(kù)的分庫(kù)分表,分庫(kù)可以減少數(shù)據(jù)庫(kù)的IO性能壓力升敲,而真正要解決單表數(shù)據(jù)太大的問(wèn)題答倡,就需要分表。
對(duì)于RabbitMQ同樣驴党,通過(guò)集群模式瘪撇,能夠增大他的吞吐量,但是港庄,針對(duì)單個(gè)隊(duì)列倔既,如何增加吞吐量呢?普通集群保證不了數(shù)據(jù)的高可用鹏氧,而鏡像隊(duì)列雖然可以保證消息高可用渤涌,但是消費(fèi)者并不能對(duì)消息增加消費(fèi)并發(fā)度,所以把还,RabbitMQ的集群機(jī)制并不能增加單個(gè)隊(duì)列的吞吐量实蓬。
上面的懶隊(duì)列其實(shí)就是針對(duì)這個(gè)問(wèn)題的一種解決方案。但是很顯然吊履,懶隊(duì)列的方式屬于治標(biāo)不治本瞳秽。真正要提升RabbitMQ單隊(duì)列的吞吐量,還是要從數(shù)據(jù)也就是消息入手率翅,只有將數(shù)據(jù)真正的分開(kāi)存儲(chǔ)才行练俐。RabbitMQ提供的Sharding插件,就是一個(gè)可選的方案冕臭。他會(huì)真正將一個(gè)隊(duì)列中的消息分散存儲(chǔ)到不同的節(jié)點(diǎn)上腺晾,并提供多個(gè)節(jié)點(diǎn)的負(fù)載均衡策略實(shí)現(xiàn)對(duì)等的讀與寫功能。
1.安裝Sharding插件
在當(dāng)前RabbitMQ的運(yùn)行版本中辜贵,已經(jīng)包含了Sharding插件悯蝉,需要使用插件時(shí),只需要安裝啟用即可托慨。
2.配置Sharding策略
啟用完成后鼻由,需要配置Sharding的策略。
按照要求厚棵,就可以配置一個(gè)針對(duì)sharding_開(kāi)頭的交換機(jī)和隊(duì)列的策略:
3.新增帶Sharding的Exchange交換機(jī)
?在創(chuàng)建隊(duì)列時(shí)蕉世,可以看到,安裝了Sharding插件后婆硬,多出了一種隊(duì)列類型狠轻,x-modulus-hash:
4.往分片交換機(jī)上發(fā)送消息
?接下來(lái),就可以用下面的生產(chǎn)者代碼彬犯,在RabbitMQ上聲明一個(gè)x-modulus-hash類型的交換機(jī)向楼,并往里面發(fā)送一萬(wàn)條消息查吊。
啟動(dòng)后,就會(huì)在RabbitMQ上聲明一個(gè)sharding_exchange湖蜕。查看這個(gè)交換機(jī)的詳情逻卖,可以看到他的分片情況:
并且,一萬(wàn)條消息被平均分配到了三個(gè)隊(duì)列當(dāng)中:
Sharding插件帶來(lái)的x-modulus-hash類型Exchange昭抒,會(huì)忽略之前的routingkey配置箭阶,而將消息以輪詢的方式平均分配到Exchange綁定的所有隊(duì)列上。
5.消費(fèi)分片交換機(jī)上的消息
現(xiàn)在sharding2_exchange交換機(jī)上的消息已經(jīng)平均分配到了三個(gè)碎片隊(duì)列上戈鲁。這時(shí)如何去消費(fèi)這些消息呢仇参?你會(huì)發(fā)現(xiàn)這些碎片隊(duì)列的名字并不是毫無(wú)規(guī)律的,他是有一個(gè)固定的格式的婆殿。都是固定的這種格式:sharding: {exchangename}-{node}-{shardingindex}?诈乒。你當(dāng)然可以針對(duì)每個(gè)隊(duì)列去單獨(dú)聲明消費(fèi)者,這樣當(dāng)然是能夠消費(fèi)到消息的婆芦,但是這樣怕磨,你消費(fèi)到的消息就是一些零散的消息了,這不符合分片的業(yè)務(wù)場(chǎng)景要求消约。
數(shù)據(jù)分片后肠鲫,還是希望能夠像一個(gè)普通隊(duì)列一樣消費(fèi)到完整的數(shù)據(jù)副本。這時(shí)或粮,Sharding插件提供了一種偽隊(duì)列的消費(fèi)方式导饲。你可以聲明一個(gè)名字為?exchangename?的偽隊(duì)列,然后像消費(fèi)一個(gè)普通隊(duì)列一樣去消費(fèi)這一系列的碎片隊(duì)列氯材。
為什么說(shuō)是偽隊(duì)列渣锦?exchange、queue傻傻分不清楚氢哮?因?yàn)槊麨閑xchangename的隊(duì)列實(shí)際是不存在的袋毙。
6.注意事項(xiàng)
Sharding插件將消息分散存儲(chǔ)時(shí),是盡量按照輪詢的方式進(jìn)行冗尤。
首先听盖,這些消息在分片的過(guò)程中,是沒(méi)有考慮消息順序的裂七,這會(huì)讓RabbitMQ中原本就不是很嚴(yán)謹(jǐn)?shù)南㈨樞蜃兊酶友┥霞铀钥础K裕?b>Sharding插件適合于那些對(duì)于消息延遲要求不嚴(yán)格,以及對(duì)消費(fèi)順序沒(méi)有任何要求的的場(chǎng)景碍讯。
然后悬蔽,Sharding插件消費(fèi)偽隊(duì)列的消息時(shí),會(huì)從消費(fèi)者最少的碎片中選擇隊(duì)列捉兴。這時(shí)蝎困,如果你的這些碎片隊(duì)列中已經(jīng)有了很多其他的消息,那么再去消費(fèi)偽隊(duì)列消息時(shí)倍啥,就會(huì)受到這些不均勻數(shù)據(jù)的影響禾乘。所以,如果使用Sharding插件虽缕,這些碎片隊(duì)列就盡量不要單獨(dú)使用了始藕。
RabbitMQ針對(duì)各種復(fù)雜場(chǎng)景,還有非常多精妙的設(shè)計(jì)以及擴(kuò)展氮趋。我們多學(xué)習(xí)一些擴(kuò)展的場(chǎng)景伍派,也還只是冰山一角,但是剩胁,這些場(chǎng)景已經(jīng)超出了國(guó)內(nèi)80%企業(yè)的應(yīng)用范圍诉植。多學(xué)習(xí)了解這些擴(kuò)展場(chǎng)景,對(duì)我們的好處不光是能把RabbitMQ用得更好昵观,更重要在于能幫你更深入的理解MQ的應(yīng)用場(chǎng)景以及各種細(xì)節(jié)問(wèn)題晾腔。而對(duì)于業(yè)務(wù)問(wèn)題挖掘深度,才是決定一個(gè)程序員實(shí)力的前提啊犬。
?如果你回頭再看下這一章節(jié)的各種復(fù)雜場(chǎng)景灼擂,你會(huì)發(fā)現(xiàn),這一章節(jié)中的隊(duì)列觉至,還全都只是回到了最初的經(jīng)典隊(duì)列剔应。如果結(jié)合這些場(chǎng)景,再依次來(lái)分析一下新出的Quorum隊(duì)列语御,Stream隊(duì)列领斥,你會(huì)有什么感覺(jué)?
你以為你學(xué)懂了RabbitMQ沃暗,其實(shí)只是坐井觀天月洛。學(xué)得越多,不懂的也越多孽锥!