1.TTL(Time To Live)
1)消息的過期時(shí)間---設(shè)置方式
1.通過隊(duì)列屬性設(shè)置消息過期時(shí)間:所有隊(duì)列中的消息超過時(shí)間未被消費(fèi)時(shí),都會(huì)過期躏升。
2.設(shè)置單條消息的過期時(shí)間:在發(fā)送消息的時(shí)候指定消息屬性。
如果同時(shí)指定了 Message TTL 和 Queue TTL跃巡,則小的那個(gè)時(shí)間生效败明。
2.死信隊(duì)列
1)簡(jiǎn)單介紹
消息在某些情況下會(huì)變成死信(Dead Letter)液茎。隊(duì)列在創(chuàng)建的時(shí)候可以指定一個(gè)死信交換機(jī) DLX(Dead Letter Exchange)歌殃。死信交換機(jī)綁定的隊(duì)列被稱為死信隊(duì)列 DLQ(Dead Letter Queue)乔妈,DLX 實(shí)際上也是普通的交換機(jī),DLQ 也是普通的隊(duì)列(例如替補(bǔ)球員也是普通球員)氓皱。
2)什么情況下消息會(huì)變成死信?
1.消息被消費(fèi)者拒絕并且未設(shè)置重回隊(duì)列:(NACK || Reject ) && requeue== false 2.消息過期 3.隊(duì)列達(dá)到最大長(zhǎng)度路召,超過了 Max length(消息數(shù))或者 Max length bytes(字節(jié)數(shù)),最先入隊(duì)的消息會(huì)被發(fā)送到 DLX波材。
3)死信隊(duì)列如何使用?
1.聲明原交換機(jī)(GP_ORI_USE_EXCHANGE)股淡、原隊(duì)列(GP_ORI_USE_QUEUE),相互綁定廷区。隊(duì)列中的消息 10 秒鐘過期唯灵,因?yàn)闆]有消費(fèi)者,會(huì)變成死信躲因。并指定原隊(duì)列的死信交換機(jī)(GP_DEAD_LETTER_EXCHANGE)早敬。
2.聲 明 死 信 交 換 機(jī) ( GP_DEAD_LETTER_EXCHANGE ) 忌傻、 死信隊(duì)列 (GP_DEAD_LETTER_QUEUE)大脉,相互綁定
3.最終消費(fèi)者監(jiān)聽死信隊(duì)列。
4.生產(chǎn)者發(fā)送消息水孩。
3.延遲隊(duì)列
1)應(yīng)用場(chǎng)景
我們?cè)趯?shí)際業(yè)務(wù)中有一些需要延時(shí)發(fā)送消息的場(chǎng)景镰矿,例如: 1.家里有一臺(tái)智能熱水器,需要在 30 分鐘后啟動(dòng)2. 未付款的訂單俘种,15 分鐘后關(guān)閉
2)實(shí)現(xiàn)方案
RabbitMQ 本身不支持延遲隊(duì)列秤标,總的來說有三種實(shí)現(xiàn)方案:1.先存儲(chǔ)到數(shù)據(jù)庫绝淡,用定時(shí)任務(wù)掃描 2.利用 RabbitMQ 的死信隊(duì)列(Dead Letter Queue)實(shí)現(xiàn) 3.利用 rabbitmq-delayed-message-exchange 插件
3)方案2分析-TTL+DLX 的實(shí)現(xiàn)
1.步驟分析:基于消息 TTL,我們來看一下利用死信隊(duì)列(DLQ)實(shí)現(xiàn)延遲隊(duì)列的步驟:1)創(chuàng)建一個(gè)交換機(jī)2)創(chuàng)建一個(gè)隊(duì)列苍姜,與上述交換機(jī)綁定牢酵,并且通過屬性指定隊(duì)列的死信交換機(jī)。3)創(chuàng)建一個(gè)死信交換機(jī) 4)創(chuàng)建一個(gè)死信隊(duì)列4)將死信交換機(jī)綁定到死信隊(duì)列 5)消費(fèi)者監(jiān)聽死信隊(duì)列
2.消息的流轉(zhuǎn)流程:生產(chǎn)者——原交換機(jī)——原隊(duì)列(超過 TTL 之后)——死信交換機(jī)——死信隊(duì)列——最終消費(fèi)者
3.使用死信隊(duì)列實(shí)現(xiàn)延時(shí)消息的缺點(diǎn):1) 如果統(tǒng)一用隊(duì)列來設(shè)置消息的 TTL衙猪,當(dāng)梯度非常多的情況下馍乙,比如 1 分鐘,2分鐘垫释,5 分鐘丝格,10 分鐘,20 分鐘棵譬,30 分鐘......需要?jiǎng)?chuàng)建很多交換機(jī)和隊(duì)列來路由消息显蝌。 2)如果單獨(dú)設(shè)置消息的 TTL,則可能會(huì)造成隊(duì)列中的消息阻塞——前一條消息沒有出隊(duì)(沒有被消費(fèi))订咸,后面的消息無法投遞(比如第一條消息過期 TTL 是 30min曼尊,第二條消息 TTL 是 10min。10 分鐘后脏嚷,即使第二條消息應(yīng)該投遞了涩禀,但是由于第一條消息還未出隊(duì),所以無法投遞)然眼。3)可能存在一定的時(shí)間誤差艾船。
4)方案3分析-基于延遲隊(duì)列插件的實(shí)現(xiàn)(Linux)
1.插件的安裝:省率
2.插件使用:
1)通過聲明一個(gè) x-delayed-message 類型的 Exchange 來使用 delayed-messaging特性。x-delayed-message 是插件提供的類型高每,并不是 rabbitmq 本身的(區(qū)別于 direct屿岂、topic、fanout鲸匿、headers)爷怀。
2)生產(chǎn)者:消息屬性中指定 x-delay 參數(shù)。
4.服務(wù)端流控
1)遇到的問題
當(dāng) RabbitMQ 生產(chǎn) MQ 消息的速度遠(yuǎn)大于消費(fèi)消息的速度時(shí)带欢,會(huì)產(chǎn)生大量的消息堆積运授,占用系統(tǒng)資源,導(dǎo)致機(jī)器的性能下降乔煞。我們想要控制服務(wù)端接收的消息的數(shù)量吁朦,應(yīng)該怎么做呢?
2)不能真正地實(shí)現(xiàn)服務(wù)端限流的方式-設(shè)置隊(duì)列倆個(gè)控制長(zhǎng)度的屬性
3)方式-內(nèi)存控制
1.RabbitMQ 會(huì)在啟動(dòng)時(shí)檢測(cè)機(jī)器的物理內(nèi)存數(shù)值。默認(rèn)當(dāng) MQ 占用 40% 以上內(nèi)存時(shí)渡贾,MQ 會(huì)主動(dòng)拋出一個(gè)內(nèi)存警告并阻塞所有連接(Connections)逗宜。可以通過修改rabbitmq.config 文件來調(diào)整內(nèi)存閾值,默認(rèn)值是 0.4
2.用命令動(dòng)態(tài)設(shè)置纺讲,如果設(shè)置成 0擂仍,則所有的消息都不能發(fā)布。
5.消費(fèi)端限流
1)消息過多導(dǎo)致問題:默認(rèn)情況下熬甚,如果不進(jìn)行配置逢渔,RabbitMQ 會(huì)盡可能快速地把隊(duì)列中的消息發(fā)送到消費(fèi)者。因?yàn)橄M(fèi)者會(huì)在本地緩存消息乡括,如果消息數(shù)量過多复局,可能會(huì)導(dǎo)致 OOM 或者影響其他進(jìn)程的正常運(yùn)行。
2)消費(fèi)端的流量限制的使用原因:在消費(fèi)者處理消息的能力有限粟判,例如消費(fèi)者數(shù)量太少亿昏,或者單條消息的處理時(shí)間過長(zhǎng)的情況下,如果我們希望在一定數(shù)量的消息消費(fèi)完之前档礁,不再推送消息過來角钩,就要用到消費(fèi)端的流量限制措施。
3)消費(fèi)端的流量限制的方式:可以基于 Consumer 或者 channel 設(shè)置 prefetch count 的值呻澜,含義為 Consumer端的最大的 unacked messages 數(shù)目递礼。當(dāng)超過這個(gè)數(shù)值的消息未被確認(rèn),RabbitMQ 會(huì)停止投遞新的消息給該消費(fèi)者羹幸。
4)具體項(xiàng)目中使用:SimpleMessageListenerContainer---》container.setPrefetchCount(2);? ?Spring Boot 配置:----》spring.rabbitmq.listener.simple.prefetch=2
5)舉例:channel 的 prefetch count 設(shè)置為 5脊髓。當(dāng)消費(fèi)者有 5 條消息沒有給 Broker 發(fā)送 ACK后,RabbitMQ 不再給這個(gè)消費(fèi)者投遞消息栅受。