Alibaba微服務(wù)組件之 Sentinel 闖關(guān)

副本介紹

分布式系統(tǒng)中,我們往往會(huì)遇到一些服務(wù)可用性問(wèn)題?出現(xiàn)這些問(wèn)題的原因是什么?我們又應(yīng)該如何解決這些問(wèn)題呢?

第一關(guān):分布式系統(tǒng)中遇到的問(wèn)題

服務(wù)的可用性問(wèn)題

4個(gè)9 5個(gè)9 x個(gè)9。

x代表了3-5。 代表系統(tǒng)一年使用過(guò)程中,系統(tǒng)可以正常使用時(shí)間與總時(shí)間(1年)之比。

例如 4個(gè)9. (1-99.99%)x365x24=0.876小時(shí)=52.6分鐘,表示該系統(tǒng)在連續(xù)運(yùn)行1年時(shí)間里最多可能的業(yè)務(wù)中斷時(shí)間是52.6分鐘。

服務(wù)可用性問(wèn)題

服務(wù)雪崩效應(yīng): 因服務(wù)提供者的不可用導(dǎo)致服務(wù)調(diào)用者的不可用,并將不可用逐漸放大的過(guò)程,就叫服務(wù)雪崩效應(yīng)。

導(dǎo)致服務(wù)不可用的原因:

導(dǎo)致服務(wù)不可用的原因
Reliability && Resilience

常見(jiàn)的容錯(cuò)機(jī)制:

  • 超時(shí)機(jī)制

    在不做任何處理的情況下,服務(wù)提供者不可用會(huì)導(dǎo)致消費(fèi)者請(qǐng)求線程強(qiáng)制等待,而造成系統(tǒng)資源耗盡。加入超時(shí)機(jī)制,一旦超時(shí),就釋放資源。由于釋放資源速度較快,一定程度上可以抑制資源耗盡的問(wèn)題。

  • 服務(wù)限流

    服務(wù)限流
  • 隔離

    用戶的請(qǐng)求將不再直接訪問(wèn)服務(wù),而是通過(guò)線程池中的空閑線程來(lái)訪問(wèn)服務(wù),如果線程池已滿,則會(huì)進(jìn)行降級(jí)處理,用戶的請(qǐng)求不會(huì)被阻塞,至少可以看到一個(gè)執(zhí)行結(jié)果(例如返回友好的提示信息),而不是無(wú)休止的等待或者看到系統(tǒng)崩潰。

第二關(guān):Sentinel 介紹

Sentinel 是什么?

Sentinel 是阿里開(kāi)源的,面向分布式服務(wù)架構(gòu)的高可用防護(hù)組件。提供了多維度的流控降級(jí)能力,秒級(jí)實(shí)時(shí)監(jiān)控與動(dòng)態(tài)規(guī)則管理。主要以流量為切入點(diǎn),從限流、流量整形、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)、熱點(diǎn)防護(hù)等多個(gè)維度來(lái)幫助開(kāi)發(fā)者保障微服務(wù)的穩(wěn)定性。

Sentinel 具有以下特征:
  • 豐富的應(yīng)用場(chǎng)景: Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場(chǎng)景,例如秒殺(即突發(fā)流量控制在系統(tǒng)容量可以承受的范圍)、消息削峰填谷、實(shí)時(shí)熔斷下游不可用應(yīng)用等。
  • 完備的實(shí)時(shí)監(jiān)控: Sentinel 同時(shí)提供實(shí)時(shí)的監(jiān)控功能。您可以在控制臺(tái)中看到接入應(yīng)用的單臺(tái)機(jī)器秒級(jí)數(shù)據(jù),甚至 500 臺(tái)以下規(guī)模的集群的匯總運(yùn)行情況。
  • 廣泛的開(kāi)源生態(tài): Sentinel 提供開(kāi)箱即用的與其它開(kāi)源框架/庫(kù)的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應(yīng)的依賴并進(jìn)行簡(jiǎn)單的配置即可快速地接入 Sentinel。
  • 完善的 SPI 擴(kuò)展點(diǎn): Sentinel 提供簡(jiǎn)單易用、完善的 SPI 擴(kuò)展點(diǎn)。您可以通過(guò)實(shí)現(xiàn)擴(kuò)展點(diǎn),快速的定制邏輯。例如定制規(guī)則管理、適配數(shù)據(jù)源等。
