sentinel入門使用

1.簡介

微服務體系架構下,服務容錯是一個大事,常見的容錯方案有

  • 超時

  • 流控(限流)

  • 熔斷降級

在業界也有很多可選擇的容錯產品,比如說服務之間調用ribbon+resttemplate支持超時設置,feign支持超時,甚至我們在設計實現api的時候,也會考慮相關的api超時機制。

比如說支持流控、熔斷降級的產品hystrix、resilience4j,以及阿里開源的sentinel。

當然今天我們的主角是sentinel,因爲它的優秀,我準備寫一個短系列文章分享介紹使用它!整理了一下,內容大致包括

  • 入門使用

  • 控制檯dashboard

  • spring cloud alibba 整合sentinel使用

  • 擴展sentinel之錯誤頁面

  • 擴展sentinel之區分來源

  • 擴展sentinel之支持restful url

  • 擴展sentinel之規則持久化

本篇文章是第一篇,我們從入門開始!

2.sentinel介紹

關於sentinel介紹,我想推薦你去看官網,非常詳細!這也是我想推薦給小夥伴們學習新東西的一個方式

  • 一定要看官網,一定要掌握學習的方法,總結形成自己的知識體系!

  • 反之,如果我們只是滿足於藉助搜索引擎翻幾篇文章,比如說吧就看我的博客,那是遠遠不夠的!

  • 藉助搜索引擎,看看博客,只能是快速入門!所以還是那句話:一定要看官網

那麼官網的地址在哪呢?github,我貼一下它的地址:

https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5

順便截個圖:

總結一下,官方的介紹

  • sentinel是一個服務穩定性的防護組件,流控、熔斷降級規則豐富,應用場景豐富

  • 還提供的dashboard控制面板,相關規則管理,比如說規則動態配置刷新;支持監控

  • 更關鍵的是sentinel不依賴任何第三方庫,或者開源組件,這就很感人了!不管是普通sevlet web應用,老一代spring web應用,還是springboot應用,還是整合到spring cloud應用,統統都滿足!

3.入門案例

3.1.搭建環境

我這裏以springboot應用爲例,畢竟springboot今天是主流應用基礎框架。首先我們需要引入sentinel依賴

<!--公共變量定義-->
<properties>
  <java.version>1.8</java.version>
  <spring-boot.version>2.3.2.RELEASE</spring-boot.version>
</properties>

<!--sentinel依賴-->
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-core</artifactId>
  <version>1.8.2</version>
</dependency>

這裏關於版本的選擇,我貼一個官方的地址:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

因爲我這裏選擇的springboot版本是:2.3.2.RELEASE,所以sentinel版本參照官網選擇的版本是:1.8.2

3.2.加載規則

對於sentinel防護組件,使用的關鍵是兩個點

  • 聲明資源

  • 定義相關規則,保護資源

3.2.1.聲明資源

 

/**
 * <p>
 * sentinel 資源
 * </p>
 *
 * @author [email protected]
 * @since 2021/8/5
 */
public interface MySentinelResource {
    /**
     * 流控資源
     */
    public static final String FLOW_RESOURCE = "flowResource";
}

3.2.2.加載資源

/**
 * <p>
 * 加載sentinel規則
 * 1.流控規則
 * 2.降級規則
 * 3.系統規則
 * 4.熱點規則
 * 5.授權規則
 * </p>
 *
 * @author [email protected]
 * @since 2021/8/5
 */
@Component
@Slf4j
public class LoadSentinelRules {

    public LoadSentinelRules(){
        // 初始化加載流控規則
        initFlowRules();
        log.info("加載了流控規則.");

    }


    /**
     * 初始化流控規則
     */
    public void initFlowRules(){
        // 流控規則集合
        List<FlowRule> flowRules = Lists.newArrayList();

        FlowRule rule = new FlowRule();
        rule.setResource(MySentinelResource.FLOW_RESOURCE);// 資源
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 流控閾值類型:qps
        rule.setCount(1);// 流控閾值:1

        flowRules.add(rule);

        FlowRuleManager.loadRules(flowRules);
    }

}

3.3.流控規則

編寫一個conttroller,將相關的端點作爲資源,通過sentinel進行保護

/**
 * <p>
 * sentinel demo controller
 * </p>
 *
 * @author [email protected]
 * @since 2021/8/5
 */
@RestController
@RequestMapping("sentinel")
@Slf4j
public class SentinelController {

    @RequestMapping("flow")
    public String flow(String userId){
        Entry entry = null;
        String result = "ok!";
        try{
            // 1.開始進入資源,流控保護開始
            SphU.entry(MySentinelResource.FLOW_RESOURCE);

            // 2.被保護的資源
            log.info("SentinelController--flow,param:{}", userId);

        }catch (BlockException e){
            log.error("發生流控異常! msg:{}", e);
            result = "error!限流了!";
        }finally {
            // 3.釋放資源,需要與SphU.entry配對
            if(entry != null){
                entry.exit();
            }
        }

       return result;
    }
}

