
- 前言 -
RabbitMQ 是基于 AMQP 協(xié)議的,通過使用通用協(xié)議就可以做到在不同語言之間傳遞。
- AMQP 協(xié)議 -
1、Server:又稱 broker,接受客戶端連接,實現(xiàn) AMQP 實體服務(wù)。2、Connection:連接和具體 broker 網(wǎng)絡(luò)連接。3、Channel:網(wǎng)絡(luò)信道,幾乎所有操作都在 channel 中進行,channel 是消息讀寫的通道。客戶端可以建立多個 channel,每個 channel 表示一個會話任務(wù)。4、message:消息,服務(wù)器和應(yīng)用程序之間傳遞的數(shù)據(jù),由 properties 和 body 組成。properties 可以對消息進行修飾,比如消息的優(yōu)先級,延遲等高級特性;body 是消息實體內(nèi)容。5、Virtual host:虛擬主機,用于邏輯隔離,最上層消息的路由。一個 Virtual host 可以若干個 Exchange 和 Queue,同一個 Virtual host 不能有同名的 Exchange 或 Queue。6、Exchange:交換機,接受消息,根據(jù)路由鍵轉(zhuǎn)發(fā)消息到綁定的隊列上。7、Banding:Exchange 和 Queue 之間的虛擬連接,binding 中可以包括 routing key。8、Routing key:一個路由規(guī)則,虛擬機根據(jù)他來確定如何路由 一條消息。