Sentinel 分為兩部分:
  • 核心庫(kù)(Java 客戶端)不依賴任何框架/庫(kù),能夠運(yùn)行于所有 Java 運(yùn)行時(shí)環(huán)境,同時(shí)對(duì) Dubbo / Spring Cloud 等框架也有較好的支持。
  • 控制臺(tái)(Dashboard)基于 Spring Boot 開(kāi)發(fā),打包后可以直接運(yùn)行,不需要額外的 Tomcat 等應(yīng)用容器。
Sentinel 和 Hystrix對(duì)比
Sentinel和Hystrix對(duì)比

第三關(guān):Sentinel - 實(shí)踐<原生Spring>

1. 補(bǔ)充pom文件

        <!--sentinel核心庫(kù)-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.8.0</version>
        </dependency>

        <!--如果要使用@SentinelResource-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.0</version>
        </dependency>

        <!--整合控制臺(tái)-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.0</version>
        </dependency>

2. 啟動(dòng)類中配置bean - SentinelResourceAspect

如果是通過(guò) SpringCloud Alibaba 接入的 Sentinel,則無(wú)需進(jìn)行額外配置,就可以使用 @SentinelResource 注解

若使用的是Spring AOP ( 無(wú)論是 SpringBoot 還是 傳統(tǒng)的 Spring 應(yīng)用 ),則需要配置下面的bean

    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }

3. 自定義降級(jí)控流、熔斷的方法

   /**
     * 定義規(guī)則
     *
     * spring 的初始化方法
     */
    @PostConstruct  //該注解的接口會(huì)在spring啟動(dòng)的時(shí)候,自動(dòng)執(zhí)行
    private static void initFlowRules(){

        // 流控規(guī)則
        List<FlowRule> rules = new ArrayList<>();

        // 流控
        FlowRule rule = new FlowRule();
        // 為哪個(gè)資源進(jìn)行流控
        rule.setResource(RESOURCE_NAME); //資源名同接口地址
        // 設(shè)置流控規(guī)則 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 設(shè)置受保護(hù)的資源閾值
        // Set limit QPS to 20.
        rule.setCount(1);
        rules.add(rule);



        // 通過(guò)@SentinelResource來(lái)定義資源并配置降級(jí)和流控的處理方法
        FlowRule rule2 = new FlowRule();
        //設(shè)置受保護(hù)的資源
        rule2.setResource(USER_RESOURCE_NAME);
        // 設(shè)置流控規(guī)則 QPS
        rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 設(shè)置受保護(hù)的資源閾值
        // Set limit QPS to 20.
        rule2.setCount(1);

        rules.add(rule2);

        // 加載配置好的規(guī)則
        FlowRuleManager.loadRules(rules);
    }

    @PostConstruct  // 初始化
    public void initDegradeRule(){
        /*降級(jí)規(guī)則 異常*/
        List<DegradeRule> degradeRules = new ArrayList<>();
        DegradeRule degradeRule = new DegradeRule();
        degradeRule.setResource(DEGRADE_RESOURCE_NAME);
        // 設(shè)置規(guī)則策略: 異常數(shù)
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        // 觸發(fā)熔斷異常數(shù) : 2
        degradeRule.setCount(2);
        // 觸發(fā)熔斷最小請(qǐng)求數(shù):2
        degradeRule.setMinRequestAmount(2);
        // 統(tǒng)計(jì)時(shí)長(zhǎng):  單位:ms    1分鐘
        degradeRule.setStatIntervalMs(60*1000); //  時(shí)間太短不好測(cè)

        // 一分鐘內(nèi): 執(zhí)行了2次以上  出現(xiàn)了2次異常  就會(huì)觸發(fā)熔斷

        // 熔斷持續(xù)時(shí)長(zhǎng) : 單位 秒
        // 一旦觸發(fā)了熔斷, 再次請(qǐng)求對(duì)應(yīng)的接口就會(huì)直接調(diào)用  降級(jí)方法。
        // 10秒過(guò)了后——半開(kāi)狀態(tài): 恢復(fù)接口請(qǐng)求調(diào)用, 如果第一次請(qǐng)求就異常, 再次熔斷,不會(huì)根據(jù)設(shè)置的條件進(jìn)行判定
        degradeRule.setTimeWindow(10);


        degradeRules.add(degradeRule);
        DegradeRuleManager.loadRules(degradeRules);

        /*
        慢調(diào)用比率--DEGRADE_GRADE_RT
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        degradeRule.setCount(100);
        degradeRule.setTimeWindow(10);
        //請(qǐng)求總數(shù)小于minRequestAmount時(shí)不做熔斷處理
        degradeRule.setMinRequestAmount(2);
        // 在這個(gè)時(shí)間段內(nèi)2次請(qǐng)求
        degradeRule.setStatIntervalMs(60*1000*60);   //  時(shí)間太短不好測(cè)
        // 慢請(qǐng)求率:慢請(qǐng)求數(shù)/總請(qǐng)求數(shù)> SlowRatioThreshold ,
        // 這里要設(shè)置小于1   因?yàn)槁?qǐng)求數(shù)/總請(qǐng)求數(shù) 永遠(yuǎn)不會(huì)大于1
        degradeRule.setSlowRatioThreshold(0.9);*/

    }

