RabbitMQ 客戶端源碼系列 - Flow Controller 原理

前言
這次分享 RabbitMQ 自帶的保護 RabbitMQ 免于過載的功能 - Flow Controller(「流量控制」),如果不明白原理和場景使用 RabbitMQ 時,遇到 Flow Controller 容易一臉懵逼不知所措,今天我們就來了解它的原理。
什么是流量控制?
流控制是一個在計算機網絡和網絡軟件中存在了幾十年的概念。本質上,它是一種向發送方施加背壓以避免接收方過載的機制。接收器通常緩沖傳入的數據包/消息,作為處理超過其處理速率的發送速率的一種方式。但是接收器緩沖區不能永遠增長,因此發送速率只能暫時超過接收器處理能力(突發流量),或者發送器必須放慢速度(背壓)。
流量控制是一種向發送方施加這種背壓的方法,減慢它們的速度,以便接收方的緩沖區不會溢出并且延遲不會變得太大。在發送方/接收方鏈中,這種背壓可以沿鏈向上傳播到流量的源頭。在更復雜的連接組件圖中,流控制可以平衡快速和慢速發送方之間的傳入流量,避免過載,但允許系統在不同數量的發送方、不同的速率和不同的負載模式(穩定或突發)下達到充分利用。
RabbitMQ 中的流量控制
RabbitMQ 看起來很像一個網絡。每個 RabbitMQ Broker 在內部都使用 actor 模式實現,其中不同的組件通過消息傳遞相互通信,有時是在本地,有時是通過網絡。還有發布者通過網絡向代理發送消息,消費者從代理接收消息。

消息流的簡化描述
將系統作為一個整體(代理和客戶端),我們有四種可用的流量控制機制:
- 基于信用的流量控制。
- 內存報警。
- 發布者確認。
- 消費者確認和預取。
基于信用的流量控制
基于信用的流量控制是一種限制消息進入速率的方法。它允許系統內的各個參與者保護自己并在他們無法足夠快地處理消息時施加反壓。它僅針對那些有問題的連接、通道和隊列,而系統的其他部分不受影響。
它的工作方式是系統中處理消息的每個參與者都使用“信用”作為向鏈施加背壓的一種方式。如果通道想要向隊列發送消息,它需要信用。隊列授予通道一些初始信用,然后,通道發送到隊列的每條消息都需要一個信用。隊列將定期授予通道更多的信用,當它反過來能夠將消息傳遞到持久層時。如果通道沒有信用,它會被阻止向隊列發送消息,直到隊列授予它更多。這樣通道就不能粗暴地運行在隊列上。

經典隊列的基于信用的流量控制
所以我們有一個信用流控制鏈,可以一直向發布者施加背壓。最終,TCP 背壓將施加到發布者,因為 TCP 讀取器進程在被阻塞時不會從套接字讀取。
當連接、通道或隊列用完信用時,它們會被阻塞,直到授予更多信用,這種狀態稱為“流”。在管理 UI 中,您可能會看到連接、通道或隊列處于流狀態,這表明流最近發生。這只是意味著他們暫時用完了信用,正在等待鏈中的下一個環節趕上并授予一些信用。這可以每秒觸發多次。


信用枯竭

信貸贈款
當隊列或連接達到其吞吐量限制或下游瓶頸時,流狀態可以在鏈中的各個點每秒多次觸發,因為各個參與者的信用額度達到 0 然后得到補充。
但這并不一定會阻止代理耗盡內存。傳入消息并不總是高內存使用率的唯一主要原因,它也可能來自大隊列和許多其他原因。
內存警報
如果基于信用的流量控制無法充分剎車,或者內存使用量由于其他原因增長到臨界水平,則內存警報將作為最后的手段啟動,以保護代理免于崩潰(或被操作系統殺死)內存不足。
當內存警報開始時,所有發布者都會被阻止。這就像您關閉了跨集群的傳入消息的水龍頭。不是基于信用的流量控制的目標速率限制,而是大錘。
消費者可以繼續消費,此時希望排空隊列會開始減少內存占用。
在管理 UI 中,當內存警報生效時,您將看到連接被阻止或阻塞。
Memory
https://www.rabbitmq.com/memory.html。
發布者確認
發布者確認的主要工作是數據安全,但它們在流量控制中也起著重要作用。
有以下三種方式使用發布者確認:
- 一次發送一個,在發送下一個之前等待每個確認(非常慢)。
- 基于窗口的. 發送消息直到達到窗口大小(時間或消息數量)并在發送下一個窗口之前等待所有確認。
- 流水線。允許發布者連續發送消息,但在未確認的消息計數(傳輸中的消息)達到限制時阻止。當確認進來時,可以發送更多消息,直到再次達到限制。
流水線(或簡稱異步)方法提供最高和最穩定的吞吐量。它可以用作防止經紀人過載的額外保護,因為發布者本身甚至在對經紀人施加壓力之前就將自己置于“流”中。
當您不使用發布者確認時,您僅依靠 TCP 流控制來控制發布者和代理上的連接讀取器進程之間的鏈接。在發布者數量相對較少的情況下,TCP 流量控制足以避免代理過載,但是當您有大量客戶端時,TCP 是不夠的,并且發布者確認在重負載下對于集群穩定性變得必要。有趣的是,AMQP 1.0 添加了鏈路流控制來克服這個問題。
Publisher confirms
https://www.rabbitmq.com/confirms.html。
消費者確認和預取
使用帶有預取的手動確認會給 RabbitMQ 帶來壓力,以阻止它使您的消費者客戶端不堪重負。它使用流水線方法發送恒定的消息流,但將未確認消息的數量限制為預取 (QoS) 的大小。使用 AutoAck 模式,我們再次僅依賴 TCP 背壓。客戶端的各種入口緩沖區可能會很快填滿。
























