1. 程式人生 > 程式設計 >Dubbo調優(二) -- 限流策略

Dubbo調優(二) -- 限流策略

一:前情導讀

高併發環境下若生產者不能及時處理請求造成大量請求執行緒積壓,最終會演變為大面積服務崩潰現象產生。根據服務特點設定合理的請求拒絕策略,保證服務正常執行是本文重點。當然必須區別於負載均衡只能分配流量而不能限制流量

在這裡插入圖片描述

二:消費端actives

僅針對消費者端生效,只能在<dubbo:reference>亦或是其子標籤<dubbo:method>或者是<dubbo:consumer>中配置。優先順序策略與文章Dubbo調優 -- 超時TimeOut描述一致

2.1 配置示例
2.2 引數詳解
描述 備註
作用 消費者最大併發數量限制,超過限制將會丟擲異常
實現 過濾器Filter,具體實現子類為ActiveLimitFilter
預設值 0表示沒有限制
配置地點 <dubbo:consumer>、<dubbo:reference> 、<dubbo:method>
2.3 原始碼導讀

在這裡插入圖片描述

  1. 處理請求引數:URL為Dubbo封裝的一個請求物件類,包含Map<String,String>型別屬性numbers,該屬性中含有actives配置
  2. 請求過濾判斷:RpcStatus類封裝生產者呼叫狀態,AtomicInteger原子型別active屬性儲存當前呼叫數量。通過其與URL中獲取到的對應引數屬性值比較判斷
  3. 請求返回結果:如果允許則進行下一步RPC呼叫,不允許則會暫停等待執行緒timeout引數時長,若喚醒還未有空餘執行緒則丟擲異常

三:消費端connections

大家熟悉的HTTP協議就屬於短連線,每次請求的時候都會多次驗證握手建立連線。預設的Dubbo協議屬於長連線,採用NIO非同步傳輸,每消費者與生產者之間預設採用單一長連線方式通訊。換個簡單說法就是每個消費者與生產者之間長連線預設就建立一個,所有請求共用

connections引數針對上述長連線與短連線具備不同作用效果:

  • 短連線因為是多連線所以限制其個數
  • 長連線因為是單一連線所以是指定其建立數量
3.1 配置示例

connections引數生效的位置在消費端,圖一表示消費端的配置,圖二表示在生產者的配置。根據自身測試以及github驗證,生產端的配置確實會通過註冊中心傳遞給消費端生效

在這裡插入圖片描述
在這裡插入圖片描述

3.2 引數詳解
描述 備註
作用 限制消費者短連線數量,長連線建立數量
實現 初始化連線時根據引數控制
預設值 長連線預設表示使用JVM共享長連線,線上一般都是多生產多消費,這個引數不建議更改
配置地點 <dubbo:consumer>、<dubbo:reference> 、<dubbo:provider>、<dubbo:service>
3.3 原始碼導讀

首先專案初始化的時候會根據connections引數初始化連線,過程在DubboProtocol類的getClients()方法中,下圖是debug跟進的初始化結果。可以看到用於儲存連線的陣列最後返回的是兩個連線例項

在這裡插入圖片描述
連線使用發生在類DubboInvoker中,該類的方法doInvoke()用於執行呼叫邏輯。使用的連線就是在DubboProtocol類中getClients()初始化出來並在方法refer()中放入DubboInvoker物件的連線。如下圖所示是DubboInvoker中doIncoke()使用連線的關鍵程式碼
在這裡插入圖片描述

四:生產端accepts

消費者可以通過connections引數設定連線的數量,但是如果生產者不進行自我保護,採用預設的無限制連線策略。高併發情況下生產者可能就會因為連線數量巨大崩潰,這時可以通過引數accepts限制生產者可接受最大連線數量

4.1 配置示例

accepts用於生產者限制最大連線數量保護自身服務可用性,可以在標籤<dubbo:protocol>中進行配置。這時候在<dubbo:reference>中設定connections超過accepts值,用於方便後續的原始碼跟進

在這裡插入圖片描述
在這裡插入圖片描述