4. 給對(duì)應(yīng)接口添加 @SentinelResource 注解

private static final String USER_RESOURCE_NAME = "user";

   /**
     * @SentinelResource 改善接口中資源定義和被流控降級(jí)后的處理方法
     * 怎么使用: 1.添加依賴<artifactId>sentinel-annotation-aspectj</artifactId>
     *          2.配置bean——SentinelResourceAspect
     *   value  定義資源
     *   blockHandler 設(shè)置 流控降級(jí)后的處理方法(默認(rèn)該方法必須聲明在同一個(gè)類)
     *      如果不想在同一個(gè)類中 添加blockHandlerClass指定對(duì)應(yīng)的類 但是方法必須是static
     *   fallback 當(dāng)接口出現(xiàn)了異常,就可以交給fallback指定的方法進(jìn)行處理
     *      如果不想在同一個(gè)類中 添加fallbackClass指定對(duì)應(yīng)的類 但是方法必須是static
     *     blockHandler 如果和fallback同時(shí)指定了,則blockHandler優(yōu)先級(jí)更高
     *   
     *   exceptionsToIgnore 排除哪些異常不處理
     * @param id
     * @return
     */
    @RequestMapping("/user")
    @SentinelResource(value = USER_RESOURCE_NAME,  fallback = "fallbackHandleForGetUser",
            /*exceptionsToIgnore = {ArithmeticException.class},*/
            /*blockHandlerClass = User.class,*/ blockHandler = "blockHandlerForGetUser")
    public User getUser(String id) {
        int a=1/0;
        return new User("成功");
    }

    public User fallbackHandleForGetUser(String id,Throwable e) {
        e.printStackTrace();
        return new User("異常處理");
    }

    /**
     * 注意:
     *  1. 一定要public
     *  2. 返回值一定要和源方法保證一致, 包含源方法的參數(shù)。
     *  3. 可以在參數(shù)最后添加BlockException 可以區(qū)分是什么規(guī)則的處理方法
     * @param id
     * @param ex
     * @return
     */
    public User blockHandlerForGetUser(String id, BlockException ex) {
        ex.printStackTrace();
        return new User("流控!!");
    }

第四關(guān):Sentinel - 整合SpringCloud Alibaba

  • 補(bǔ)充pom文件

    <!--sentinel啟動(dòng)器-->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  • 補(bǔ)充配置文件

    這樣我們請(qǐng)求了該服務(wù)的接口后,sentinel控制臺(tái)就會(huì)有記錄了

    server:
      port: 8861
    spring:
      application:
        name: order-sentinel
      cloud:
        sentinel:
          transport:
            dashboard: 192.168.2.101:8858
          web-context-unify: false  # 默認(rèn)將調(diào)用鏈路收斂, 導(dǎo)致鏈路流控效果無(wú)效
    

