Sentinel之Slots插槽源碼分析降級規(guī)則(六)

一、引子

除了流量控制以外,對調(diào)用鏈路中不穩(wěn)定的資源進行熔斷降級也是保障高可用的重要措施之一。由于調(diào)用關(guān)系的復(fù)雜性,如果調(diào)用鏈路中的某個資源不穩(wěn)定,最終會導(dǎo)致請求發(fā)生堆積。Sentinel 熔斷降級會在調(diào)用鏈路中某個資源出現(xiàn)不穩(wěn)定狀態(tài)時(例如調(diào)用超時或異常比例升高),對這個資源的調(diào)用進行限制,讓請求快速失敗,避免影響到其它的資源而導(dǎo)致級聯(lián)錯誤。當資源被降級后,在接下來的降級時間窗口之內(nèi),對該資源的調(diào)用都自動熔斷(默認行為是拋出 DegradeException)。

二、降級策略

我們通常用以下幾種方式來衡量資源是否處于穩(wěn)定的狀態(tài):

  • 平均響應(yīng)時間 (DEGRADE_GRADE_RT):當資源的平均響應(yīng)時間超過閾值(DegradeRule 中的 count,以 ms 為單位)之后,資源進入準降級狀態(tài)。接下來如果持續(xù)進入 5 個請求,它們的 RT 都持續(xù)超過這個閾值,那么在接下的時間窗口(DegradeRule 中的 timeWindow,以 s 為單位)之內(nèi),對這個方法的調(diào)用都會自動地返回(拋出 DegradeException)。
  • 異常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):當資源的每秒異??倲?shù)占通過量的比值超過閾值(DegradeRule 中的 count)之后,資源進入降級狀態(tài),即在接下的時間窗口(DegradeRule 中的 timeWindow,以 s 為單位)之內(nèi),對這個方法的調(diào)用都會自動地返回。異常比率的閾值范圍是 [0.0, 1.0],代表 0% - 100%。
  • 異常數(shù) (DEGRADE_GRADE_EXCEPTION_COUNT):當資源近 1 分鐘的異常數(shù)目超過閾值之后會進行熔斷。

注意:異常降級僅針對業(yè)務(wù)異常,對 Sentinel 限流降級本身的異常(BlockException)不生效。為了統(tǒng)計異常比例或異常數(shù),需要通過 Tracer.trace(ex) 記錄業(yè)務(wù)異常。示例:

Entry entry = null;
try {
  entry = SphU.entry(key, EntryType.IN, key);

  // Write your biz code here.
  // <<BIZ CODE>>
} catch (Throwable t) {
  if (!BlockException.isBlockException(t)) {
    //這里會統(tǒng)計異常數(shù)
    Tracer.trace(t);
  }
} finally {
  if (entry != null) {
    entry.exit();
  }
}

開源整合模塊,如 Sentinel Dubbo Adapter, Sentinel Web Servlet Filter 或 @SentinelResource 注解會自動統(tǒng)計業(yè)務(wù)異常,無需手動調(diào)用。

三、源碼分析

3.1 DegradeSlot

public class DegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, Object... args)
        throws Throwable {
       //規(guī)則檢查
        DegradeRuleManager.checkDegrade(resourceWrapper, context, node, count);
        fireEntry(context, resourceWrapper, node, count, args);
    }

    @Override
    public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        fireExit(context, resourceWrapper, count, args);
    }
}

進入DegradeRuleManager中,可以發(fā)現(xiàn)與前面的限流規(guī)則一樣,這個是用于管理降級的類。
我們重點看下checkDegrade方法。

3.2 DegradeRuleManager

    public static void checkDegrade(ResourceWrapper resource, Context context, DefaultNode node, int count)
        throws BlockException {
        if (degradeRules == null) {
            return;
        }

        List<DegradeRule> rules = degradeRules.get(resource.getName());
        if (rules == null) {
            return;
        }

        for (DegradeRule rule : rules) {
            if (!rule.passCheck(context, node, count)) {
                throw new DegradeException(rule.getLimitApp());
            }
        }
    }
  1. degradeRule是對應(yīng)資源的額降級規(guī)則,是一個map。
  2. 獲取到對應(yīng)資源的降級規(guī)則。
  3. 調(diào)用Degrade的passCheck檢測是否需要降級。
  4. 若降級了則拋出DegradeException異常。

