SpringCloudAlibaba之Sentinel流控熔断

Sentinel 的使用可以分为两个部分:

  • 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持(见 主流框架适配)。
  • 控制台(Dashboard):控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。

1. 引入 Sentinel 依赖


	com.alibaba.cloud
	spring-cloud-starter-alibaba-sentinel

2. 入门案例

资源 是 Sentinel 中的核心概念之一。最常用的资源是我们代码中的 Java 方法。 当然,您也可以更灵活的定义你的资源,例如,把需要控制流量的代码用 Sentinel API SphU.entry("HelloWorld")entry.exit() 包围起来即可。在下面的例子中,我们将 System.out.println("hello world"); 作为资源(被保护的逻辑),用 API 包装起来。参考代码如下:

SentinelService.java

package cn.javayuli.service;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 限流测试
 * @author hanguilin
 */
@Service
public class SentinelService {

    /**
     * 处理请求
     */
    public void handleRquest() {
        // 配置规则.
        initFlowRules();

        // 1.5.0 版本开始可以直接利用 try-with-resources 特性,自动 exit entry
        try (Entry entry = SphU.entry("HelloWorld")) {
            // 被保护的逻辑
            System.out.println("hello world");
        } catch (BlockException ex) {
            // 处理被流控的逻辑
            System.out.println("blocked!");
        }
    }

    /**
     * 配置流控规则, QPS最大20
     */
    private void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // Set limit QPS to 20.
        rule.setCount(20);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}

SentinelController.java

package cn.javayuli.controller;

import cn.javayuli.service.SentinelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 限流测试
 * @author hanguilin
 */
@RestController
public class SentinelController {

    @Autowired
    private SentinelService sentinelService;

    /**
     * 请求资源
     */
    @GetMapping("getSource")
    public void doGetSource () {
        sentinelService.handleRquest();
    }

}

3.检查结果

启动项目,并使用Jmeter进行压测

配置1秒发送18个请求

SpringCloudAlibaba之Sentinel流控熔断_第1张图片

配置访问接口

SpringCloudAlibaba之Sentinel流控熔断_第2张图片

控制台正常打印hello world

现在把18调成30,发现已经被锁住了

SpringCloudAlibaba之Sentinel流控熔断_第3张图片

Demo 运行之后,我们可以在日志 ${currentUser}/logs/csp/${appName}-metrics.log.xxx 里看到下面的输出:

SpringCloudAlibaba之Sentinel流控熔断_第4张图片

|--timestamp-|------date time----|--resource-|p |block|s |e|rt
1608555871000|2020-12-21 21:04:31|/getSource|10|0|10|0|42|0|0|1
1608555871000|2020-12-21 21:04:31|HelloWorld|10|0|10|0|0|0|0|0
1608555871000|2020-12-21 21:04:31|__total_inbound_traffic__|10|0|10|0|42|0|0|0
1608555872000|2020-12-21 21:04:32|/getSource|20|0|20|0|1|0|0|1
1608555872000|2020-12-21 21:04:32|HelloWorld|15|5|15|0|0|0|0|0
1608555872000|2020-12-21 21:04:32|__total_inbound_traffic__|20|0|20|0|1|0|0|0

其中 p 代表通过的请求, block 代表被阻止的请求, s 代表成功执行完成的请求个数, e 代表用户自定义的异常, rt 代表平均响应时长。

4.熔断降级

Sentinel 提供了 @SentinelResource 注解用于定义资源,并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException

@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里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:

    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • defaultFallback(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:

    • 返回值类型必须与原函数返回值类型一致;
    • 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
    • defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。

1.8.0 版本开始,defaultFallback 支持在类级别进行配置。

注:1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理

特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandlerfallbackdefaultFallback,则被限流降级时会将 BlockException 直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException)。

从 1.4.0 版本开始,注解方式定义资源支持自动统计业务异常,无需手动调用 Tracer.trace(ex) 来记录业务异常。Sentinel 1.4.0 以前的版本需要自行调用 Tracer.trace(ex) 来记录业务异常。

配置

Spring Cloud Alibaba

