爲什麼使用原因是?
服務之間的傳遞常用的調用就是直接調用(RPC框架)和消息MQ推送兩種,但是都有一個缺點,下游消息接收方無法控制到達自己的流量,如果調用方不限速,很有可能把下游壓垮。
背景信息
在實際應用中,收到的請求是沒有規律的。例如:某應用的處理請求的能力是每秒 10 個。在某一秒,突然到來了 30 個請求,而接下來兩秒,都沒有請求到達。在這種情況下,如果直接拒絕 20 個請求,應用在接下來的兩秒就會空閒。所以,需要把驟增的請求平均到一段時間內,讓系統負載保持在請求處理水位之內,同時儘可能地處理更多請求
上圖中,紅色的部分代表超出消息處理能力的部分。把紅色部分的消息平均到之後的空閒時間去處理,這樣既可以保證系統負載處在一個穩定的水位,又可以儘可能地處理更多消息。通過配置流控規則,可以達到消息勻速處理的效果。
舉個例子,秒殺業務:
上游發起下單操作
下游完成秒殺業務邏輯(庫存檢查,庫存凍結,餘額檢查,餘額凍結,訂單生成,餘額扣減,庫存扣減,生成流水,餘額解凍,庫存解凍等等)
上游下單業務簡單,每秒發起了10000個請求,下游秒殺業務複雜,每秒只能處理2000個請求,很有可能上游不限速的下單,導致下游系統被壓垮,引發雪崩。
爲了避免雪崩,常見的優化方案有兩種:
1)業務上游隊列緩衝,限速發送
2)業務下游隊列緩衝,限速執行
1、業務下游隊列緩衝,限速執行第一種方法
問:MQ怎麼改能緩衝流量?
答:由MQ-server推模式(常用模式),升級爲MQ-client拉模式。
MQ-client根據自己的處理能力,每隔一定時間,或者每次拉取若干條消息,實施流控,達到保護自身的效果。並且這是MQ提供的通用功能,無需上下游修改代碼。
問:如果上游發送流量過大,MQ提供拉模式確實可以起到下游自我保護的作用,會不會導致消息在MQ中堆積(提升整體吞吐量)?
答:下游MQ-client拉取消息,消息接收方能夠批量獲取消息,需要下游消息接收方進行優化,方能夠提升整體吞吐量,例如:批量寫。
rocketMQ的拉取模式代碼 https://blog.csdn.net/zhaohongfei_358/article/details/101457563
rabbitMQ拉取模式代碼 https://my.oschina.net/u/3959468/blog/2979069
2、業務下游隊列緩衝,限速執行第二種方法
rabbitMQ 提供了一種 QOS (服務質量保證)功能,即在非自動確認消息的前提下,如果一定數目的消息(通過基於 consume 或者 channel 設置 QOS 的值)未被確認前,不進行消費新的消息。關鍵代碼就是在聲明消費者代碼裏面的
void basicQos(unit prefetchSize , ushort prefetchCount, bool global )
-
prefetchSize:0
-
prefetchCount:會告訴 RabbitMQ 不要同時給一個消費者推送多於 N 個消息,即一旦有 N 個消息還沒有 ack,則該 consumer 將 block 掉,直到有消息 ack
-
global:true、false 是否將上面設置應用於 channel,簡單點說,就是上面限制是 channel 級別的還是 consumer 級別
備註:prefetchSize 和 global 這兩項,rabbitmq 沒有實現,暫且不研究。特別注意一點,prefetchCount 在 no_ask=false 的情況下才生效,即在自動應答的情況下這兩個值是不生效的。