3.3 DegradeRule

降級規(guī)則的參數(shù)

  • count: RT臨界值或者異常數(shù)、異常比列
  • timeWindow:降級的時間間隔,單位秒
  • grade:閾值類型RT、異常數(shù)、異常比例

下面看下passCheck方法:

 @Override
    public boolean passCheck(Context context, DefaultNode node, int acquireCount, Object... args) {
        if (cut) {
            return false;
        }

        ClusterNode clusterNode = ClusterBuilderSlot.getClusterNode(this.getResource());
        if (clusterNode == null) {
            return true;
        }

        if (grade == RuleConstant.DEGRADE_GRADE_RT) {
            double rt = clusterNode.avgRt();
            if (rt < this.count) {
                passCount.set(0);
                return true;
            }

            // Sentinel will degrade the service only if count exceeds.
            if (passCount.incrementAndGet() < RT_MAX_EXCEED_N) {
                return true;
            }
        } else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {
            double exception = clusterNode.exceptionQps();
            double success = clusterNode.successQps();
            long total = clusterNode.totalQps();
            // if total qps less than RT_MAX_EXCEED_N, pass.
            if (total < RT_MAX_EXCEED_N) {
                return true;
            }

            double realSuccess = success - exception;
            if (realSuccess <= 0 && exception < RT_MAX_EXCEED_N) {
                return true;
            }

            if (exception / success < count) {
                return true;
            }
        } else if (grade == RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
            double exception = clusterNode.totalException();
            if (exception < count) {
                return true;
            }
        }

        synchronized (lock) {
            if (!cut) {
                // Automatically degrade.
                cut = true;
                ResetTask resetTask = new ResetTask(this);
                pool.schedule(resetTask, timeWindow, TimeUnit.SECONDS);
            }

            return false;
        }
    }

關(guān)鍵參數(shù):

  1. cut:資源是否已經(jīng)降級標志,為true表示已經(jīng)降級了。
  2. passCount:若達到降級條件后,連續(xù)復(fù)合降級條件的次數(shù),默認為RT_MAX_EXCEED_N(5)次。

過程大致如下:

  1. 如果已經(jīng)降級了(cut為ture),則阻塞;否則獲取clusterNode
  2. 降級規(guī)則為RuleConstant.DEGRADE_GRADE_RT,先獲取資源的平均RT;若RT小于設(shè)置的閾值count,則請求通過并設(shè)置passCount為0,否在判斷passCount是否小于5,若小于則請求通過;否則請求阻塞。
  3. 降級規(guī)則為RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO異常比例時,先獲取資源的exception數(shù),success數(shù),total數(shù)。若total數(shù)小于5請求通過;exception是小于5請求通過;異常比列exception/total小于設(shè)置的閾值則請求通過;否則請求阻塞。
  4. 降級規(guī)則為RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT異常數(shù)時,若異常數(shù)小于設(shè)置的閾值時則請求通過;否則請求阻塞。
  5. 若上述有規(guī)則不滿足,則說明該資源需要降級;降級時需要先設(shè)置cut為true,并啟動一個定時任務(wù)來設(shè)置降級時間窗口后降級的重置。該任務(wù)如下:
    private static final class ResetTask implements Runnable {

        private DegradeRule rule;

        ResetTask(DegradeRule rule) {
            this.rule = rule;
        }

        @Override
        public void run() {
            //設(shè)置passCount為0
            rule.getPassCount().set(0);
            //設(shè)置cut為false
            rule.setCut(false);
        }
    }

四、我的總結(jié)

  1. 介紹了Sentinel的j降級規(guī)則以及降級原理。
  2. 降級有三種策略,rt,異常數(shù),異常比例;目前dashboard控制臺能夠設(shè)置應(yīng)該就只有rt和異常比例了。
  3. 通過設(shè)置passCount來避免出現(xiàn)偶爾一個請求異常的情況,提高降級的準確性。
  4. 生產(chǎn)環(huán)境下建議使用設(shè)置rt策略來控制降級。

以上內(nèi)容,若有不當之處,請指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容