暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Sentinel介绍与使用

码酱 2021-09-06
570

前言:为什么需要流控降级?

我们的生产环境经常会出现一些不稳定的情况,如:
  • 大促时瞬间洪峰流量导致系统超出最大负载,load 飙高,系统崩溃导致用户无法下单

  • “黑马”热点商品击穿缓存,DB 被打垮,挤占正常流量

  • 调用端被不稳定服务拖垮,线程池被占满,导致整个调用链路卡死 

这些不稳定的场景可能会导致严重后果。大家可能想问:如何做到均匀平滑的用户访问?如何预防流量过大或服务不稳定带来的影响?这时候我们就要请出微服务稳定性的法宝 —— 高可用流量防护,其中重要的手段就是流量控制熔断降级,它们是保障微服务稳定性重要的一环。

为什么需要流量控制?

流量是非常随机性的、不可预测的。前一秒可能还风平浪静,后一秒可能就出现流量洪峰了(例如双十一零点的场景)。然而我们系统的容量总是有限的,如果突然而来的流量超过了系统的承受能力,就可能会导致请求处理不过来,堆积的请求处理缓慢,CPU/Load 飙高,最后导致系统崩溃。因此,我们需要针对这种突发的流量来进行限制,在尽可能处理 请求的同时来保障服务不被打垮,这就是流量控制。

为什么需要熔断降级?

一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格, 可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务 出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。

现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定, 就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务进行 熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。

上面大致介绍了一下服务熔断和限流,现在来看Sentinel

Sentinel: 高可用护航的利器

Sentinel 是阿里巴巴开源的,面向分布式服务架构的高可用防护组件,主要以流量为切入点,从流量控制、流量整形、熔断降级、系统自适应保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心 场景,例如秒杀、冷启动、消息削峰填谷、自适应流量控制、实时熔断下游不可用服务等, 是保障微服务高可用的利器,原生支持 Java/Go/C++ 等多种语言,并且提供 Istio/Envoy 全局流控支持来为 Service Mesh 提供高可用防护的能力。
Sentinel 的技术亮点
  • 高度可扩展能力:基础核心 + SPI 接口扩展能力,用户可以方便地扩展流控、通信、 监控等功能。

  • 多样化的流量控制策略(资源粒度、调用关系、流控指标、流控效果等多个维度),提 供分布式集群流控的能力。 

  • 热点流量探测和防护。

  • 对不稳定服务进行熔断降级和隔离。

  • 全局维度的系统负载自适应保护,根据系统水位实时调节流量。 

  • 覆盖 API Gateway 场景,为 Spring Cloud Gateway、Zuul 提供网关流量控制的能力。 

  • 实时监控和规则动态配置管理能力。

Sentinel 主要特性

Sentinel 生态圈

关于Sentinel与Hystrix的区别见:https://yq.aliyun.com/articles/633786/

前期我们也写了一篇关于Hystrix的文章,可以对比着学习SpringCloud-Hystrix解决雪崩

Sentinel 入门案例

1.官网下载Sentinel的jar包,https://github.com/alibaba/Sentinel/releases

启动,用户和密码为sentinel

接上篇dubbo入门案例项目听说Dubbo很不错!

加入sentinel的依赖

 <!-- Sentinel依赖-->
  <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
      <version>2.2.5.RELEASE</version>
  </dependency>

复制
在application.yml中添加sentinel控制台信息
 spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080   #sentinel控制台的请求地址

复制
启动项目,查看sentinel控制台

@SentinelResource 注解

  • 注意:注解方式埋点不支持 private 方法。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:

  • value:资源名称,必需项(不能为空)

  • entryType:entry 类型,可选项(默认为 EntryType.OUT)

  • blockHandler / blockHandlerClass:

blockHandler 对应处理 BlockException的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必须为 static 函数,否则无法解析。

  • fallback /fallbackClass

    :fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。

  • defaultFallback

    (since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。

fallback 函数签名和位置要求:

  • 返回值类型必须与原函数返回值类型一致;

  • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。

  • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass为对应的类的 Class 对象,注意对应的函数必须为 static 函数,否则无法解析。

defaultFallback 函数签名要求:

  • 返回值类型必须与原函数返回值类型一致;

  • 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。

  • defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必须为 static 函数,否则无法解析。

  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

定义规则
FlowRuleManager.loadRules(List<FlowRule> rules); // 修改流控规则
DegradeRuleManager.loadRules(List<DegradeRule> rules); // 修改降级规则
SystemRuleManager.loadRules(List<SystemRule> rules); // 修改系统规则
AuthorityRuleManager.loadRules(List<AuthorityRule> rules); // 修改授权规则


复制
举例熔断降级,流控的硬编码方式
@PostConstruct
    public void initSentinelRule() {
        //熔断规则:5s内调用接口出现异常次数超过5的时候, 进行熔断
        List<DegradeRule> degradeRules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource("getUserList");
        rule.setCount(5);
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);//熔断规则
        rule.setTimeWindow(5);
        degradeRules.add(rule);
        DegradeRuleManager.loadRules(degradeRules);


        //流控规则:QPS为2
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource("getUserList");
        // QPS控制在2以内
        rule1.setCount(2);
        // QPS限流
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    }


复制
控制台配置方式

新增一条流控

当qps达到2时,会出现sentinel流控效果

在实际项目中,我们可能不想看到这样的返回效果,这时候我们可以自定义
@GetMapping("/users")
@SentinelResource(value = "provider",blockHandlerClass = MyHandler.class,blockHandler "myBlockHandler",
        fallbackClass = MyHandler.class,fallback "myFallBack")
public String getUserList(){
    Random random = new Random();
    //生成0,5之间的整数
    int i = random.nextInt(5);
    System.out.println(i);
    if(i>2){
        throw new RuntimeException("搞事情!!!");
    }
    List<User> userList = conUserService.getUserList();
    System.out.println(userList);
    return userList.toString();
}

复制
@Slf4j
public class MyHandler {
    /**
     * 限流降级时调用
     * @return
     */

    public static String myBlockHandler(BlockException e){
        log.info("限流了!!!!"+e.getMessage());
        return "限流了!!!!";
    }

    /**
     * 出错时调用
     * @return
     */

    public static String myFallBack(){
        log.info("出错了!!!");
        return "出错了!!!";
    }
}

复制

看一下效果,当QPS大于2时,会出现限流

更多详细教程见官方文档https://github.com/alibaba/Sentinel/wiki/



喜欢就加个关注吧,


文章转载自码酱,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论