關鍵代碼說明

  • 第一步,通過SphU.entry方法聲明進入資源

  • 第二步,編寫需要被保護資源

  • 第三步,通過 entry.exit釋放資源

3.4.流控效果

把應用啓動起來,我們上面配置一個流控規則,表示每秒中允許通過的qps是1,超過1即需要流控(限流)

 

請求api:http://127.0.0.1:8080/sentinel/flow?userId=1,1秒內多次刷新

3.5.熔斷降級規則

通過上面的案例,我們看到了sentinel流控的效果。不過實現的代碼,看起來比較糟糕!你還記得這段代碼嗎?

 @RequestMapping("flow")
    public String flow(String userId){
        Entry entry = null;
        String result = "ok!";
        try{
            // 1.開始進入資源,流控保護開始
            SphU.entry(MySentinelResource.FLOW_RESOURCE);

            // 2.被保護的資源
            log.info("SentinelController--flow,param:{}", userId);

        }catch (BlockException e){
            log.error("發生流控異常! msg:{}", e);
            result = "error!限流了!";
        }finally {
            // 3.釋放資源,需要與SphU.entry配對
            if(entry != null){
                entry.exit();
            }
        }

       return result;
    }

需要通過

  • try{...}catch(BlockException e){...}finally{...}代碼塊

  • SphU.entry聲明資源開始

  • 通過entry.exit聲明保護資源結束

實際項目中,如果每個需要作爲資源被保護起來的業務方法,都這麼去寫,相信小夥伴們一定很抓狂!

那麼有沒有什麼更好的實現方法呢?答案是有,sentinel給我們提供了一個@SentinelResource註解,只需要在業務方法上加上該註解,那麼sentinel就會自動把該業務方法作爲資源保護起來。

正好,通過熔斷降級規則案例,來結合@SentinelResource註解一起使用。

3.5.1.引入依賴

要使用@SentinelResource方式保護資源,需要我們引入一個新的依賴,本質上註解方式底層實現是AOP

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
    <version>1.8.2</version>
</dependency>

3.5.2.sentinel aop配置

/**
 * <p>
 * sentinel aop 配置
 * </p>
 *
 * @author [email protected]
 * @since 2021/8/3
 */
@Configuration
public class SentinelAspectConfiguration {
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
}

3.5.3.加載降級規則

 /**
     * 初始化降級規則
     */
    public void initDegradeRules(){
        List<DegradeRule> degradeRules = Lists.newArrayList();

        DegradeRule rule = new DegradeRule();
        rule.setResource(MySentinelResource.DEGRADE_RESOURCE);// 資源
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);// 閾值類型:慢調用比例
        rule.setMinRequestAmount(5);// 最小請求數
        rule.setTimeWindow(1);// 熔斷時長,單位秒
        rule.setSlowRatioThreshold(1);// 比例閾值
        rule.setCount(1);// 最大RT 單位 毫秒
        rule.setStatIntervalMs(1000);// 統計時長,單位毫秒

        degradeRules.add(rule);

        DegradeRuleManager.loadRules(degradeRules);

    }

3.5.4.編寫資源

/**
     * 測試熔斷降級規則
     * @return
     */
    @RequestMapping("degrade")
    @SentinelResource(value =MySentinelResource.DEGRADE_RESOURCE, fallback = "degradeFallback")
    public String degrade(){
        log.info("SentinelController--annotationDegrade start");
        int time = new Random().nextInt(1000);
        try {
            TimeUnit.MILLISECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("SentinelController--annotationDegrade end,耗時:{}毫秒",time);
        return "degrade ok!";
    }

   // 降級方法
    public String degradeFallback(Throwable e){
        log.error("熔斷降級了,異常消息:{}", e);
        return "error!熔斷降級了!";
    }

3.5.5.降級效果

請求:http://127.0.0.1:8080/sentinel/degrade?userId=1,且不斷刷新

3.5.6.@SentinelResource註解說明

到此,分別通過SphU.entry,與註解@SentinelResource,實現了sentinel流控、與熔斷降級的效果。我們發現@SentinelResource的方式真是好啊!代碼優雅了很多!

那麼對於該註解,做一個簡單的說明,它的關鍵屬性有

  • value:指定資源名稱

  • blockHandler:如果是流控,用於指定發生流控後的處理方法

  • fallback:如果是降級,用於指定發生降級後的處理方法

這三個是比較常用的屬性,更多屬性,推薦你去看官方文檔,連接地址:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81

本文源碼地址:https://gitee.com/yanghouhua/springboot.git

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章