sentinel基本规则的api操作

sentinel基本规则的api操作

sentinel的功能作用: 限流

sentinel和hystrix的区别是怎么样的:

image-20210131160032389

sentinel有哪些规则呢:

流量控制,熔断降级,热点参数限流,系统自适应限流,黑白名单控制,网关流控,集群流控

流量控制

流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

pom.xml

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>${sentinel.version}</version>
        </dependency>

代码:

public class Demo {

    private static final String resourceName = "helloResource";

    public static void main(String[] args) {
        initFlowRules();
        sphoMethod();
    }

    /**
     * sphu的方式
     * 抛出异常的方式定义资源
     */
    public static void sphuMethod(){
        while (true){
            //如果违反了规则就抛出异常
            try (Entry entry = SphU.entry(resourceName)){
                System.out.println(new Date().toString() + ": hello world");
            } catch (BlockException e) {
                System.out.println("blocked!");
            }

        }
    }


    /**
     * spho的方式
     * 返回布尔值方式定义资源
     */

    public static void sphoMethod(){
        while (true){
            if(SphO.entry(resourceName)){
                try {
                    System.out.println(new Date().toString() + ": hello world");
                }finally {
                    SphO.exit();
                }
            }else{
                System.out.println("blocked!");
            }
        }
    }


    //这个规则代表只允许每秒qps为10的请求通过resourceName这个资源
    public static void initFlowRules(){
        //定义规则
        FlowRule flowRule = new FlowRule();
        flowRule.setResource(resourceName);
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        flowRule.setCount(10);
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));

    }
}

首先解析一下我们配置的规则是什么:只允许每秒qps为10的请求通过resourceName这个资源

运行一下main方法:

image-20210131175310163

​ 这样我们就可以知道:限流的直接表现是在执行 Entry nodeA = SphU.entry(resourceName) 的时候抛出 FlowException 异常。FlowExceptionBlockException 的子类,我们可以捕捉 BlockException 来自定义被限流之后的处理逻辑。

我们先看上面的initFlowRules方法里面定义的规则含义,即FlowRule的Api含义:

一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:

  • resource:资源名,即限流规则的作用对象

  • count: 限流阈值

  • grade: 限流阈值类型(QPS 或并发线程数)

  • limitApp: 流控针对的调用来源,若为 default 则不区分调用来源

  • strategy: 调用关系限流策略

  • controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)

具体代码请看: com.onion.apiDemo.flowRule.Demo这个demo。github地址会放到文章结尾

熔断降级

Sentinel 提供以下几种熔断策略:

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

配置如下:

        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule(KEY)
                .setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
                // Set ratio threshold to 50%.
                .setCount(0.5d)
                .setStatIntervalMs(30000)
                .setMinRequestAmount(50)
                // Retry timeout (in second)
                .setTimeWindow(10);
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);

执行代码如下:

               try {
                        entry = SphU.entry(KEY);
                        sleep(ThreadLocalRandom.current().nextInt(5, 10));
                        pass.addAndGet(1);
                        // Error probability is 45%
                        if (ThreadLocalRandom.current().nextInt(0, 100) > 55) {
                            // biz code raise an exception.
                            throw new RuntimeException("oops");
                        }
                    } catch (BlockException e) { //熔断降级的时候会抛出BlockException
                        block.addAndGet(1);
                        sleep(ThreadLocalRandom.current().nextInt(5, 10));
                    } catch (Throwable t) {
                        bizException.incrementAndGet();
                        Tracer.traceEntry(t, entry); //注意:为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常
                    } finally {
                        total.addAndGet(1);
                        if (entry != null) {
                            entry.exit();
                        }
                    }
                }

熔断降级规则(DegradeRule)包含下面几个重要的属性:

Field 说明 默认值
resource 资源名,即规则的作用对象
grade 熔断策略,支持慢调用比例/异常比例/异常数策略 慢调用比例
count 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow 熔断时长,单位为 s
minRequestAmount 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) 5
statIntervalMs 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) 1000 ms
slowRatioThreshold 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

注意:这里count的比例是: 异常比例/总数的。比如设置了count等于0.5。总请求是100,异常请求个数为:60,正常请求个数为:40,那么就会触发熔断降级了。

熔断降级运行:

​ 也是通过SphU.entry(KEY)来进行。如果SphU.entry(KEY)熔断降级的话。会抛出BlockException异常。

注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效,为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常,慢调用不需要

熔断器支持事件监听

​ 即是Sentinel 支持注册自定义的事件监听器监听熔断器状态变换事件(state change event),代码如下:

        EventObserverRegistry.getInstance().addStateChangeObserver("logging",
                (prevState, newState, rule, snapshotValue) -> {
                                // 变换至 OPEN state 时会携带触发时的值
                    if (newState == State.OPEN) {
                        System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),
                                TimeUtil.currentTimeMillis(), snapshotValue));
                    } else {
                        System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),
                                TimeUtil.currentTimeMillis()));
                    }
                });

具体代码请看: com.onion.apiDemo.degradeRule.ExceptionRatioCircuitBreakerDemo 这个demo。github地址会放到文章结尾

​ 这个demo主要功能就是:8个线程跑一段代码。该代码有百分之55的机会抛出异常并且还会统计该段代码的总的运行数量,通过的数量,异常的数量,block(熔断降级)的数量。 并且有个线程每隔一秒就打印这些指标出来。

热点参数限流

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

​ 热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

image-20210202105045945

规则配置如下:

需要额外加入这个依赖:

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-parameter-flow-control</artifactId>
            <version>${sentinel.version}</version>
        </dependency>