4.2 引數詳解
描述 備註
作用 限制生產者最大可接受連線數量,用於保護生產者自身
實現 消費者初始化建立連線時會開啟建立連結,這時候就會根據限制引數判斷
預設值 0表示沒有限制,比較危險的配置
配置地點 <dubbo:protocol>
4.3 原始碼導讀

生產者啟動初始化過程中可以看到開啟連線的時候獲取了引數accepts的設定,過程在AbstractServer類建構函式中可以看到

在這裡插入圖片描述
消費端初始化的時候當超過生產者限制連線數量後,在AbstractClient類中可以看到,建構函式中呼叫方法connect()建立連線。這時候會丟擲異常,因為異常原因是等待建立連線超時3000ms。驗證引數accepts效果
在這裡插入圖片描述

五:生產端執行緒池

多執行緒併發操作一定離不開執行緒池,Dubbo自身提供了支援了四種執行緒池型別支援。生產者<dubbo:protocol>標籤中可配置執行緒池關鍵引數,執行緒池型別、阻塞佇列大小、核心執行緒數量等

5.1 iothreads、threads
  • iothreads:限制的是io執行緒池大小,該執行緒池執行緒用於處理Dubbo框架自身業務邏輯。預設值為CPU+1,不建議更改設定
  • threads:用於指定下面講到的業務執行緒池執行緒數量,這個才是業務需要關心的執行緒數量。預設大小200
5.2 threadpool

引數threadpool指定使用執行緒池型別,Dubbo中自身實現提供瞭如下表所示四種執行緒池。預設使用固定大小執行緒池FixedThreadPool

型別名稱 佇列型別 特性備註
FixedThreadPool queues屬性為0建立無容量阻塞佇列SynchronousQueue,若 queues小於0則建立Integer.MAX_VALUE容量LinkedBlockingQueue阻塞佇列,大於0則建立 queues引數限定容量LinkedBlockingQueue阻塞佇列 核心執行緒數量與最大執行緒數量一致採用引數threads值、執行緒空閒存活時間0
CachedThreadPool 佇列建立型別規則與FixedThreadPool一致 相對於固定容量大小FixedThreadPool執行緒池多了引數corethreads設定核心執行緒數量支援預設0,執行緒空閒存活時間暫時未提供引數設定,預設1分鐘
LimitedThreadPool 佇列建立型別規則與FixedThreadPool一致 相對於CachedThradPool而言最大的變化在於執行緒存活時間修改為Long.MAX_VALUE
EagerThreadPool 佇列為Dubbo設計實現的TaskQueue佇列,該佇列繼承自LinkedBlockingQueue。當queues引數小於等於0則其容量為1,若大於0則容量為queues引數值 後面會有專門文章研究這個執行緒池實現
5.3 注意

Dubbo官網檔案只描述了fixed/cached,四種執行緒池預設支援的是fixed

六:生產端executes

一個只能在生產者即dubbo:service亦或是其子標籤dubbo:method中配置的屬性,消費者中配置不會生效。這個引數主要目的是在生產者端限制應用執行緒使用數量

6.1 配置示例

限制該服務每個方法併發不超過10,其中dubboProtocolGetMethod方法併發不超過2。方法級別的配置優先順序高於服務配置

在這裡插入圖片描述

6.2 引數詳解
配置地點 生產者dubbo:service標籤或其子標籤dubbo:method
預設值 0表示沒有限制
作用 服務提供者每個方法只能佔用執行緒池中配置數量執行緒,超出則丟擲異常
實現 過濾器Filter
6.3 原始碼導讀
  • 主要涉及類:ExecuteLimitFilter,關注相關類RpcStatus、URL
  • 主要方法:getMethodParameter()、beginCount()、getStatus()
    在這裡插入圖片描述
  1. 處理請求引數,URL為Dubbo封裝的一個請求物件類,包含Map<String,String>型別屬性numbers,該屬性中含有executes配置
  2. 提取executes引數值,numbers -- paramters -- 預設值順序返回
  3. 比較executes值數量,RpcStatus類封裝生產者呼叫狀態,AtomicInteger原子型別active屬性儲存當前呼叫數量