多數據中心的百萬級消息服務實戰

背景

利用 RabbitMQ 集羣橫向擴展能力,均衡流量壓力,讓消息集羣的秒級服務能力達到百萬,Google 曾做過此類實驗;有貨在某些推送場景下也做了類似嘗試,在此對此前實踐經驗以及踩得坑做些總結工作。

RabbitMQ 概述

RabbitMQ 是基於 AMQP 協議實現的消息中間件的一種,常用於在分佈式系統中存儲轉發消息,表現爲易用、可擴展、高可用等特點,最初活躍在金融系統中。消息中間件的主要作用是讓服務組件之間能夠解耦,消息生產者無需關注消息消費者的存在與行爲。

1.Message: 由 Producer 發出, 經過 Exchange 路由到相應的 Queue, 然後 Consumer 從 Queue 中取走消費;

2.Queue: 存儲消息的容器,消息存儲在隊列裏,直到有消費者連接隊列並取走爲止;

  1. 綁定(Binding): 將 Queue 與 Exchange 之間按規則建立映射關係,類似建立網絡路由表,通過 Binding 規定了 Exchange 如何將消息路由到某個隊列中;

  2. 交換機(Exchange):Exchage 就是路由器,每個消息都有一個路由 Key 的屬性,交換機中有一些隊列的 Binding(路由規則),交換機有多種類型,如 topic、direct、fanout;

5.Broker(服務器): 接受客戶端連接,實現 AMQP 消息隊列和路由功能的進程;

  1. 虛擬主機(virtual-host): 一個虛擬主機有一組交換機,隊列和 Binding,用戶只能在虛擬主機的範圍內進行權限控制,每一個服務器都有一個默認的虛擬主機(/);

  2. 連接(Connection): 客戶端與 broker 之間的 Tcp 連接;

  3. 信道(Channel): 比連接更小的單位,創建連接後需要在其內創建信道發送消息,一個連接內可以有多個信道,這樣設計是爲了減少 tcp 連接,客戶端線程儘量共用連接,不共用 Channel;

RabbitMQ Brokers 是一個或多個 Erlang 節點的邏輯分組,每個節點運行 RabbitMQ 應用程序並共享用戶,虛擬主機,隊列,交換,綁定和運行時參數。有時我們將節點的集合稱爲集羣。在所有節點上覆制 RabbitMQ 代理的操作所需的所有數據 / 狀態。一個例外是消息隊列,它們默認駐留在一個節點上,儘管它們是可見的,並且可以從所有節點訪問。要跨集羣中的節點複製隊列,需要配置 Mirror 特性。

集羣又可以分爲兩種,普通模式(默認模式)以兩個節點(A、B)爲例來進行說明。對於 Queue 來說,消息實體只存在於其中一個節點 A(或者 B),A 和 B 兩個節點僅有相同的元數據,即隊列的結構。當消息進入 A 節點的 Queue 後,Consumer 從 B 節點消費時,RabbitMQ 會臨時在 A、B 間進行消息傳輸,把從 A 中的消息實體取出並經過 B 發送給 Consumer。所以 Consumer 應儘量連接每一個節點,從中取消息。即對於同一個邏輯隊列,要在多個節點建立物理 Queue。否則無論 Consumer 連 A 或 B,出口總在 A,會產生瓶頸。當 A 節點故障後,B 節點無法取到 A 節點中還未消費的消息實體。如果做了消息持久化,那麼得等 A 節點恢復,然後纔可被消費。如果沒有持久化的話,就會產生消息丟失的現象。

把需要的隊列做成鏡像隊列,隊列存在與多個節點屬於 RabbitMQ 的 HA 方案。該模式解決了普通模式中的問題,其實質和普通模式不同之處在於,消息實體會主動在鏡像節點間同步,而不是在客戶端取數據時臨時拉取。該模式帶來的副作用也很明顯,除了降低系統性能外,如果鏡像隊列數量過多,加之大量的消息進入,集羣內部的網絡帶寬將會被這種同步通訊大大消耗掉。所以在對可靠性要求較高的場合中適用。

如何構建百萬級消息服務

上文講述了 RabbitMQ 的一些基礎概念,接下來首先分析 Google 的測試思想,然後介紹下我們在此基礎上的一些其他想法,藉此瞭解下如何構建能夠支持百萬級消息併發的 RabbitMQ 服務。

Google 共使用了 32 臺 8 核 30G 內存的虛擬機,構建了相對來說比較龐大的 rabbitmq 集羣,各虛擬機的作用分配如下:

30 RabbitMQ RAM 節點(正常 RAM 節點,RabbitMQ 元數據和定義僅保存在 RAM 中);1 RabbitMQ

Disc 節點(元數據持久化節點,其中 RabbitMQ 代理元數據和定義也保留在光盤上);1 RabbitMQ Stats 節點(統計信息節點,運行 RabbitMQ 管理插件,不帶任何隊列);

在這種高負載的生產(1345531msgs/pers)消費(1413840 msgs/pers)壓力下,RabbitMQ 僅有 2343 條消息暫時在其等待發送的隊列中累積,在這樣的負載下,RabbitMQ 節點也沒有顯示內存壓力,或者需要基於資源限制的啓動流控機制。

使用 RabbitMQ 的許多用戶現在大多集羣規模大致爲 3-7 個 RabbitMQ 節點組成的羣集,從該類集羣中就可以獲得極好的結果。鑑於這一基礎,在 Google 的實驗中使用的 30 節點 RabbitMQ 集羣與當前實踐中常見的相比是相當大的。當然大數據的增長,物聯網,實時分析等應用可能會增加未來許多 RabbitMQ 集羣的規模。

在這樣的大型集羣中,系統的設計,構建和擴展都有一些要點。即使對於較小的集羣也是如此,首先,RabbitMQ 的消息傳遞工作的基本並行單位是隊列。除了適用於某些高可用性配置的部分異常之外,RabbitMQ 隊列由單個 Erlang 進程(輕量級線程抽象)支持,通過謹慎地分配消息的生產者,相對於他們的消息最終到達的隊列,可以解決單個隊列所構成的潛在瓶頸。Pivotal RabbitMQ 教程演示了支持各種場景和路由方案的消息架構的構建。Google 使用了非常基本的例子。當然除了教程中涵蓋的場景之外,RabbitMQ 還存在更多的可能性,包括使用一致的哈希交換類型進行動態負載平衡場景。

其次,重要的是要注意個別節點的職責,尤其在負載非常高的集羣中。可以在羣集中的任何節點上啓用或禁用 RabbitMQ 管理插件。RabbitMQ 管理插件提供上述基於 Web 的管理 UI,以及相應的基於 HTTP 的管理 API,還可以作爲統計其他集羣節點報告性能指標。在大型集羣中,許多節點都是報告度量,目前統計數據庫都可能成爲瓶頸。因此,Google 在實驗過程中,單獨創建了一個信息統計節點,並將其從負載均衡器的後端服務器列表中排除掉,從而消息生產與消費不會經過該節點,統計信息與生產消費也就不會發生競爭資源的情況。

在 AWS 上使用同等規模與配置的環境,驗證了 Google 提供的測試結果後,又做了一些別的嘗試,如使用 RabbitMQ Sharding 插件、Consistent-hash Sharding Exchange 來更加靈活的動態均衡隊列壓力,同樣可以達到此類性能。

RabbitMQ Sharding 插件

下面介紹下如何使 Sharding 插件,3.6.0 以及以後的 RabbitMQ 版本啓用 Sharding 插件,使用命令:

rabbitmq-pluginsenable rabbitmq_sharding

在大規模集羣上,配置節點多分片隊列,可以有效分攤單隊列的性能瓶頸。這個插件能夠讓分片隊列自動擴展,如果您添加更多的節點到您的 RabbitMQ 羣集,那麼該插件將自動在新節點中創建更多的分片。假設集羣初始僅有一個節點 A,配置每個節點分佈 4 個分片隊列,現在將節點 B 加入了節點 A 所在羣集。插件將自動在節點 b 中創建 4 個隊列,並將它們連接到分片分區。已經傳遞的消息將不會被重新平衡,但新到達的消息將被分區到新的隊列。

默認情況下 RabbitMQ 的交換機以”all or nothing”方式工作,即:如果路由 key 與綁定到交換機的一組隊列匹配,則 RabbitMQ 將將消息路由到該集合中的所有隊列。因此,爲了使這個插件能正常工作,我們需要將消息路由到一個交換機來分配消息,讓消息最多被分配到一個隊列。該插件提供了一種新的 Exchange 類型 “x-modulus-hash”,它將使用傳統的哈希技術應用於跨隊列分區消息。“x-modulus-hash” 交換機將對用於發佈消息的 Routing-Key 進行 hash,然後將 hash 值 mod N 來選擇路由消息的隊列,其中 N 是綁定到交換機的隊列數。此交換將完全忽略用於將隊列綁定到交換機的 Routing-Key。如果只需要消息分區,而不是由此插件提供的自動隊列創建,那麼只需使用一致的哈希 Exchange,這個後面介紹。

