非常強悍的 RabbitMQ 總結,寫得真好!
前言
RabbitMQ 是基於 AMQP 協議的,通過使用通用協議就可以做到在不同語言之間傳遞。
AMQP 協議
核心概念
-
server:又稱 broker,接受客戶端連接,實現 AMQP 實體服務。
-
connection:連接和具體 broker 網絡連接。
-
channel:網絡信道,幾乎所有操作都在 channel 中進行,channel 是消息讀寫的通道。客戶端可以建立多個 channel,每個 channel 表示一個會話任務。
-
message:消息,服務器和應用程序之間傳遞的數據,由 properties 和 body 組成。properties 可以對消息進行修飾,比如消息的優先級,延遲等高級特性;body 是消息實體內容。
-
Virtual host:虛擬主機,用於邏輯隔離,最上層消息的路由。一個 Virtual host 可以若干個 Exchange 和 Queue,同一個 Virtual host 不能有同名的 Exchange 或 Queue。
-
Exchange:交換機,接受消息,根據路由鍵轉發消息到綁定的隊列上。
-
banding:Exchange 和 Queue 之間的虛擬連接,binding 中可以包括 routing key
-
routing key:一個路由規則,虛擬機根據他來確定如何路由 一條消息。
-
Queue:消息隊列,用來存放消息的隊列。
Exchange
交換機的類型,direct、topic、fanout、headers,durability(是否需要持久化 true 需要)auto delete 當最後一個綁定 Exchange 上的隊列被刪除 Exchange 也刪除。
-
Direct Exchange, 所有發送到 Direct Exchange 的消息被轉發到 RouteKey 中指定的 Queue,Direct Exchange 可以使用默認的默認的 Exchange (default Exchange),默認的 Exchange 會綁定所有的隊列,所以 Direct 可以直接使用 Queue 名(作爲 routing key )綁定。或者消費者和生產者的 routing key 完全匹配。
-
Toptic Exchange, 是指發送到 Topic Exchange 的消息被轉發到所有關心的 Routing key 中指定 topic 的 Queue 上。Exchange 將 routing key 和某 Topic 進行模糊匹配,此時隊列需要綁定一個 topic。所謂模糊匹配就是可以使用通配符,“#”可以匹配一個或多個詞,“”只匹配一個詞比如 “log.#” 可以匹配“log.info.test” "log." 就只能匹配 log.error。
-
Fanout Exchange: 不處理路由鍵,只需簡單的將隊列綁定到交換機上。發送到改交換機上的消息都會被髮送到與該交換機綁定的隊列上。Fanout 轉發是最快的。
消息如何保證 100%投遞
什麼是生產端的可靠性投遞?
-
保證消息的成功發出
-
保證 MQ 節點節點的成功接收
-
發送端 MQ 節點(broker)收到消息確認應答
-
完善消息進行補償機制
可靠性投遞保障方案
消息落庫,對消息進行打標
消息的延遲投遞
在高併發場景下,每次進行 db 的操作都是每場消耗性能的。我們使用延遲隊列來減少一次數據庫的操作。
消息冪等性
冪等性是什麼?點擊這篇文章看下。
我對一個動作進行操作,我們肯能要執行 100 次 1000 次,對於這 1000 次執行的結果都必須一樣的。比如單線程方式下執行 update count-1 的操作執行一千次結果都是一樣的,所以這個更新操作就是一個冪等的,如果是在併發不做線程安全的處理的情況下 update 一千次操作結果可能就不是一樣的,所以併發情況下的 update 操作就不是一個冪等的操作。對應到消息隊列上來,就是我們即使受到了多條一樣的消息,也和消費一條消息效果是一樣的。
在公衆號頂級架構師後臺回覆 “offer”,獲取一份驚喜禮包。
高併發的情況下如何避免消息重複消費
-
唯一 id + 加指紋碼,利用數據庫主鍵去重。
優點:實現簡單
缺點:高併發下有數據寫入瓶頸。
-
利用 Redis 的原子性來實習。
使用 Redis 進行冪等是需要考慮的問題
-
是否進行數據庫落庫,落庫後數據和緩存如何做到保證冪等(Redis 和數據庫如何同時成功同時失敗)?
-
如果不進行落庫,都放在 Redis 中如何這是 Redis 和數據庫的同步策略?還有放在緩存中就能百分之百的成功嗎?
confirm 確認消息、Return 返回消息
理解 confirm 消息確認機制
- 消息的確認,指生產者收到投遞消息後,如果 Broker 收到消息就會給我們 的生產者一個應答,生產者接受應答來確認 broker 是否收到消息。
如何實現 confirm 確認消息。
-
在 Channel 上開啓確認模式:channel.confirmSelect()
-
在 channel 上添加監聽:addConfirmListener,監聽成功和失敗的結果,具體結果對消息進行重新發送或者記錄日誌。
return 消息機制
Return 消息機制處理一些不可路由的消息,我們的生產者通過指定一個 Exchange 和 Routinkey,把消息送達到某一個隊列中去,然後我們消費者監聽隊列進行消費處理!
在某些情況下,如果我們在發送消息的時候當 Exchange 不存在或者指定的路由 key 路由找不到,這個時候如果我們需要監聽這種不可到達的消息,就要使用 Return Listener!
Mandatory 設置爲 true 則會監聽器會接受到路由不可達的消息,然後處理。如果設置爲 false,broker 將會自動刪除該消息。
消費端自定義監聽
消費端限流
什麼是消費端的限流?限流算法點擊這裏閱讀。
假設我們有個場景,首先,我們有個 rabbitMQ 服務器上有上萬條消息未消費,然後我們隨便打開一個消費者客戶端,會出現:巨量的消息瞬間推送過來,但是我們的消費端無法同時處理這麼多數據。
這時就會導致你的服務崩潰。其他情況也會出現問題,比如你的生產者與消費者能力不匹配,在高併發的情況下生產端產生大量消息,消費端無法消費那麼多消息。
- rabbitMQ 提供了一種 qos(服務質量保證)的功能,即非自動確認消息的前提下,如果有一定數目的消息(通過 consumer 或者 Channel 設置 qos)未被確認,不進行新的消費。
void basicQOS(unit prefetchSize,ushort prefetchCount,Boolean global) 方法。
-
prefetchSize:0 單條消息的大小限制。0 就是不限制,一般都是不限制。
-
prefetchCount: 設置一個固定的值,告訴 rabbitMQ 不要同時給一個消費者推送多餘 N 個消息,即一旦有 N 個消息還沒有 ack,則 consumer 將 block 掉,直到有消息 ack
-
global:truefalse 是否將上面的設置用於 channel,也是就是說上面設置的限制是用於 channel 級別的還是 consumer 的級別的。
消費端 ack 與重回隊列
-
消費端進行消費的時候,如果由於業務異常我們可以進行日誌的記錄,然後進行補償!(也可以加上最大努力次數的嘗試)
-
如果由於服務器宕機等嚴重問題,那我們就需要手動進行 ack 保證消費端的消費成功!
消息重回隊列
-
重回隊列就是爲了對沒有處理成功的消息,把消息重新投遞給 broker!
-
實際應用中一般都不開啓重回隊列。
TTL 隊列 / 消息
TTL time to live 生存時間。
-
支持消息的過期時間,在消息發送時可以指定。
-
支持隊列過期時間,在消息入隊列開始計算時間,只要超過了隊列的超時時間配置,那麼消息就會自動的清除。
死信隊列
死信隊列:DLX,Dead-Letter-Exchange
利用 DLX,當消息在一個隊列中變成死信(dead message,就是沒有任何消費者消費)之後,他能被重新 publish 到另一個 Exchange,這個 Exchange 就是 DLX。
消息變爲死信的幾種情況:
-
消息被拒絕(basic.reject/basic.nack)同時 requeue=false(不重回隊列)
-
TTL 過期
-
隊列達到最大長度
DLX 也是一個正常的 Exchange,和一般的 Exchange 沒有任何的區別,他能在任何的隊列上被指定,實際上就是設置某個隊列的屬性。
當這個隊列出現死信的時候,RabbitMQ 就會自動將這條消息重新發布到 Exchange 上去,進而被路由到另一個隊列。可以監聽這個隊列中的消息作相應的處理,這個特性可以彌補 rabbitMQ 以前支持的 immediate 參數的功能。
死信隊列的設置
- 設置 Exchange 和 Queue,然後進行綁定
Exchange: dlx.exchange(自定義的名字)
queue: dlx.queue(自定義的名字)
routingkey: #(# 表示任何 routingkey 出現死信都會被路由過來)
然後正常的聲明交換機、隊列、綁定,只是我們在隊列上加上一個參數:
arguments.put("x-dead-letter-exchange","dlx.exchange");
rabbitMQ 集羣模式
-
主備模式:實現 rabbitMQ 高可用集羣,一般在併發量和數據不大的情況下,這種模式好用簡單。又稱 warren 模式。(區別於主從模式,主從模式主節點提供寫操作,從節點提供讀操作,主備模式從節點不提供任何讀寫操作,只做備份)如果主節點宕機備份從節點會自動切換成主節點,提供服務。
-
集羣模式:經典方式就是 Mirror 模式,保證 100% 數據不丟失,實現起來也是比較簡單。
-
鏡像隊列,是 rabbitMQ 數據高可用的解決方案,主要是實現數據同步,一般來說是由 2-3 節點實現數據同步,(對於 100% 消息可靠性解決方案一般是 3 個節點)
-
在公衆號後端架構師後臺回覆 “架構整潔”,獲取一份驚喜禮包。
多活模式:這種模式也是實現異地數據複製的主流模式,因爲 shovel 模式配置相對複雜,所以一般來說實現異地集羣都是使用這種雙活,多活的模式,這種模式需要依賴 rabbitMQ 的 federation 插件,可以實現持續可靠的 AMQP 數據。
rabbitMQ 部署架構採用雙中心模式(多中心)在兩套(或多套)數據中心個部署一套 rabbitMQ 集羣,各中心的 rabbitMQ 服務需要爲提供正常的消息業務外,中心之間還需要實現部分隊列消息共享。
多活架構如下:
federation 插件是一個不需要構建 Cluster,而在 Brokers 之間傳輸消息的高性能插件,federation 可以在 brokers 或者 cluster 之間傳輸消息,連接的雙方可以使用不同的 users 或者 virtual host 雙方也可以使用不同版本的 erlang 或者 rabbitMQ 版本。federation 插件可以使用 AMQP 協議作爲通訊協議,可以接受不連續的傳輸。
Federation Exchanges, 可以看成 Downstream 從 Upstream 主動拉取消息,但
並不是拉取所有消息,必須是在 Downstream 上已經明確定義 Bindings 關係的
Exchange, 也就是有實際的物理 Queue 來接收消息,纔會從 Upstream 拉取消息
到 Downstream。
使用 AMQP 協議實施代理間通信,Downstream 會將綁定關係組合在一起, 綁定 / 解除綁定命令將發送到 Upstream 交換機。
因此,Federation Exchange 只接收具有訂閱的消息。
HAProxy 是一款提供高可用性、負載均衡以及基於 TCP (第四層) 和 HTTP
(第七層) 應用的代理軟件, 支持虛擬主機,它是免費、快速並且可靠的一種解決
方案。HAProxy 特別適用於那些負載特大的 web 站點,這些站點通常又需要會
話保持或七層處理。HAProxy 運行在時下的硬件上,完全可以支持數以萬計的
併發連接。並且它的運行模式使得它可以很簡單安全的整合進您當前的架構中
同時可以保護你的 web 服務器不被暴露到網絡上。
HAProxy 性能爲何這麼好?
-
單進程、事件驅動模型顯著降低了. 上下文切換的開銷及內存佔用.
-
在任何可用的情況下,單緩衝 (single buffering) 機制能以不復制任何數據的方式完成讀寫操作,這會節約大量的 CPU 時鐘週期及內存帶寬
-
藉助於 Linux 2.6 (>= 2.6.27.19). 上的 splice() 系統調用,HAProxy 可以實現零複製轉發 (Zero-copy forwarding), 在 Linux 3.5 及以上的 OS 中還可以實現心零複製啓動 (zero-starting)
-
內存分配器在固定大小的內存池中可實現即時內存分配,這能夠顯著減少創建一個會話的時長
-
樹型存儲: 側重於使用作者多年前開發的彈性二叉樹,實現了以 O(log(N)) 的低開銷來保持計時器命令、保持運行隊列命令及管理輪詢及最少連接隊列
keepAlive
KeepAlived 軟件主要是通過 VRRP 協議實現高可用功能的。VRRP 是
Virtual Router RedundancyProtocol(虛擬路由器冗餘協議) 的縮寫,
VRRP 出現的目的就是爲了解決靜態路由單點故障問題的,它能夠保證當
個別節點宕機時,整個網絡可以不間斷地運行所以,Keepalived - - 方面
具有配置管理 LVS 的功能,同時還具有對 LVS 下面節點進行健康檢查的功
能,另一方面也可實現系統網絡服務的高可用功能
keepAlive 的作用
-
管理 LVS 負載均衡軟件
-
實現 LVS 集羣節點的健康檢查中
-
作爲系統網絡服務的高可用性 (failover)
Keepalived 如何實現高可用
Keepalived 高可用服務對之間的故障切換轉移,是通過 VRRP (Virtual Router
Redundancy Protocol , 虛擬路由器冗餘協議) 來實現的。
在 Keepalived 服務正常工作時,主 Master 節點會不斷地向備節點發送 (多播的方式) 心跳消息,用以告訴備 Backup 節點自己還活看,當主 Master 節點發生故障時,就無法發送心跳消息,備節點也就因此無法繼續檢測到來自主 Master 節點的心跳了,於是調用自身的接管程序,接管主 Master 節點的 IP 資源及服務。
而當主 Master 節點恢復時備 Backup 節點又會釋放主節點故障時自身接管的 IP 資源及服務,恢復到原來的備用角色。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/V5vlXmqQY21GqAJC_bjXbQ