第五节 Sentinel 基本使用

亮子 2022-12-26 03:04:24 17110 0 0 0

1、定义资源

资源是Sentinel的关键概念。它可以是Java应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

只要通过Sentinel API定义的代码,就是资源,能够被Sentinel保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。

Sentinel可以简单的分为Sentinel核心库和Dashboard。核心库不依赖Dashboard,但是结合Dashboard可以取得最好的效果。

我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。使用
Sentinel来进行资源保护,主要分为几个步骤:

1.定义资源
2.定义规则
3.检验规则是否生效

先把可能需要保护的资源定义好(埋点),之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。

对于主流的框架,我们提供适配,只需要按照适配中的说明配置,Sentinel就会默认定义提供的服务,方法等为资源。

1.1 方式一:

主流框架的默认适配为了减少开发的复杂程度,我们对大部分的主流框架,例如Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor等都做了适配。您只需要引入对应的依赖即可方便地整合Sentinel。

可以参见:主流框架的适配。

1.2 方式二:

抛出异常的方式定义资源SphU包含了try-catch风格的API。用这种方式,当资源发生了限流之后会抛出BlockException。这个时候可以捕捉异常,进行限流之后的逻辑处理。

示例代码如下:

        //1.5.0版本开始可以利用try-with-resources特性(使用有限制)
        //资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
        try(Entry entry = SphU.entry("resourceName"))
        {
            //被保护的业务逻辑
            //do something here...
        }
        catch (BlockException ex)
        {
            //资源访问阻止,被限流或被降级
            //在此处进行相应的处理操作
        }

特别地,若entry的时候传入了热点参数,那么exit的时候也一定要带上对应的参数(exit(count,args)),否则可能会有统计错误。这个时候不能使用try-with-resources的方式。
另外通过Tracer.trace(ex)来统计异常信息时,由于try-with-resources语法中catch调用顺序的问题,会导致无法正确统计异常数,因此统计异常信息时也不能在try-with-resources的catch块中调用Tracer.trace(ex)。

手动exit示例:

Entry entry = null;
        //务必保证finally会被执行
        try{
            //资源名可使用任意有业务语义的字符串,注意数目不能太多(超过1K),超出几千请作为参数传入而不要直接作为资源名
            //EntryType代表流量类型(inbound/outbound),其中系统规则只对IN类型的埋点生效
            entry = SphU.entry("自定义资源名");
            //被保护的业务逻辑
            //do something...
        }
        catch (BlockException ex) {
            // 资源访问阻止,被限流或被降级
            // 进行相应的处理操作
        }
        catch (Exception ex) {
            // 若需要配置降级规则,需要通过这种方式记录业务异常
            Tracer.traceEntry(ex, entry);
        }
        finally {
            // 务必保证 exit,务必保证每个entry与exit配对
            if(entry!=null){
                entry.exit();
            }
        }

热点参数埋点示例:

        Entry entry = null;
        try {
            // 若需要配置例外项,则传入的参数只支持基本类型。
            // EntryType代表流量类型,其中系统规则只对IN类型的埋点生效
            // count大多数情况都填1,代表统计为一次调用。
            entry =SphU.entry(resourceName,EntryType.IN,1,paramA,paramB);
            // Your logic here.
        }
        catch(BlockException ex) {
            //Handle request rejection.
        }
        finally {
            // 注意:exit的时候也一定要带上对应的参数,否则可能会有统计错误。
            if(entry!=null){
                entry.exit(1,paramA,paramB);
            }
        }

SphU.entry()的参数描述:

参数名 类型 解释 默认值
entryType EntryType 资源调用的流量类型,是入口流量(EntryType.IN)还是出口流量(EntryType.OUT),注意系统规则只对IN生效 EntryType.OUT
count int 本次资源调用请求的token数目 1
args Object[] 传入的参数,用于热点参数限流

注意:
SphU.entry(xxx)需要与entry.exit()方法成对出现,匹配调用,否则会导致调用链记录异常,抛出ErrorEntryFreeException异常。常见的错误:

  • 自定义埋点只调用SphU.entry(),没有调用entry.exit()
  • 顺序错误,比如:entry1->entry2->exit1->exit2,应该为entry1->entry2->exit2->exit1

1.3 方式三:返回布尔值方式定义资源

SphO提供if-else风格的API。用这种方式,当资源发生了限流之后会返回false,这个时候可以根据返回值,进行限流之后的逻辑处理。
示例代码如下:

        // 资源名可使用任意有业务语义的字符串
        if(SphO.entry("自定义资源名")){
            //务必保证finally会被执行
            try{
                 // 被保护的业务逻辑
            }
            finally{
                SphO.exit();
            }
        }
        else{
            //资源访问阻止,被限流或被降级
            //进行相应的处理操作
        }

注意:
SphO.entry(xxx)需要与SphO.exit()方法成对出现,匹配调用,位置正确,否则会导致调用链记录异常,抛出ErrorEntryFreeException异常。

实例代码:

    @GetMapping(value = "/helloWorld2")
    public String helloWorld2() {

        // 资源名可使用任意有业务语义的字符串
        if(SphO.entry("helloWorld2")){
            //务必保证finally会被执行
            try{
                // 被保护的业务逻辑
                long millis = System.currentTimeMillis();
                log.info("helloWorld2="+millis);
                return "helloWorld2="+millis;
            }
            finally{
                SphO.exit();
            }
        }
        else{
            //资源访问阻止,被限流或被降级
            //进行相应的处理操作
            log.error("系统繁忙,请稍后再试!");
            return "系统繁忙,请稍后再试!";
        }
    }

sentinel控制台添加流控规则:

图片alt

访问http://localhost/helloWorld2

正常访问显示:

图片alt

如果频繁访问会出现:

图片alt

触碰降级规则,返回降级信息;