安裝插件後,您可以通過設置與交換名稱匹配的策略來定義交換分片。例如,如果我們有一個稱爲 shard.images 的交換,我們可以定義以下策略來分片:set_policy images-swarding "^images"

這將爲集羣中的每個節點創建 2 個分片隊列,並使用 Routing

key:”hello” 對這些隊列進行綁定,隨後定義一個名爲 images 的 exchange。

隨後,插件會自動在每個節點上創建 2 個分片隊列,名爲 “sharding:images-*”。

在上面的例子中,我們在定義策略時使用路由 key 爲 “hello”。這意味着用於分片的底層交換機將使用上面指定的 hello 路由 key 將分片隊列綁定到交換機。這意味着對於“Direct-Exchange”,使用路由密鑰 hello 發佈的息將被路由到所有的分片隊列。如果您決定使用“Fanout-exchange” 進行分片,則在綁定期間使用的 “hello” 路由 key 將被交換機忽略。如果使用 “x-modulus-hash” 交換,則路由 key 也將被忽略。因此,根據您使用的交換機,路由策略定義在路由消息時會產生影響。

Consistent-sharding Exchange

在某些情況下,你可能希望發送到交換機的消息是一致和均勻地分佈在多個不同的隊列。在上面的插件中如果隊列數量發生變化,則不難確保新的拓撲結構仍然在不同隊列之間均勻分配消息,此時就可以藉助 Consistent-sharding 類型 Exchange,與 Sharding 插件的主要區別是,該類 Exchange 不能自動創建分片隊列,需要手動創建並配置 Binding 關係,且支持一致性 hash。

在作爲交換類型的一致哈希的情況下,從所接收的每個消息的 Routing-key 進行哈希計算後散列存儲。因此,具有相同 Routing-Key 的消息將具有計算的相同散列,將被路由到相同的隊列。將隊列綁定到一致性哈希的 Exchange 時,綁定 key 是一個數字字符串,表示希望該隊列在整個 hash 空間中佔有的點數。具有相同 Routing-key 的所有消息將進入相同的隊列。因此,如果希望隊列 A 接收路由消息是隊列 B 接收路由消息的兩倍,那麼需要將隊列 A 綁定到 Exchange 的綁定 Key(字符串的數字)設置爲隊列 B 的綁定 Key 的 2 倍。當然,只有當你的路由 Key 均勻分佈在散列空間中時纔是這種情況。例如,如果在所有消息上僅使用兩個不同的路由 Key,即使其他隊列在其綁定 Key 中具有較高的值,兩個密鑰也可能路由到同一個隊列。使用更大的路由 Key 集合,路由 Key 的統計分佈接近綁定 Key 的設置的比率。

在這種情況下,隨機 Routing-key 的消息最終將會均勻分佈到兩個隊列中。

RabbitMQ 可靠性與可用性討論

但是如何確保消息傳遞的可靠性以及如何配置高可用,很多人都一直存在疑惑,實踐纔是檢驗真理的唯一標準,所以基於有貨某些使用場景,也分析總結下經驗與教訓,希望對大家有所幫助。

場景 1,如何保證消息的傳遞可靠,生產者與消費者互不感知,那麼怎麼確認生產者已將消息投遞到 RabbitMQ 服務端,又如何確認消費者已經消費了該消息?這裏需要使用的 RabbtiMQ 提供的生產者 Confirm 機制、消費者 Ack 機制來解決;

使用標準 AMQP 0-9-1,保證消息不丟失的唯一方法是使用事務:使信道事務發佈,發佈消息,提交。在這種情況下,交易是不必要的重量級,並將吞吐量降低 250 倍。爲了彌補這一點,引入了確認機制。它模仿了協議中已經存在的消費者確認機制。

要啓用確認,客戶端發送 confirm.select 方法。根據是否設置不等待,RabbitMQ Broker 可以通過 confirm.select-ok 進行回覆。一旦在通道上使用了 confirm.select 方法,就被認爲處於確認模式。事務通道不能進入確認模式,一旦通道處於確認模式,則不能進行事務處理。

一旦通道處於確認模式,代理和客戶端都會計數消息(從第一個 confirm.select 開始計數)。然後 Broker 通過在同一個頻道上發送 basic.ack 來確認消息。發送標籤字段包含已確認消息的序列號。Broker 還可以在 basic.ack 中設置多個字段,表明所有小於該序列號的消息都已到達並被處理。