- Exchange -
交換機的類型,direct、topic、fanout、headers,durability(是否需要持久化true需要)auto delete 當(dāng)最后一個綁定 Exchange 上的隊列被刪除 Exchange 也刪除。
1、Direct Exchange,所有發(fā)送到 Direct Exchange 的消息被轉(zhuǎn)發(fā)到 RouteKey 中指定的 Queue, Direct Exchange 可以使用默認的默認的 Exchange (default Exchange),默認的 Exchange 會綁定所有的隊列,所以 Direct 可以直接使用 Queue 名(作為routing key )綁定。或者消費者和生產(chǎn)者的 routing key 完全匹配。2、Toptic Exchange,是指發(fā)送到 Topic Exchange 的消息被轉(zhuǎn)發(fā)到所有關(guān)心的 Routing key 中指定 topic 的 Queue 上。Exchange 將 routing key 和某 Topic 進行模糊匹配,此時隊列需要綁定一個 Topic。所謂模糊匹配就是可以使用通配符,“#”可以匹配一個或多個詞,“”只匹配一個詞比如“l(fā)og.#”可以匹配“l(fā)og.info.test” "log. "就只能匹配 log.error。3、Fanout Exchange:不處理路由鍵,只需簡單的將隊列綁定到交換機上。發(fā)送到該交換機上的消息都會被發(fā)送到與該交換機綁定的隊列上。Fanout 轉(zhuǎn)發(fā)是最快的。
- 消息如何保證 100 %投遞 -
什么是生產(chǎn)端的可靠性投遞?
2、保證 MQ 節(jié)點節(jié)點的成功接收;3、發(fā)送端 MQ 節(jié)點(broker)收到消息確認應(yīng)答;
可靠性投遞保障方案
在高并發(fā)場景下,每次進行db的操作都是每場消耗性能的。我們使用延遲隊列來減少一次數(shù)據(jù)庫的操作。
消息冪等性
我對一個動作進行操作,我們肯能要執(zhí)行 100 次 1000 次,對于這 1000 次執(zhí)行的結(jié)果都必須一樣的。比如單線程方式下執(zhí)行 update count-1 的操作執(zhí)行一千次結(jié)果都是一樣的。
所以,這個更新操作就是一個冪等的,如果是在并發(fā)不做線程安全的處理的情況下 update 一千次操作結(jié)果可能就不是一樣的,所以并發(fā)情況下的 update 操作就不是一個冪等的操作。對應(yīng)到消息隊列上來,就是我們即使收到了多條一樣的消息,也和消費一條消息效果是一樣的。
高并發(fā)的情況下如何避免消息重復(fù)消費
- 唯一 id +加指紋碼,利用數(shù)據(jù)庫主鍵去重。缺點:高并發(fā)下有數(shù)據(jù)寫入瓶頸。
- 是否進行數(shù)據(jù)庫落庫,落庫后數(shù)據(jù)和緩存如何做到保證冪等(Redis 和數(shù)據(jù)庫如何同時成功同時失敗)?
- 如果不進行落庫,都放在 Redis 中,如何設(shè)計 Redis 和數(shù)據(jù)庫的同步策略?還有放在緩存中就能百分之百的成功嗎?
confirm 確認消息、Return 返回消息
- 消息的確認,指生產(chǎn)者收到投遞消息后,如果 Broker 收到消息就會給我們 的生產(chǎn)者一個應(yīng)答,生產(chǎn)者接受應(yīng)答來確認 Broker 是否收到消息。
如何實現(xiàn)confirm確認消息
- 在 Channel 上開啟確認模式:channel.confirmSelect();
- 在 Channel 上添加監(jiān)聽:addConfirmListener,監(jiān)聽成功和失敗的結(jié)果,具體結(jié)果對消息進行重新發(fā)送或者記錄日志。
Return 消息機制
Return 消息機制處理一些不可路由的消息,我們的生產(chǎn)者通過指定一個Exchange 和 Routinkey,把消息送達到某一個隊列中去,然后我們消費者監(jiān)聽隊列進行消費處理!在某些情況下,如果我們在發(fā)送消息的時候當(dāng) Exchange 不存在或者指定的路由 key 路由找不到,這個時候如果我們需要監(jiān)聽這種不可到達的消息,就要使用Return Listener!Mandatory 設(shè)置為 true 則會監(jiān)聽器會接受到路由不可達的消息,然后處理。如果設(shè)置為 false,broker 將會自動刪除該消息。
- 消費端自定義監(jiān)聽 -
消費端限流
假設(shè)我們有個場景,首先,我們有個 RabbitMQ 服務(wù)器上有上萬條消息未消費,然后我們隨便打開一個消費者客戶端,會出現(xiàn):巨量的消息瞬間推送過來,但是我們的消費端無法同時處理這么多數(shù)據(jù)。
其他情況也會出現(xiàn)問題,比如你的生產(chǎn)者與消費者能力不匹配,在高并發(fā)的情況下生產(chǎn)端產(chǎn)生大量消息,消費端無法消費那么多消息。- RabbitMQ 提供了一種 qos(服務(wù)質(zhì)量保證)的功能,即非自動確認消息的前提下,如果有一定數(shù)目的消息(通過 consumer 或者 Channel 設(shè)置 qos)未被確認,不進行新的消費。
void basicQOS(unit prefetchSize,ushort prefetchCount,Boolean global)方法。
- prefetchSize:0 單條消息的大小限制。0 就是不限制,一般都是不限制。
- prefetchCount: 設(shè)置一個固定的值,告訴 rabbitMQ 不要同時給一個消費者推送多余 N 個消息,即一旦有 N 個消息還沒有 ack,則 consumer 將block 掉,直到有消息 ack。
- global:truefalse 是否將上面的設(shè)置用于 channel,也是就是說上面設(shè)置的限制是用于 channel 級別的還是 consumer 的級別的。
消費端ack與重回隊列
- 消費端進行消費的時候,如果由于業(yè)務(wù)異常我們可以進行日志的記錄,然后進行補償!(也可以加上最大努力次數(shù)的嘗試)
- 如果由于服務(wù)器宕機等嚴重問題,那我們就需要手動進行ack保證消費端的消費成功!
消息重回隊列
- 重回隊列就是為了對沒有處理成功的消息,把消息重新投遞給 broker!
TTL隊列/消息
- 支持消息的過期時間,在消息發(fā)送時可以指定。
- 支持隊列過期時間,在消息入隊列開始計算時間,只要超過了隊列的超時時間配置,那么消息就會自動的清除。
死信隊列
死信隊列:DLX,Dead-Letter-Exchange
利用DLX,當(dāng)消息在一個隊列中變成死信(dead message,就是沒有任何消費者消費)之后,他能被重新publish到另一個Exchange,這個Exchange就是DLX。- 消息被拒絕(basic.reject/basic.nack)同時requeue=false(不重回隊列);
DLX也是一個正常的Exchange,和一般的Exchange沒有任何的區(qū)別,他能在任何的隊列上被指定,實際上就是設(shè)置某個隊列的屬性。當(dāng)這個隊列出現(xiàn)死信的時候,RabbitMQ就會自動將這條消息重新發(fā)布到Exchange上去,進而被路由到另一個隊列。可以監(jiān)聽這個隊列中的消息作相應(yīng)的處理,這個特性可以彌補rabbitMQ以前支持的immediate參數(shù)的功能。
設(shè)置 Exchange 和 Queue,然后進行綁定;
Exchange: dlx.exchange(自定義的名字);
queue: dlx.queue(自定義的名字);
routingkey: #(#表示任何routingkey出現(xiàn)死信都會被路由過來);
然后正常的聲明交換機、隊列、綁定,只是我們在隊列上加上一個參數(shù):
arguments.put("x-dead-letter-exchange","dlx.exchange")。

