@SentinelResource详解
往期回顾
Nacos的安装与配置
Spring Cloud集成Nacos作为注册中心
LoadBalacer集成Nacos实现负载均衡
常见的负载均衡策略分析
Spring Cloud集成Dubbo实现RPC调用
SpringCloud集成Nacos作为配置中心
Nacos整合OpenFegin实现RPC调用
Nacos整合Gateway入门实例
Spring Cloud Gateway的过滤器配置
Nacos整合Gateway实现动态路由
Sentinel的安装与配置
前面我们已经简单的介绍了如何安装与使用Sentinel,接下来我们继续来看看Sentinel的一些核心概念以及特性吧
基本概念回顾
我们前面已经介绍过Sentinel的两个核心概念,这里我们再回顾一下吧:
- Sentinel 的基本概念有两个,它们分别是:资源和规则
基本概念 | 描述 |
---|---|
资源 | 资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如由应用程序提供的服务或者是服务里的方法,甚至可以是一段代码。 我们可以通过 Sentinel 提供的 API 来定义一个资源,使其能够被 Sentinel 保护起来。通常情况下,我们可以使用方法名、URL 甚至是服务名来作为资源名来描述某个资源。 |
规则 | 围绕资源而设定的规则。Sentinel 支持流量控制、熔断降级、系统保护、来源访问控制和热点参数等多种规则,所有这些规则都可以动态实时调整。 |
定义资源
Sentinel需要先把可能需要保护的资源定义好,之后再配置规则。也可以理解为,只要有了资源,我们就可以在任何时候灵活地定义各种流量控制规则。在编码的时候,只需要考虑这个代码是否需要保护,如果需要保护,就将之定义为一个资源。
Sentinel提供多种定义资源的方式,分别是:
- 主流框架的默认适配
- 抛出异常的方式定义资源
- 返回布尔值方式定义资源
- 注解方式定义资源
- 异步调用支持
这里我不再一一的详细介绍,想要详细了解每种方式的同学可以自行查阅官网
@SentinelResource 注解
Sentinel 支持通过 @SentinelResource
注解定义资源并配置 blockHandler
和 fallback
函数来进行限流之后的处理。@SentinelResource 注解是 Sentinel 提供的最重要的注解之一,它还包含了多个属性,如下表:
属性 | 说明 | 必填与否 | 使用要求 |
---|---|---|---|
value | 用于指定资源的名称 | 必填 | - |
entryType | entry 类型 | 可选项(默认为 EntryType.OUT) | - |
blockHandler | 服务限流后会抛出 BlockException 异常,而 blockHandler 则是用来指定一个函数来处理 BlockException 异常的。 简单点说,该属性用于指定服务限流后的后续处理逻辑。 | 可选项 |
|
blockHandlerClass | 若 blockHandler 函数与原方法不在同一个类中,则需要使用该属性指定 blockHandler 函数所在的类。 | 可选项 |
|
fallback | 用于在抛出异常(包括 BlockException)时,提供 fallback 处理逻辑。 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。 | 可选项 |
|
fallbackClass | 若 fallback 函数与原方法不在同一个类中,则需要使用该属性指定 blockHandler 函数所在的类。 | 可选项 |
|
defaultFallback | 默认的 fallback 函数名称,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。 默认 fallback 函数可以针对所以类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。 | 可选项 |
|
exceptionsToIgnore | 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。 | 可选项 | - |
注:在 Sentinel 1.6.0 之前,fallback 函数只针对降级异常(DegradeException)进行处理,不能处理业务异常。
让我们再回顾一下之前的例子
@GetMapping("/register")@SentinelResource("register")public CommonResult<String> register() {userService.register();return ResultUtils.success();}
前面我们用到的@SentinelResource注解就是定义资源了,服务启动并被调用过该接口后(Sentinel懒加载)就可以再控制台看到对应的资源,我们就可以对其添加对应的规则了
注意:注解方式埋点不支持 private 方法。
特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出
BlockException
时只会进入blockHandler
处理逻辑。若未配置blockHandler
、fallback
和defaultFallback
,则被限流降级时会将BlockException
直接抛出。
代码示例:
public class TestService {// 对应的 `handleException` 函数需要位于 `ExceptionUtil` 类中,并且必须为 static 函数.@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})public void test() {System.out.println("Test");}// 原函数@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")public String hello(long s) {return String.format("Hello at %d", s);}// Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.public String helloFallback(long s) {return String.format("Halooooo %d", s);}// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.public String exceptionHandler(long s, BlockException ex) {// Do some log here.ex.printStackTrace();return "Oops, error occurred at " + s;}
}
Sentinel自定义限流异常处理
系统有默认的异常页面,但是该异常页面对用户不友好,我们应该尽量避免直接返回系统默认的异常页面,而需要根据自己的需求自定义对应的异常处理逻辑
方法级别
我们可以自定义通用的限流处理逻辑,然后在@SentinelResource中指定。
/*** @author Pymjl* @version 1.0* @date 2022/8/25 12:48**/
@RestController
@RequestMapping("/user")
@Log4j2
public class UserController {@ResourceUserService userService;@Value("${server.port}")private String port;@GetMapping("/test")@SentinelResource(value = "test", blockHandler = "handleTest")public CommonResult<String> test(HttpServletRequest request) throws UnknownHostException {System.out.printf("被[/%s:%s]调用了一次%n", request.getRemoteHost(), request.getRemotePort());String hostAddress = InetAddress.getLocalHost().getHostAddress() + ":" + port;return ResultUtils.success(hostAddress);}@GetMapping("/get/{id}")@SentinelResource(value = "getUser")public CommonResult<User> get(@PathVariable("id") Long id) {return ResultUtils.success(userService.get(id));}public CommonResult<String> handleTest(HttpServletRequest request, BlockException blockException) {log.error("调用/user/test失败");return ResultUtils.fail("Sentinel流控,调用失败");}}
通过@SentinelResource的blockhandler属性指定对应的异常处理逻辑
注意:
- blockHandler 函数访问范围需要是 public
- 返回类型需要与原方法相匹配
- 参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException
- blockHandler 函数默认需要和原方法在同一个类中,若希望使用其他类的函数,则可以指定 blockHandler 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析
当抛出异常时,若注解指定了异常的处理逻辑那么就直接使用指定的逻辑。若未指定,使用全局的异常处理,否则就返回默认的异常页面
全局异常处理
创建一个全局处理的类,然后实现BlockExceptionHandler
package cuit.epoch.pymjl.handler;import cn.hutool.json.JSONUtil;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import cuit.epoch.pymjl.result.CommonResult;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;/*** @author Pymjl* @version 1.0* @date 2022/9/4 19:57**/
@Component
@Log4j2
public class MyBlockExceptionHandler implements BlockExceptionHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e)throws Exception {//getRule返回资源、规则的详细信息log.error("BlockExceptionHandler BlockException================" + e.getRule());CommonResult<String> result = new CommonResult<>();result.setSucceed(false);if (e instanceof FlowException) {result.setMessage("接口被限流了");} else if (e instanceof DegradeException) {result.setMessage("服务降级了");} else if (e instanceof ParamFlowException) {result.setMessage("热点参数被限流了");} else if (e instanceof AuthorityException) {result.setMessage("授权规则不通过");}//返回Json数据httpServletResponse.setStatus(500);httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);try (PrintWriter writer = httpServletResponse.getWriter()) {writer.write(JSONUtil.toJsonPrettyStr(result));writer.flush();} catch (IOException ioException) {log.error("异常:{}", ioException.toString());}}
}
测试
我们启动服务,然后将对应的资源初始化再Sentinel的控制台,然后添加对应的流控规则
访问接口,对应的接口,观察结果
我们可以看到,因为test这个资源指定了对应的异常处理逻辑,所以返回的是handleTest中的处理逻辑
而因为/user/get/1
并未指定,所以就走的全局异常处理逻辑
遇见的bug
注:我这里遇见几个问题,因为水品有限,暂时还不知道这种情况的原因:
- 当给URL配置流控规则时,blockhandler指定的异常处理逻辑失效,如图:
对应的代码:
/*** @author Pymjl* @version 1.0* @date 2022/8/25 12:48**/
@RestController
@RequestMapping("/user")
@Log4j2
public class UserController {@ResourceUserService userService;@Value("${server.port}")private String port;@GetMapping("/test")@SentinelResource(value = "test", blockHandler = "handleTest")public CommonResult<String> test(HttpServletRequest request) throws UnknownHostException {System.out.printf("被[/%s:%s]调用了一次%n", request.getRemoteHost(), request.getRemotePort());String hostAddress = InetAddress.getLocalHost().getHostAddress() + ":" + port;return ResultUtils.success(hostAddress);}public CommonResult<String> handleTest(HttpServletRequest request, BlockException blockException) {log.error("调用/user/test失败");return ResultUtils.fail("Sentinel流控,调用失败");}}
并没有走指定的异常处理逻辑,而是进入了全局的限流异常处理。当给对应的资源test
添加对应的流控规则时解决该问题
- 当给未指定限流处理逻辑的资源添加对应的流控规则时,抛出的时fallback异常
对应的代码
@GetMapping("/get/{id}")@SentinelResource(value = "getUser")public CommonResult<User> get(@PathVariable("id") Long id) {return ResultUtils.success(userService.get(id));}
返回的却是fallback异常,按照我的理解应该是走限流的全局异常处理才是
如果有同学知道原因还请指正
项目源码:gitee github
get(@PathVariable(“id”) Long id) {
return ResultUtils.success(userService.get(id));
}
[外链图片转存中...(img-EDtQfWvU-1662298885385)]返回的却是fallback异常,按照我的理解应该是走限流的全局异常处理才是> 如果有同学知道原因还请指正项目源码:[gitee](https://gitee.com/pymjl_0/cloud-learn) [github](https://github.com/Pymjl/cloud-learn)
@SentinelResource详解相关推荐
- Sentinel @SentinelResource 详解
Sentinel 提供了 @SentinelResource 注解用于定义资源,并提供了 AspectJ 的扩展用于自动定义资源.处理 BlockException 等.使用 Sentinel Ann ...
- @SentinelResource 注解详解
@SentinelResource 注解详解 引入 pom 依赖 @SentinelResource 注解 引入 pom 依赖 官网说明: Sentinel 提供了 @SentinelResource ...
- 从命令行到IDE,版本管理工具Git详解(远程仓库创建+命令行讲解+IDEA集成使用)
首先,Git已经并不只是GitHub,而是所有基于Git的平台,只要在你的电脑上面下载了Git,你就可以通过Git去管理"基于Git的平台"上的代码,常用的平台有GitHub.Gi ...
- JVM年轻代,老年代,永久代详解
秉承不重复造轮子的原则,查看印象笔记分享连接↓↓↓↓ 传送门:JVM年轻代,老年代,永久代详解 速读摘要 最近被问到了这个问题,解释的不是很清晰,有一些概念略微模糊,在此进行整理和记录,分享给大家.在 ...
- docker常用命令详解
docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...
- 通俗易懂word2vec详解词嵌入-深度学习
https://blog.csdn.net/just_so_so_fnc/article/details/103304995 skip-gram 原理没看完 https://blog.csdn.net ...
- 深度学习优化函数详解(5)-- Nesterov accelerated gradient (NAG) 优化算法
深度学习优化函数详解系列目录 深度学习优化函数详解(0)– 线性回归问题 深度学习优化函数详解(1)– Gradient Descent 梯度下降法 深度学习优化函数详解(2)– SGD 随机梯度下降 ...
- CUDA之nvidia-smi命令详解---gpu
nvidia-smi是用来查看GPU使用情况的.我常用这个命令判断哪几块GPU空闲,但是最近的GPU使用状态让我很困惑,于是把nvidia-smi命令显示的GPU使用表中各个内容的具体含义解释一下. ...
- Bert代码详解(一)重点详细
这是bert的pytorch版本(与tensorflow一样的,这个更简单些,这个看懂了,tf也能看懂),地址:https://github.com/huggingface/pytorch-pretr ...
最新文章
- NetBeans 时事通讯(刊号 # 117 - Sep 16, 2010)
- jdbc链接数据库mysql
- 7-8 数字三角形 (31 分)(思路+详解+动态规划)Come Baby!!!!!!!!!!!
- storm mysql druid_Druid 集成
- loadrunner学习记录一
- [转]将微信和支付宝支付的个二维码合二为一
- python中pop函数的用法_python中pop()函数怎么用
- 人工智能运行环境linux,Intel OpenVINO 人工智能推论环境搭建 (Linux) 第一章
- 调整样式_“寒来暑往”美国海军陆战队应季节调整迷彩样式的规定变化
- 高效Redis Client多线程操作的并发吞吐设计
- 【风电功率预测】基于matlab BP神经网络风电功率预测【含Matlab源码 399期】
- WinDbg 入门教程
- 网络流量分析与Android逆向小结
- mysql 的一个错误 Error Code: 2013. Lost connection to MySQL server during...
- NetCDF数据处理
- MQTT的学习之Mosquitto简要教程(安装使用)
- 计算机丢失softwareinspect,logo1 systemInspect山泉查不到。。。和顶的又不一样[求助】...
- 百度云盘archlinux manjaro直接安装
- Java实现调用默认浏览器打开网址
- 测试过程中遇到的那些奇葩bug
热门文章
- Java使用华软通信能力平台实现短信发送
- halcon介绍以及与opencv比较
- [论文笔记]Beyond Part Models: Person Retrieval with Refined Part Pooling(PCB)
- 数理统计之协方差矩阵
- 微信小程序入门10-微信公众号token验证失败
- N1文法 ーー 可能・不可能・禁止
- 2020,AI创业与投资进入“深水区”
- Linux学习-67-日志服务器设置和日志分析工具(logwatch)安装及使用
- 常见的RC是什么意思
- ECharts2.0