何時確認呢?對於無法路由的消息,一旦 exchange 驗證了消息不會被路由到任何隊列(返回一個空列表的隊列),Broker 將發出確認。如果消息的發送屬性指定了爲強制性(mandatory),則 basic.return 將在 basic.ack 之前發送給客戶端。否定的確認也是如此(basic.nack)。

對於可以路由的消息,當所有隊列接受消息時,發送 basic.ack。對於路由到持久隊列的持久消息,這意味着已保存到磁盤。對於鏡像隊列,這意味着隊列的所有鏡像都已接受該消息。

當 RabbitMQ 交付消息給 Consumer 時,需要確認 Message 已被投遞到 Consumer。Acknowledgemenets 作用,consumer 通知 server 已收到消息或者成功消費消息,根據使用的確認模式,RabbitMQ 可以在發送(寫入 TCP 套接字)後或當接收到顯式(“手動”)客戶端確認信息時立即考慮成功傳遞的消息。手動發送的確認可以是正面或負面的,並使用以下協議方法之一:

basic.ack 用於肯定確認;basic.nack 用於否定確認(注意:這是 AMQP

0-9-1 的 RabbitMQ 擴展);basic.reject 用於否定確認,但與 basic.nack 相比有一個限制;肯定的確認只是指示 RabbitMQ 記錄一個消息傳遞。與 basic.reject 的否定確認具有相同的效果。差異主要在語義上:肯定確認假設一條消息已成功處理,而其負面對應方則表示傳送未被處理但仍應被刪除,可以批量手動確認以減少網絡流量。

綜上所述,在 1 的位置需要開啓 Channel 的 Confirm 模式,接收 RabbitMQ 服務端發送的確認消息已到達的 Ack 信息;在 3 的位置,消費者在成功消費或者業務處理失敗後,需要顯示告訴 RabbitMQ 服務端,消息已被消費成功或者失敗;

在某些類型的網絡故障中,數據包丟失可能意味着中斷的 TCP 連接需要較長時間才能夠被操作系統檢測到。AMQP 0.9.1 提供心跳功能,以確保應用程序層及時發現連接中斷。在我們的部署架構中,ELB 與 RabbitMQ 之間就是通過此機制來判斷服務是否存活,是否提示生產者服務端已掛,異步等待 confirm 的消息直接進入 unconfirm 的處理環節。

另外爲了避免在代理中丟失消息,我們需要應對代理重新啓動,代理硬件故障,甚至破壞代理崩潰。爲了確保重新啓動時消息和代理定義生效,我們需要確保它們在磁盤上持久化。AMQP 標準具有交換,隊列和持久消息的耐久性概念,要求持久對象或持久消息將在重新啓動後生存。

場景 2,如何實現處理失敗後重試機制;

某些情況下,業務在處理消息時可能會失敗,此時需要做的是重試,而不是直接丟棄;當然重試也不能僅僅是直接重試,一旦有任務長時間失敗,會導致後面的消息無法被正常處理,此時可以藉助死信機制轉發投遞到重試隊列後,隨後再嘗試重新處理該消息;

那如何實現呢?下面介紹下具體操作;

x-dead-letter-exchange: 死信轉發的 exchange;x-dead-letter-routing-key:死信轉發時的 routing-key;該隊列綁定到名爲 “amp.topic” 的 topic 類型 exchange,接收 routing-key 爲 “yoho_test_retry” 的消息;

死信轉發到 “amp.topic” 的 exchange,routing-key 爲 “yoho_test_retry”(即工作隊列接收該主題消息);x-message-ttl:message 在重試隊列中存活的時間,也就是延遲多久重試;該隊列綁定到“amp.topic”,接收 routing-key 爲“retry.yoho_test_retry” 的消息(即接收工作隊列的死信),這樣就可以實現重試隊列的機制了。

場景 3,如何實現定時任務;

定時任務,這也是一種常見的需求,那如何在 RabbitMQ 中實現這個能力,可以讓某些任務延時執行。其實同樣的也可以藉助死信機制來實現,如隊列 A 用於接收暫存 Producer 的消息,隊列 B 用於 Consumer 的消費,在隊列 A 中指定消息的 ttl 即生命週期時長,同時指定其死信交換機 DLXs,一旦消息在隊列中存活時長超過 ttl 的設定值,那麼消息會被轉發到 DLXs,綁定隊列 B 到 DLXs,即可接收到隊列 A 的死信;

