Sentinel的使用分为两个部分:
- 核心库:通过代码的手段对资源进行流控降级的处理。
- 控制台:通过可视化控制台的方式对资源进行流控。
1. 核心库的方式:
- 引入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.6</version>
</dependency>
- 定义接口
@RestController
@Slf4j
public class HelloController {
private static final String RESOURCE_NAME = "hello";
// 进行 sentinel 流控
@RequestMapping(value = "/hello")
public String hello(){
Entry entry =null;
try {
// 1. sentinel 针对资源进行限制
entry= SphU.entry(RESOURCE_NAME);
// 被保护的业务逻辑
String str="hello world";
log.info("========"+str+"==========");
return str;
}catch (BlockException ex){
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
log.info("block");
return "被流控了!";
}catch (Exception ex){
// 如需要配置降级规则,需要通过这种方式记录业务异常
Tracer.traceEntry(ex,entry);
}finally {
if(entry!=null){
entry.exit();
}
}
return null;
}
/**
* 定义 流控规则
*/
@PostConstruct
private /*static*/ void initFlowRules(){
log.info("流控规则的初始化.........");
// 流控规则
List<FlowRule> rules=new ArrayList<>();
// 流控设置 1
FlowRule rule=new FlowRule();
// 设置受保护的资源
rule.setResource(RESOURCE_NAME);
// 设置流控规则 QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
// Set limit QPS to 20
rule.setCount(1);
rules.add(rule);
// 流控设置 2
FlowRule rule1=new FlowRule();
// 设置受保护的资源
rule1.setResource(USER_RESOURCE_NAME);
// 设置流控规则 QPS
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
// Set limit QPS to 20
rule1.setCount(1);
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
/**
* 定义 降级规则
*/
@PostConstruct
public void initDegradeRule(){
log.info("熔断降级的初始化........");
/* 降级规则 异常*/
List<DegradeRule> degradeRules=new ArrayList<>();
DegradeRule degradeRule=new DegradeRule();
degradeRule.setResource(DEGRADE_RESOURCE_NAME);
// 设置规则: 异常数
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
degradeRule.setCount(2);
// 触发熔断的最小请求数
degradeRule.setMinRequestAmount(2);
// 统计时长: 单位:ms
degradeRule.setStatIntervalMs(5000);
// 熔断持续时长
// 一旦触发了熔断,再次请求对应的接口就会直接调用 降级方法
// timeWindow时间结束,再次请求对应的接口,如果第一次请求就发生异常,直接熔断。
degradeRule.setTimeWindow(10);
degradeRules.add(degradeRule);
DegradeRuleManager.loadRules(degradeRules);
}
}
@SentinelResource 注解的使用
- 引入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
</dependency>
@SentinelResource 注解
- value:资源名称,不能为空。
- entryType:流量类型。EntryType.IN:入口流量,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 函数,否则无法解析
- exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
注意:特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出。
基于@SentinelResource 注解对资源的访问进行控制
定义 @Bean SentinelResourceAspect
@SpringBootApplication
public class _01DemoApplication {
public static void main(String[] args) {
SpringApplication.run(_01DemoApplication.class,args);
}
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
}
对接口进行流量控制
@RestController
@Slf4j
public class HelloController {
private static final String USER_RESOURCE_NAME = "user";
private static final String DEGRADE_RESOURCE_NAME = "degrade";
@RequestMapping("/user")
@SentinelResource(value = USER_RESOURCE_NAME,blockHandler = "blockHandlerForGerUser")
public User getUser(String id){
return new User("wuyu");
}
public User blockHandlerForGerUser(String id , BlockException ex){
ex.printStackTrace();
return new User("流控!!!");
}
@RequestMapping("/degrade")
@SentinelResource(value = DEGRADE_RESOURCE_NAME,entryType = EntryType.IN,blockHandler = "blockHandlerForDegrade")
public User degrade(){
throw new RuntimeException();
}
public User blockHandlerForDegrade(BlockException blockException){
blockException.printStackTrace();
return new User("熔断了");
}
/**
* 定义 流控规则
*/
@PostConstruct
private /*static*/ void initFlowRules(){
log.info("流控规则的初始化.........");
// 流控规则
List<FlowRule> rules=new ArrayList<>();
// 流控规则 1
FlowRule rule=new FlowRule();
// 设置受保护的资源
rule.setResource(RESOURCE_NAME);
// 设置流控规则 QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
// Set limit QPS to 20
rule.setCount(1);
rules.add(rule);
// 流控规则 2
FlowRule rule1=new FlowRule();
// 设置受保护的资源
rule1.setResource(USER_RESOURCE_NAME);
// 设置流控规则 QPS
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
// Set limit QPS to 20
rule1.setCount(1);
rules.add(rule1);
FlowRuleManager.loadRules(rules);
}
/**
* 定义 熔断规则
*/
@PostConstruct
public void initDegradeRule(){
log.info("熔断降级的初始化........");
/* 降级规则 异常*/
List<DegradeRule> degradeRules=new ArrayList<>();
DegradeRule degradeRule=new DegradeRule();
degradeRule.setResource(DEGRADE_RESOURCE_NAME);
// 设置规则: 异常数
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
degradeRule.setCount(2);
// 触发熔断的最小请求数
degradeRule.setMinRequestAmount(2);
// 统计时长: 单位:ms
degradeRule.setStatIntervalMs(5000);
// 熔断持续时长
// 一旦触发了熔断,再次请求对应的接口就会直接调用 降级方法
// timeWindow时间结束,再次请求对应的接口,如果第一次请求就发生异常,直接熔断。
degradeRule.setTimeWindow(10);
degradeRules.add(degradeRule);
DegradeRuleManager.loadRules(degradeRules);
}
}
2. 控制台的方式(基于spring-cloud-alibaba):
- 准备sentinel控制台:
下载sentinel的jar包
为了方便sentinel的启动可以通过.bat文件去启动jar包:
server.port: 设置控制台的端口
sentinel.dashboard.auth.username:设置登陆的用户名
sentinel.dashboard.auth.password:设置密码
创建一个.bat文件,加入下面脚本,注意修改自己的配置(写在一行,不要换行):
java -Dserver.port=1111 -Dsentinel.dashboard.auth.username=wuyu -Dsentinel.dashboard.auth.password=123456 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar pause
- 引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- 配置yml文件
server:
port: 8011
spring:
application:
name: order-service
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:1111
- 对流控异常进行统一处理(这里的Result,和Response是封装的工具类)
@Component
@Slf4j
public class MyBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
log.info("BlockExceptionHandler BlockException================"+e.getRule());
Result result=null;
if(e instanceof FlowException){
result=Result.fail("被流控了");
}else if(e instanceof ParamFlowException){
result=Result.fail("参数流控了");
}else if(e instanceof DegradeException){
result=Result.fail("服务降级了");
}else if(e instanceof AuthorityException){
result=Result.fail("授权规则不通过");
}else if(e instanceof SystemBlockException){
result=Result.fail("触发系统保护规则");
}
Response.write(httpServletResponse,result);
}
}
接口信息
@RestController
@RequestMapping("/order")
@Slf4j
public class OrderController {
@RequestMapping("/add")
// @SentinelResource(value = "add",blockHandler = "blockHandlerForAdd")
public String add(){
log.info(Thread.currentThread()+"--正在下单....");
return "下单成功";
}
@RequestMapping("/get")
public String get(){
log.info(Thread.currentThread()+"--正在查询");
return "查询成功";
}
}
通过控制台进行配置流控规则,就可以直接对资源的访问进行限制,如果被流控了,会触发BlockException异常,我们实现的BlockExceptionHandler接口,会对这类异常进行统一处理。