若您是通过 Spring Cloud Alibaba 接入的 Sentinel,则无需额外进行配置即可使用 @SentinelResource 注解。

Spring AOP

若您的应用使用了 Spring AOP(无论是 Spring Boot 还是传统 Spring 应用),您需要通过配置的方式将 SentinelResourceAspect 注册为一个 Spring Bean:

@Configuration
public class SentinelAspectConfiguration {

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

我们提供了 Spring AOP 的示例,可以参见 sentinel-demo-annotation-spring-aop。

AspectJ

若您的应用直接使用了 AspectJ,那么您需要在 aop.xml 文件中引入对应的 Aspect:


    

DEMO

系列源代码GitHub地址spring-cloud-demo

代码

/**
 * hello
 *
 * @param s
 * @return
 */
@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
public String hello(long s) {
    if (s == 0) {
        throw new RuntimeException("error");
    }
    return String.format("Hello at %d", s);
}

/**
 * Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
 *
 * @param s
 * @return
 */
public String helloFallback(long s) {
    return String.format("Halooooo %d", s);
}

/**
 * Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.
 *
 * @param s
 * @param ex
 * @return
 */
public String exceptionHandler(long s, BlockException ex) {
    // Do some log here.
    ex.printStackTrace();
    return "Oops, error occurred at " + s;
}

接口测试

传入参数1

SpringCloudAlibaba之Sentinel流控熔断_第5张图片

测试结果为正常调用的结果

SpringCloudAlibaba之Sentinel流控熔断_第6张图片

参数0,测试结果为回调结果

SpringCloudAlibaba之Sentinel流控熔断_第7张图片

5.Sentinel控制台

概述

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。另外,鉴权在生产环境中也必不可少。这里,我们将会详细讲述如何通过简单的步骤就可以使用这些功能。

接下来,我们将会逐一介绍如何整合 Sentinel 核心库和 Dashboard,让它发挥最大的作用。同时我们也在阿里云上提供企业级的控制台:AHAS Sentinel 控制台,您只需要几个简单的步骤,就能最直观地看到控制台如何实现这些功能。

Sentinel 控制台包含如下功能:

  • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
  • 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
  • 规则管理和推送:统一管理推送规则。
  • 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。

注意:Sentinel 控制台目前仅支持单机部署。

下载

  • jar包可以在release页面进行下载
  • 或者下载源码,运行时需要自行打包

注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。

鉴权

从 Sentinel 1.5.0 开始,控制台提供通用的鉴权接口 AuthService,用户可根据需求自行实现。

从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel

用户可以通过如下参数进行配置:

  • -Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel
  • -Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel
  • -Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;

同样也可以直接在 Spring properties 文件中进行配置。

服务端

使用如下命令启动控制台:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

如若8080端口冲突,可使用 -Dserver.port=新端口 进行设置。

浏览器打开localhost:8080,用户名和密码均为sentinel

SpringCloudAlibaba之Sentinel流控熔断_第8张图片

客户端

在application.yml中加入如下配置

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080

如果是用nacos作为配置中心,需要在nacos中配置应用的配置文件

SpringCloudAlibaba之Sentinel流控熔断_第9张图片

使用

如果我们想使用Sentinel的限流和熔断功能,除了在代码中可以硬编码外,也可直接通过控制台进行粗略的对接口进行限流和熔断。

在Controller中加入测试方法,注意此Controller使用的时@RestController注解,如果是@Controller,请给方法加上@ResponseBody注解

/**
 * 请求资源
 */
@GetMapping("/testReq")
@SentinelResource("testSource")
public String doTest () {
    return "test";
}

先调用一次该方法,方便被簇点链路收集,调用后,可在控制台->簇点链路中看到该资源

SpringCloudAlibaba之Sentinel流控熔断_第10张图片

点击+流控新增规则

使用Jmeter进行测试,每秒执行10个请求

SpringCloudAlibaba之Sentinel流控熔断_第11张图片

http请求

SpringCloudAlibaba之Sentinel流控熔断_第12张图片

发现此处通过QPS最大限定值后,其余请求都被拒绝

SpringCloudAlibaba之Sentinel流控熔断_第13张图片

你可能感兴趣的:(SpringCloud,spring,cloud,alibaba)