下面具體看下操作流程;

從 “amp.topic” 的 exchange 中接收 routing-key 爲 “delay.yoho_test_delay” 主題的消息;

死信轉到交換機 “amp.topic” 中,消息的 routing-key 爲 “delay.yoho_test_delay”(即工作隊列接收的延遲消息的隊列),消息在延遲隊列中存活時間 ttl,同時該隊列綁定到“amp.topic” 交換機,接收 routing-key 爲 “yoho_test_delay” 注意的消息(即生產發送消息指定的 topic);如此一來延遲隊列接收消息後,等待 ttl 時長,將消息轉發到工作隊列中,即可實現延遲隊列機制;

場景 4,如何跨中心共享消息;

有時跨中心業務需要共享消息,如緩存清理等,在業務代碼中分別向多箇中心的 RabbitMQ 發佈消費消息顯然不是一種比較好的解決方案,那還有什麼好的方法呢,RabbitMQ 爲此提供了 Federation 插件來很好的解決此類問題;

Federation 插件是一個在不需要 cluster,而在 brokers 之間傳輸消息的高性能插件,Federation 插件可以在 brokers 或者 cluster 之間傳輸消息,連接的雙方可以使用不同的 users 和 virtual hosts,或者雙方的 rabbitmq 和 erlang 的版本不一致,Federation 插件使用 AMQP 協議通訊,可以接受不連續的傳輸。

Federation 插件允許你配置一個 exchanges Federation 或者 queues Federation。一個 exchange/queues federation 允許你從一個或者多個 upstream 接受信息 (就是遠程的 exchange/queues 或者其他 brokers),一個 federation exchange 可以路由消息到一個本地 queue 中,一個 federation queue 可以使一個本地的 consumer 接受從 upstream queue 過來的消息。下面分別看下如何啓用,創建以及兩者的區別:

(1)啓動 Federation 插件命令:

rabbitmq-pluginsenable rabbitmq_federation

(2)啓動 web 配置插件:

rabbitmq-pluginsenable rabbitmq_federation_management

Federation exchanges,可以看成 downstream 從 upstream 主動拉取消息,但並不是拉取所有消息,必須是在 downstream 上已經明確定義 Bindings 關係的 exchange,也就是有實際的物理 queue 來接收消息,纔會從 upstream 拉取消息到 downstream。使用 AMQP 協議實施代理間通信。Downstream 會將綁定關係組合在一起,綁定 / 解除綁定命令將發送到 upstream 交換機。因此,Federation 交換機只接收具有訂閱的消息。

任何 upstream exchange 接收到的消息都可能被 downstream 中 Federation exchange 接收到,但直接發送給 Federation Exchange 的消息是不能 upstream 中所綁定的 exchange 接收到的。

Federation queues 與 Federationexchange 最大的區別共享消息的機制不同,Federation 隊列僅在本地消耗消息時檢索消息,消費者需要消息,並且 Upstream 隊列具有未被消費的消息。這樣做的目的是確保消息僅在需要時,纔會在聯合隊列之間傳輸。

先看下創建過程,如下創建一個名爲 “fqueue_test” 的 federation

Federation 隊列可以被聲明爲任何其他隊列。爲了使 RabbitMQ 能夠識別出隊列需要聯合,還有哪些節點消息應該被消耗,Downstream(消費)節點需要進行配置。

通過聲明策略來完成配置。策略是隊列名稱匹配的模式。匹配隊列將聯合。Federation 隊列只能屬於一個策略。如果多個策略與隊列名稱匹配,則應用優先級最高的策略。當兩個策略具有相同的優先級時,隨機選擇匹配的策略。

Federation 隊列可以作爲另一個 Federation 隊列的 “上游”,甚至可以形成 “循環”,例如,隊列 A 將隊列 B 聲明爲上游,隊列 B 將隊列 A 聲明爲上游。允許更復雜的多重連接的安排。Federation 隊列將使用 AMQP 連接到其所有上游隊列。在聲明或配置聯合隊列時,每個上游隊列都將列出用於建立鏈接的連接屬性。

每個單獨的隊列分別應用其參數,例如,如果在聯合隊列上設置 x-max-length,則該隊列的長度將受限制(可能會在其已滿時丟棄消息),但與其聯合的其他隊列將不受影響。特別要注意的是,當每個隊列或每個消息的 TTL 被使用時,當一個消息被傳送到另一個隊列時,它的定時器將被重置。

