Sentinel 的使用可以分为两个部分:
- 核心库(Java 客户端):不依赖任何框架/库,能够运行于 Java 7 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard):控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。
1. 引入 Sentinel 依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
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个请求
配置访问接口
控制台正常打印hello world
现在把18调成30,发现已经被锁住了
Demo 运行之后,我们可以在日志 ${currentUser}/logs/csp/${appName}-metrics.log.xxx
里看到下面的输出:
|--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
处理逻辑。若未配置 blockHandler
、fallback
和 defaultFallback
,则被限流降级时会将 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:
<aspects>
<aspect name="com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect"/>
</aspects>
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
测试结果为正常调用的结果
参数0,测试结果为回调结果
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
客户端
在application.yml中加入如下配置
spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: localhost:8080
如果是用nacos作为配置中心,需要在nacos中配置应用的配置文件
使用
如果我们想使用Sentinel的限流和熔断功能,除了在代码中可以硬编码外,也可直接通过控制台进行粗略的对接口进行限流和熔断。
在Controller中加入测试方法,注意此Controller使用的时@RestController注解,如果是@Controller,请给方法加上@ResponseBody注解
/**
* 请求资源
*/
@GetMapping("/testReq")
@SentinelResource("testSource")
public String doTest () {
return "test";
}
先调用一次该方法,方便被簇点链路收集,调用后,可在控制台->簇点链路中看到该资源
点击+流控
新增规则
使用Jmeter进行测试,每秒执行10个请求
http请求
发现此处通过QPS最大限定值后,其余请求都被拒绝