請(qǐng)求接口被流控就會(huì)被sentinel默認(rèn)的方法展示。想要自定義流控方法的返回,跟Sentinel整合原生Spring 一樣, 通過(guò)加注解@SentinelResource(value = "xx", blockHandler = "流控方法名"),自定義流控方法來(lái)實(shí)現(xiàn)。

除此之外,當(dāng)我們多個(gè)方法的流控、降級(jí)、熔斷方法返回值都一樣,就可以編寫(xiě)自定義攔截器進(jìn)行統(tǒng)一處理

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tulingxueyuan.order.domain.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {

    Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception {
        // getRule() 資源  規(guī)則的詳細(xì)信息
        log.info("BlockExceptionHandler BlockException================"+e.getRule());

        Result r = null;

        if (e instanceof FlowException) {
            r = Result.error(100,"接口限流了");

        } else if (e instanceof DegradeException) {
            r = Result.error(101,"服務(wù)降級(jí)了");

        } else if (e instanceof ParamFlowException) {
            r = Result.error(102,"熱點(diǎn)參數(shù)限流了");

        } else if (e instanceof SystemBlockException) {
            r = Result.error(103,"觸發(fā)系統(tǒng)保護(hù)規(guī)則了");

        } else if (e instanceof AuthorityException) {
            r = Result.error(104,"授權(quán)規(guī)則不通過(guò)");
        }

        //返回json數(shù)據(jù)
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        new ObjectMapper().writeValue(response.getWriter(), r);
    }
}

第五關(guān):Sentinel-Dashboard 安裝

Sentinel 控制臺(tái): https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0

docker安裝控制臺(tái)

搜索、下載容器

[root@192 ~]# docker search sentinel               
[root@192 ~]# docker pull bladex/sentinel-dashboard

啟動(dòng)容器

docker run --name sentinel-dashboard -d -p 8858:8858 bladex/sentinel-dashboard
客戶端接入控制臺(tái)

引入pom文件

    客戶端需要引入 Transport 模塊來(lái)與 Sentinel 控制臺(tái)進(jìn)行通信。您可以通過(guò) `pom.xml` 引入 JAR 包
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>x.y.z</version>
</dependency>

配置啟動(dòng)參數(shù) ( 原生spring )

    啟動(dòng)時(shí)加入 JVM 參數(shù) `-Dcsp.sentinel.dashboard.server=192.168.2.101:8858` 指定控制臺(tái)地址和端口。若啟動(dòng)多個(gè)應(yīng)用,則需要通過(guò) `-Dcsp.sentinel.api.port=xxxx` 指定客戶端監(jiān)控 API 的端口(默認(rèn)是 8719)。

    從 1.6.3 版本開(kāi)始,控制臺(tái)支持網(wǎng)關(guān)流控規(guī)則管理。您需要在接入端添加 `-Dcsp.sentinel.app.type=1` 啟動(dòng)參數(shù)以將您的服務(wù)標(biāo)記為 API Gateway,在接入控制臺(tái)時(shí)您的服務(wù)會(huì)自動(dòng)注冊(cè)為網(wǎng)關(guān)類型,然后您即可在控制臺(tái)配置網(wǎng)關(guān)規(guī)則和 API 分組。

除了修改 JVM 參數(shù),也可以通過(guò)配置文件取得同樣的效果。更詳細(xì)的信息可以參考 啟動(dòng)配置項(xiàng)。

第六關(guān):流控規(guī)則 < 流控通常在服務(wù)端 >

流控模式

直接流控 關(guān)聯(lián)流控 鏈路流控

1、直接流控

給誰(shuí)設(shè)置流控,達(dá)到要求,誰(shuí)就被限流。

2、關(guān)聯(lián)流控

給接口A設(shè)置流控,關(guān)聯(lián)資源是接口B。 這時(shí)候,當(dāng)請(qǐng)求B達(dá)到一定要求,A就會(huì)被限流。