與 Federation 交換機不同,在 Federation 隊列之間可以轉發消息的次數沒有限制。在一組相互聯合的隊列中,消息將移動到空閒消費容量的位置。因此,如果閒置消費容量繼續移動,消息將繼續移動。上述就是 Federation 的使用方法以及注意點,當然與其他插件的配合,可以衍生出多種使用方法。

場景 5,如何保證消息隊列的高可用,這樣的場景很多比如核心業務的訂單服務、erp 服務等等。

默認情況下,RabbitMQ 羣集中的隊列位於單個節點(首次被聲明的節點上),而 Exchanges 和 Bindings 可以認爲在所有節點上存在,可以選擇在 cluster 中跨節點節點之間配置爲鏡像隊列。每個鏡像隊列由一個 master 和一個或多個 slave 組成,如果 master 因爲某些原因失效,則將從 slave 中選擇一個提升爲 master。

發佈到隊列的消息將複製到所有鏡像。消費者連接到主機,無論它們連接到哪個節點,鏡像會丟棄已在主設備上確認的消息。隊列鏡像因此增強了可用性,但不跨節點分配負載(所有參與節點都執行所有工作)。

隊列已被配置爲鏡像,master 節點位於 server5,slave 節點位於 server6,此時,隨意關閉任意一臺 RabbitMQ 節點,該隊列都可以正常對外提供服務。

A 先掛,B 後掛,master 轉移 B,此時需先拉起 B,後拉起 A,可恢復鏡像隊列;

A、B 同時掛,同時拉起,可恢復鏡像隊列;

若新加入 cluster 節點,最好不要在生產環境手工同步,採用自然同步方式,對於沒有工作 queue 可以手工同步操作(同步操作時,queue 是不可用的);當所有 slave 都處在 (與 master) 未同步狀態時,並且 ha-promote-on-shutdown policy 設置爲 when-syned(默認)時,如果 master 因爲主動的原因停掉,比如是通過 rabbitmqctl stop 命令停止或者優雅關閉 OS,那麼 slave 不會接管 master,也就是說此時鏡像隊列不可用;但是如果 master 因爲被動原因停掉,比如 VM 或者 OS crash 了,那麼 slave 會接管 master。這個配置項隱含的價值取向是優先保證消息可靠不丟失,放棄可用性。如果 ha-promote-on-shutdown policy 設置爲 alway,那麼不論 master 因爲何種原因停止,slave 都會接管 master,優先保證可用性。

A、B 都未掛,兩者網絡異常,各自爲 master,此時出現網絡分區衝突,必須手工介入保證消息不丟失,萬不可隨意重啓導致數據丟失(不論是否持久化), 將一臺數據量較小的從 cluster 中剔除,消費完成後再重啓恢復鏡像;或者將其中一臺從集羣中剔除後,加入另外一臺 slave,再消費完成剔除的節點中數據;(會出現重複消費,此時需要客戶端做冪等處理保證唯一一次消費)

當然在高可用的場景下,隊列的性能會受到一定的影響,此時可以藉助上面提到的 Sharding 機制(根據場景選擇 x-modulus-hash 還是 consistent-hash),解決單隊列的性能瓶頸,在高可用、高併發下尋求一個動態的平衡;

上圖爲鏡像場景的壓測結果,對比普通集羣,鏡像對性能的影響很明顯,消息持久化也拉低了集羣的性能,適當增加 Prefetch 可以提高集羣性能。

性能與高可靠、高可用,魚和熊掌不可兼得,所以欲提升 RabbitMQ 集羣或單節點服務的性能,犧牲可靠性(根據場景來),在消費能力範圍內,儘量提高 prefetch 的數量,其次就是簡單粗暴型(加機器(隊列實際存儲節點性能未榨乾,建議隊列均衡分配到各節點)、加配置)。

Spring AMQP 提供了一個 API,可輕鬆訪問 AMQP 消息代理。像往常一樣,Spring 模板作爲技術細節的抽象。對於 AMQP,AmqpTemplate 可以做到這一點。

Spring-amqp 項目擁有所有必要的通用接口(例如 AmqpTemplate)和 API 類,而具體的實現則依賴 spring-rabbitmq,Spring-rabbitmq 依賴於 RabbitMQ amqp-client 的通用 Java API。客戶端應用程序僅依靠 spring-amqp 來實現松耦合。能夠從一個 AMQP 代理切換到另一個 AMQP 代理,而不會在代碼中進行任何重大更改。

作者:有貨技術

來源:www.jianshu.com/p/ddca1548d0a1

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/tYKsbAjPHIk-uEjKxElP5w