代码:

    public static void initParamFlowRule(){
        ParamFlowRule paramFlowRule = new ParamFlowRule();
        paramFlowRule.setResource(RESOURCE_KEY);
        //	限流阈值,全局的
        paramFlowRule.setCount(5);
        paramFlowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        //热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置
        paramFlowRule.setParamIdx(0);

        ParamFlowItem paramFlowItem = new ParamFlowItem()
                .setObject(String.valueOf(PARAM_B)) //设置热点参数的数值
                .setClassType(int.class.getName()) //设置热点参数的类型
                .setCount(10);//单独参数的阈值
        paramFlowRule.setParamFlowItemList(Collections.singletonList(paramFlowItem));
        ParamFlowRuleManager.loadRules(Collections.singletonList(paramFlowRule));
    }

热点参数规则(ParamFlowRule)类似于流量控制规则(FlowRule):

ParamFlowItem其实就是设置单独参数的阈值,ParamFlowRule是设置全局的阈值

运行部分的代码:

T param = generateParam();
try {
    entry = SphU.entry(resourceName, EntryType.IN, 1, param,param);
    // Add pass for parameter.
    passFor(param);
} catch (BlockException e) {
    // block.incrementAndGet();
    blockFor(param);
} catch (Exception ex) {
    // biz exception
    ex.printStackTrace();
} finally {
    // total.incrementAndGet();
    if (entry != null) {
        entry.exit(1, param);
    }
}

​ Entry entry(String name, EntryType type, int count, Object... args) 参数解析:

  • entryType: 资源调用的流量类型,是入口流量(EntryType.IN)还是出口流量(EntryType.OUT),注意系统规则只对 IN 生效
  • count: 表示每次调用计数为多少,通常传1。
  • args:传入的参数

注意:若 entry 的时候传入了热点参数,那么 exit 的时候也一定要带上对应的参数(exit(count, args)),否则可能会有统计错误。

具体代码请看: com.onion.apiDemo.ParamFlowRule.ParamFlowRuleDemo 这个demo。github地址会放到文章结尾

系统自适应限流

​ Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统规则支持以下的模式:

  • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
  • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

系统自适应限流得代码如下:

    List<SystemRule> rules = new ArrayList<SystemRule>();
    SystemRule rule = new SystemRule();
    // max load is 3
    rule.setHighestSystemLoad(3.0);
    // max cpu usage is 60%
    rule.setHighestCpuUsage(0.6);
    // max avg rt of all request is 10 ms
    rule.setAvgRt(10);
    // max total qps is 20
    rule.setQps(20);
    // max parallel working thread is 10
    rule.setMaxThread(10);

    rules.add(rule);
    SystemRuleManager.loadRules(Collections.singletonList(rule));

具体代码请看: com.onion.apiDemo.systemRule.SystemGuardDemo 这个demo。github地址会放到文章结尾

黑白名单控制

​ 很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

调用方信息通过 ContextUtil.enter(resourceName, origin) 方法中的 origin 参数传入。

规则配置

来源访问控制规则(AuthorityRule)非常简单,主要有以下配置项:

  • resource:资源名,即限流规则的作用对象。
  • limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB
  • strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式。

代码显示:

public class AuthorityRuleDemo {

    public static String KEY = "AuthorityRuleKey";

    public static void main(String[] args) {
        System.out.println("---------------------白名单打印---------------------");
        initWhiteRule();
        test(KEY,"appA");
        test(KEY,"appB");
        test(KEY,"appC");

        System.out.println("---------------------黑名单打印---------------------");
        initBlackRule();
        test(KEY,"appA");
        test(KEY,"appB");
        test(KEY,"appC");
    }
    

    public static void test(String resource,String appName){
        ContextUtil.enter(resource,appName);
        Entry entry = null;
        try {
             entry = SphU.entry(KEY);
            System.out.println("pass:" + appName);
        }catch (BlockException e){
            System.out.println("block:" + appName);
        }finally {
            if(entry!=null){
                entry.exit();
            }
            ContextUtil.exit();
        }
        
    }
   
    /**
     * 初始化白名单规则
     */
    public  static void initWhiteRule(){
        AuthorityRule authorityRule = new AuthorityRule();
        authorityRule.setResource(KEY);
        authorityRule.setStrategy(RuleConstant.AUTHORITY_WHITE);  //设置白名单类型
        authorityRule.setLimitApp("appA,appB,appE");
        AuthorityRuleManager.loadRules(Collections.singletonList(authorityRule));
    }

    /**
     * 初始化黑名单规则
     */
    public  static void initBlackRule(){
        AuthorityRule authorityRule = new AuthorityRule();
        authorityRule.setResource(KEY);
        authorityRule.setStrategy(RuleConstant.AUTHORITY_BLACK);  //设置白名单类型
        authorityRule.setLimitApp("appA,appB,appE");
        AuthorityRuleManager.loadRules(Collections.singletonList(authorityRule));
    }



}

具体代码请看:com.onion.apiDemo.authorityRule.AuthorityRuleDemo这个demo。github地址会放到文章结尾

github地址https://gitee.com/gzgyc/dubbo-demo.git

一些比集群流控的文章:

https://blog.csdn.net/weixin_42073629/article/details/106450575

https://www.jianshu.com/p/67d02420e814

https://blog.csdn.net/wangzhanzheng/article/details/86477559

生产环境落地的文章:

https://mp.weixin.qq.com/s/AjHCUmygTr78yo9yMxMEyg

posted @ 2021-02-05 11:50  大笨象会跳舞  阅读(1081)  评论(0编辑  收藏  举报