3、鏈路流控

接口A和接口B都調(diào)用了接口C。我們對(duì)C設(shè)置鏈路流控,入口資源是接口A。這時(shí)候,當(dāng)接口A調(diào)用達(dá)到一定要求,接口A請(qǐng)求C就被流控了。但是接口B請(qǐng)求C不管怎么請(qǐng)求,都是可以調(diào)通的。

// 接口C
@SentinelResource(value="getUser",blockHandler = "blockHandlerGetUser")
public String getUser() {
  return "查詢用戶";
}

// 關(guān)聯(lián)流控   訪問(wèn) 觸發(fā)/getUser
@RequestMapping("/test1")
public String test1(){
  return orderService.getUser();
}
// 關(guān)聯(lián)流控  訪問(wèn)/add 觸發(fā)/get
@RequestMapping("/test2")
public String test2() throws InterruptedException {
  return orderService.getUser();
}
鏈路流控

測(cè)試會(huì)發(fā)現(xiàn)鏈路規(guī)則不生效

注意,高版本此功能直接使用不生效,如何解決?

    從1.6.3 版本開(kāi)始,Sentinel Web filter默認(rèn)收斂所有URL的入口context,因此鏈路限流不生效。

    1.7.0 版本開(kāi)始(對(duì)應(yīng)SCA的2.1.1.RELEASE),官方在CommonFilter 引入了WEB_CONTEXT_UNIFY 參數(shù),用于控制是否收斂context。將其配置為 false 即可根據(jù)不同的URL 進(jìn)行鏈路限流。SCA 2.1.1.RELEASE之后的版本,可以通過(guò)配置spring.cloud.sentinel.web-context-unify=false即可關(guān)閉收斂 
server:
  port: 8861
spring:
  application:
    name: order-sentinel
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.2.101:8858
      web-context-unify: false  # 默認(rèn)將調(diào)用鏈路收斂, 導(dǎo)致鏈路流控效果無(wú)效
流控效果

快速失敗 Warm Up 排隊(duì)等待

1、快速失敗

超出要求,直接失敗,走流控方法 ( block )

官方解釋: ( RuleConstant.CONTROL_BEHAVIOR_DEFAULT )方式是默認(rèn)的流量控制方式,當(dāng)QPS超過(guò)任意規(guī)則的閾值后,新的請(qǐng)求就會(huì)被立即拒絕,拒絕方式為拋出FlowException。這種方式適用于對(duì)系統(tǒng)處理能力確切已知的情況下,比如通過(guò)壓測(cè)確定了系統(tǒng)的準(zhǔn)確水位時(shí)。

2、Warm Up

適用于 洪峰流量 ,預(yù)熱模式,一點(diǎn)一點(diǎn)給釋放

官方解釋: Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即預(yù)熱/冷啟動(dòng)方式。當(dāng)系統(tǒng)長(zhǎng)期處于低水位的情況下,當(dāng)流量突然增加時(shí),直接把系統(tǒng)拉升到高水位可能瞬間把系統(tǒng)壓垮。通過(guò)"冷啟動(dòng)",讓通過(guò)的流量緩慢增加,在一定時(shí)間內(nèi)逐漸增加到閾值上限,給冷系統(tǒng)一個(gè)預(yù)熱的時(shí)間,避免冷系統(tǒng)被壓垮。

冷加載因子: codeFactor 默認(rèn)是3,即請(qǐng)求 QPS 從 threshold / 3 開(kāi)始,經(jīng)預(yù)熱時(shí)長(zhǎng)逐漸升至設(shè)定的 QPS 閾值。

3、排隊(duì)等待

適用于 脈沖流量 ,雪峰填谷的意思