- RabbitMQ 集群模式 -
1、主備模式:實現(xiàn) rabbitMQ 高可用集群,一般在并發(fā)量和數(shù)據(jù)不大的情況下,這種模式好用簡單。又稱 warren 模式。(區(qū)別于主從模式,主從模式主節(jié)點提供寫操作,從節(jié)點提供讀操作,主備模式從節(jié)點不提供任何讀寫操作,只做備份)如果主節(jié)點宕機備份從節(jié)點會自動切換成主節(jié)點,提供服務(wù)。2、集群模式:經(jīng)典方式就是 Mirror 模式,保證 100% 數(shù)據(jù)不丟失,實現(xiàn)起來也是比較簡單。鏡像隊列,是 rabbitMQ 數(shù)據(jù)高可用的解決方案,主要是實現(xiàn)數(shù)據(jù)同步,一般來說是由 2-3 節(jié)點實現(xiàn)數(shù)據(jù)同步(對于 100% 消息可靠性解決方案一般是 3 個節(jié)點)。多活模式:這種模式也是實現(xiàn)異地數(shù)據(jù)復(fù)制的主流模式,因為 shovel 模式配置相對復(fù)雜,所以一般來說實現(xiàn)異地集群都是使用這種雙活,多活的模式,這種模式需要依賴 rabbitMQ 的 federation 插件,可以實現(xiàn)持續(xù)可靠的 AMQP 數(shù)據(jù)。rabbitMQ 部署架構(gòu)采用雙中心模式(多中心)在兩套(或多套)數(shù)據(jù)中心部署一套 rabbitMQ 集群,各中心的 rabbitMQ 服務(wù)需要為提供正常的消息業(yè)務(wù)外,中心之間還需要實現(xiàn)部分隊列消息共享。federation 插件是一個不需要構(gòu)建 Cluster,而在 Brokers 之間傳輸消息的高性能插件,federation 可以在 brokers 或者 cluster 之間傳輸消息,連接的雙方可以使用不同的 users 或者 virtual host 雙方也可以使用不同版本的 erlang 或者 rabbitMQ 版本。federation 插件可以使用 AMQP 協(xié)議作為通訊協(xié)議,可以接受不連續(xù)的傳輸。
Federation Exchanges,可以看成 Downstream 從 Upstream 主動拉取消息,但并不是拉取所有消息,必須是在Downstream上已經(jīng)明確定義Bindings關(guān)系的 Exchange,也就是有實際的物理 Queue 來接收消息,才會從 Upstream 拉取消息到 Downstream。
使用 AMQP 協(xié)議實施代理間通信,Downstream 會將綁定關(guān)系組合在一起, 綁定/解除綁定命令將發(fā)送到 Upstream 交換機。因此,F(xiàn)ederation Exchange 只接收具有訂閱的消息。HAProxy 是一款提供高可用性、負載均衡以及基于 TCP (第四層)和 HTTP(第七層)應(yīng)用的代理軟件,支持虛擬主機,它是免費、快速并且可靠的一種解決方案。HAProxy 特別適用于那些負載特大的 web 站點,這些站點通常又需要會話保持或七層處理。HAProxy 運行在時下的硬件上,完全可以支持數(shù)以萬計的并發(fā)連接。并且它的運行模式使得它可以很簡單安全的整合進您當(dāng)前的架構(gòu)中同時可以保護你的 web 服務(wù)器不被暴露到網(wǎng)絡(luò)上。
HAProxy 性能為何這么好?
1、單進程、事件驅(qū)動模型顯著降低了.上下文切換的開銷及內(nèi)存占用。2、在任何可用的情況下,單緩沖(single buffering)機制能以不復(fù)制任何數(shù)據(jù)的方式完成讀寫操作,這會節(jié)約大量的CPU時鐘周期及內(nèi)存帶寬。3、借助于 Linux 2.6 (>= 2.6.27.19). 上的splice()系統(tǒng)調(diào)用,HAProxy 可以實現(xiàn)零復(fù)制轉(zhuǎn)發(fā)(Zero-copy forwarding),在Linux 3.5及以上的 OS 中還可以實現(xiàn)心零復(fù)制啟動(zero-starting)。4、內(nèi)存分配器在固定大小的內(nèi)存池中可實現(xiàn)即時內(nèi)存分配,這能夠顯著減少創(chuàng)建一個會話的時長。5、樹型存儲:側(cè)重于使用作者多年前開發(fā)的彈性二叉樹,實現(xiàn)了以 O(log(N)) 的低開銷來保持計時器命令、保持運行隊列命令及管理輪詢及最少連接隊列。
keepAlive
KeepAlived 軟件主要通過 VRRP 協(xié)議實現(xiàn)高可用功能。VRRP 是 Virtual Router RedundancyProtocol (虛擬路由器冗余協(xié)議)的縮寫,VRRP 出現(xiàn)的目的就是為了解決靜態(tài)路由單點故障問題的,它能夠保證當(dāng)個別節(jié)點宕機時,整個網(wǎng)絡(luò)可以不間斷地運行所以,Keepalived 方面具有配置管理 LVS 的功能,同時還具有對 LVS 下面節(jié)點進行健康檢查的功能,另一方面也可實現(xiàn)系統(tǒng)網(wǎng)絡(luò)服務(wù)的高可用功能。
1、管理 LVS 負載均衡軟件;
2、實現(xiàn) LVS 集群節(jié)點的健康檢查中;
3、作為系統(tǒng)網(wǎng)絡(luò)服務(wù)的高可用性(failover)。
Keepalived如何實現(xiàn)高可用
Keepalived 高可用服務(wù)對之間的故障切換轉(zhuǎn)移,是通過 VRRP (Virtual Router
Redundancy Protocol ,虛擬路由器冗余協(xié)議)來實現(xiàn)的。在 Keepalived 服務(wù)正常工作時,主 Master 節(jié)點會不斷地向備節(jié)點發(fā)送( 多播的方式)心跳消息,用以告訴備 Backup 節(jié)點自己還活著,當(dāng)主 Master 節(jié)點發(fā)生故障時,就無法發(fā)送心跳消息,備節(jié)點也就因此無法繼續(xù)檢測到來自主 Master 節(jié)點的心跳了,于是調(diào)用自身的接管程序,接管主 Master 節(jié)點的IP資源及服務(wù)。而當(dāng)主 Master 節(jié)點恢復(fù)時,備 Backup 節(jié)點又會釋放主節(jié)點故障時,自身接管的 IP 資源及服務(wù),恢復(fù)到原來的備用角色。
來源:https://segmentfault.com/a/1190000022387211
版權(quán)申明:內(nèi)容來源網(wǎng)絡(luò),版權(quán)歸原創(chuàng)者所有。除非無法確認,我們都會標明作者及出處,如有侵權(quán)煩請告知,我們會立即刪除并表示歉意。謝謝!