官方解釋: 勻速排隊(duì)(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會(huì)嚴(yán)格控制請(qǐng)求通過(guò)的間隔時(shí)間,也即是讓請(qǐng)求以均勻的速度通過(guò),對(duì)應(yīng)的是漏桶算法。這種方式主要用于處理間隔性突發(fā)的流量,例如消息隊(duì)列。想象一下這樣的場(chǎng)景,在某一秒有大量的請(qǐng)求到來(lái),而接下來(lái)的幾秒則處于空閑狀態(tài),我們希望系統(tǒng)能夠在接下來(lái)的空閑期間逐漸處理這些請(qǐng)求,而不是在第一秒直接拒絕多余的請(qǐng)求。

注意: 勻速排隊(duì)模式暫時(shí)不支QPS > 1000 的請(qǐng)求

第七關(guān):熔斷降級(jí)與隔離 < 通常在消費(fèi)端 >

降級(jí)規(guī)則
    除了流量控制以外,對(duì)調(diào)用鏈路中不穩(wěn)定的資源進(jìn)行熔斷降級(jí)也是保障高可用的重要措施之一。我們需要對(duì)不穩(wěn)定的 **弱依賴服務(wù)調(diào)用** 進(jìn)行熔斷降級(jí),暫時(shí)切斷不穩(wěn)定調(diào)用,避免局部不穩(wěn)定因素導(dǎo)致整體的雪崩。熔斷降級(jí)作為保護(hù)自身的手段,通常在客戶端(調(diào)用端)進(jìn)行配置。
熔斷策略

慢調(diào)用比例

設(shè)置最大響應(yīng)時(shí)間,超過(guò)了就是慢調(diào)用。 超過(guò)慢調(diào)用比例就會(huì)被熔斷降級(jí)。熔斷之后第一次調(diào)用如果還是慢調(diào)用,則直接再次熔斷,不必判斷慢調(diào)用比例。

官方解釋: 慢調(diào)用比例 (SLOW_REQUEST_RATIO):選擇以慢調(diào)用比例作為閾值,需要設(shè)置允許的慢調(diào)用 RT(即最大的響應(yīng)時(shí)間),請(qǐng)求的響應(yīng)時(shí)間大于該值則統(tǒng)計(jì)為慢調(diào)用。當(dāng)單位統(tǒng)計(jì)時(shí)長(zhǎng)(statIntervalMs)內(nèi)請(qǐng)求數(shù)目大于設(shè)置的最小請(qǐng)求數(shù)目,并且慢調(diào)用的比例大于閾值,則接下來(lái)的熔斷時(shí)長(zhǎng)內(nèi)請(qǐng)求會(huì)自動(dòng)被熔斷。經(jīng)過(guò)熔斷時(shí)長(zhǎng)后熔斷器會(huì)進(jìn)入探測(cè)恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài)),若接下來(lái)的一個(gè)請(qǐng)求響應(yīng)時(shí)間小于設(shè)置的慢調(diào)用 RT 則結(jié)束熔斷,若大于設(shè)置的慢調(diào)用 RT 則會(huì)再次被熔斷。

慢調(diào)用比例熔斷

異常比例

在設(shè)定的**最小請(qǐng)求**的基礎(chǔ)上,出現(xiàn)異常的概率**大于異常比例**,之后的請(qǐng)求則會(huì)熔斷降級(jí)。熔斷之后第一次調(diào)用如果還是異常調(diào)用,則直接再次熔斷,不必判斷異常比例。

官方解釋: 異常比例 (ERROR_RATIO):當(dāng)單位統(tǒng)計(jì)時(shí)長(zhǎng)(statIntervalMs)內(nèi)請(qǐng)求數(shù)目大于設(shè)置的最小請(qǐng)求數(shù)目,并且異常的比例大于閾值,則接下來(lái)的熔斷時(shí)長(zhǎng)內(nèi)請(qǐng)求會(huì)自動(dòng)被熔斷。經(jīng)過(guò)熔斷時(shí)長(zhǎng)后熔斷器會(huì)進(jìn)入探測(cè)恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài)),若接下來(lái)的一個(gè)請(qǐng)求成功完成(沒(méi)有錯(cuò)誤)則結(jié)束熔斷,否則會(huì)再次被熔斷。異常比率的閾值范圍是 [0.0, 1.0],代表 0% - 100%。

![異常比例熔斷](https://upload-images.jianshu.io/upload_images/20818477-053fcc19e245f8d1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

異常數(shù)

在設(shè)定的最小請(qǐng)求的基礎(chǔ)上,出現(xiàn)異常次數(shù)大于異常數(shù),之后的請(qǐng)求則會(huì)熔斷降級(jí)。熔斷之后第一次調(diào)用如果還是異常調(diào)用,則直接再次熔斷,不必判斷異常數(shù)。

官方解釋: 異常數(shù) (ERROR_COUNT):當(dāng)單位統(tǒng)計(jì)時(shí)長(zhǎng)內(nèi)的異常數(shù)目超過(guò)閾值之后會(huì)自動(dòng)進(jìn)行熔斷。經(jīng)過(guò)熔斷時(shí)長(zhǎng)后熔斷會(huì)進(jìn)入探測(cè)恢復(fù)狀態(tài)(HALF-OPEN 狀態(tài)),若接下來(lái)的一個(gè)請(qǐng)求成功完成(沒(méi)有錯(cuò)誤)則結(jié)束熔斷,否則會(huì)再次被熔斷。注意:異常降級(jí)僅針對(duì)業(yè)務(wù)異常,對(duì) Sentinel 限流降級(jí)本身的異常(BlockException)不生效。

![異常數(shù)熔斷](https://upload-images.jianshu.io/upload_images/20818477-5644c71d6eea12cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

第八關(guān):openFeign跟Sentinel的整合

1. pom文件
              <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--nacos-服務(wù)注冊(cè)發(fā)現(xiàn)-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--1. 添加openfeign依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>


        <!--sentinel依賴-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
2.yaml配置文件

開(kāi)啟openFeign對(duì)sentinel的整合. Feign.sentinel.enabled = true

server:
  port: 8041
  # 應(yīng)用名稱 (nacos會(huì)將該名稱當(dāng)做服務(wù)名稱)
spring:
  application:
    name: order-service
  cloud:
    nacos:
      server-addr: 192.168.2.101:8847
      discovery:
        username: nacos
        password: nacos
        namespace: public
feign:
  sentinel:
    # openfeign整合sentinel
    enabled: true
3.feign接口補(bǔ)充實(shí)現(xiàn)類,進(jìn)行降級(jí)方法的補(bǔ)充
// feign 接口  指定降級(jí)類
@FeignClient(value="stock-nacos",path = "/stock",fallback = StockFeignServiceFallback.class)
public interface StockFeignService {

    @RequestMapping("/reduct")
    public String reduct2();
}


// feign的fallback實(shí)現(xiàn)類,實(shí)現(xiàn)降級(jí)方法
@Component
public class StockFeignServiceFallback implements StockFeignService {
    @Override
    public String reduct2() {
        return "降級(jí)啦?。?!";
    }
}

第九關(guān):熱點(diǎn)參數(shù)流控

何為熱點(diǎn)?

    熱點(diǎn)即經(jīng)常訪問(wèn)的數(shù)據(jù)。很多時(shí)候我們希望統(tǒng)計(jì)某個(gè)熱點(diǎn)數(shù)據(jù)中訪問(wèn)頻次最高的數(shù)據(jù),并對(duì)其訪問(wèn)進(jìn)行限制。熱點(diǎn)參數(shù)限流會(huì)統(tǒng)計(jì)傳入?yún)?shù)中的熱點(diǎn)參數(shù),并根據(jù)配置的限流閾值與模式,對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用進(jìn)行限流。熱點(diǎn)參數(shù)限流可以看做是一種特殊的流量控制,僅對(duì)包含熱點(diǎn)參數(shù)的資源調(diào)用生效。

注意:

  1. 熱點(diǎn)規(guī)則需要使用@SentinelResource("resourceName")注解,否則不生效

  2. 參數(shù)必須是7種基本數(shù)據(jù)類型才會(huì)生效

單機(jī)閾值: 針對(duì)所有參數(shù)的值進(jìn)行設(shè)置的一個(gè)公共的閾值

  1. 假設(shè)當(dāng)前 參數(shù) 大部分的值都是熱點(diǎn)流量, 單機(jī)閾值就是針對(duì)熱點(diǎn)流量進(jìn)行設(shè)置, 額外針對(duì)普通流量進(jìn)行參數(shù)值流控

  2. 假設(shè)當(dāng)前 參數(shù) 大部分的值都是普通流量, 單機(jī)閾值就是針對(duì)普通流量進(jìn)行設(shè)置, 額外針對(duì)熱點(diǎn)流量進(jìn)行參數(shù)值流控

第十關(guān):Sentinel規(guī)則持久化

問(wèn)題

上述方法,在服務(wù)重啟之后,流控規(guī)則就被清空了,沒(méi)有數(shù)據(jù)持久化。

原始模式

如果不做任何修改,Dashboard 的推送規(guī)則方式是通過(guò) API 將規(guī)則推送至客戶端并直接更新到內(nèi)存中。這種做法的好處是簡(jiǎn)單,無(wú)依賴;壞處是應(yīng)用重啟規(guī)則就會(huì)消失,僅用于簡(jiǎn)單測(cè)試,不能用于生產(chǎn)環(huán)境。

拉模式( Pull )

pull 模式的數(shù)據(jù)源(如本地文件、RDBMS 等)一般是可寫(xiě)入的。使用時(shí)需要在客戶端注冊(cè)數(shù)據(jù)源:將對(duì)應(yīng)的讀數(shù)據(jù)源注冊(cè)至對(duì)應(yīng)的 RuleManager,將寫(xiě)數(shù)據(jù)源注冊(cè)至 transport 的WritableDataSourceRegistry 中。

推模式 ( Push )

生產(chǎn)環(huán)境下一般更常用的是 push 模式的數(shù)據(jù)源。對(duì)于 push 模式的數(shù)據(jù)源,如遠(yuǎn)程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不應(yīng)由 Sentinel 客戶端進(jìn)行,而應(yīng)該經(jīng)控制臺(tái)統(tǒng)一進(jìn)行管理,直接進(jìn)行推送,數(shù)據(jù)源僅負(fù)責(zé)獲取配置中心推送的配置并更新到本地。因此推送規(guī)則正確做法應(yīng)該是 配置中心控制臺(tái) /Sentinel 控制臺(tái) 配置中心 Sentinel 數(shù)據(jù)源 → Sentinel,而不是經(jīng) Sentinel 數(shù)據(jù)源推送至配置中心。

持久化方法一:嵌入到代碼里

像 第三關(guān) Sentinel 集成 原生Spring 一樣,把流控、熔斷降級(jí)的規(guī)則寫(xiě)在代碼里。

持久化方法二:Nacos配置中心實(shí)現(xiàn)推送

1、nacos配置中心中配置流控規(guī)則

[ 
  { 
  "resource": "TestResource",
  "controlBehavior": 0,
  "count": 10.0,
  "grade": 1,
  "limitApp": "default",
  "strategy": 0 
  }
]

2、補(bǔ)充yml配置

server:
  port: 8861
spring:
  application:
    name: order-sentinel
  cloud:
    sentinel:
      transport:
        dashboard: 192.168.2.101:8858
      web-context-unify: false  # 默認(rèn)將調(diào)用鏈路收斂, 導(dǎo)致鏈路流控效果無(wú)效
      datasource:
        flow-rule:
          nacos:
            server-addr: 192.168.2.101:8847
            username: nacos
            password: nacos
            dataId: order-sentinel-flow-rule
            groupId: SENTINEL_GROUP # 默認(rèn)的不用配置
            data‐type: yaml
            rule-type: flow

問(wèn)題:

nacos 配置這一套。如果從 sentinel-dashboard 設(shè)置流控、降級(jí)等操作,是不會(huì)同步到nacos配置文件里的,還需要手動(dòng)更改nacos里的配置。

至于可以怎么解決? 如果在控制臺(tái)設(shè)置了流控,nacos自動(dòng)同步,還需要研究源碼,查看方法。 但是確定是可以實(shí)現(xiàn)的。

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

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

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