Springboot整合Sentinel实现流控
在Springboot项目中整合Sentinel实现流控,Gateway整合Sentinel见Gateway整合Sentinel,Sentinel-daahboard的改造见Sentinel-dashboard改造(普通流控和网关流控规则持久化到Nacos)
本文章节如下,有兴趣可以自行跳转
1、sentinel资源的定义
2、依赖的引入
3、增加过滤器配置(将controller自动定义为资源)
4、增加UrlCleaner(url资源清洗)
5、Sentinel的BlockException统一处理
6、WebCallbackManager设置统一异常处理和Url清洗
7、Sentinel控制台和规则数据源(nacos)配置
8、Sentinel整合Feign实现服务降级熔断
1、sentinel资源的定义
sentinel里面有一个很重要的定义:资源。其实就是一段给包围起来的代码块,和java里面的关键字synchronized很想,可以支持加在方法上则对整个方法加锁,加在代码块上则是对代码块加锁。
sentinel是对资源实施流控,其提供了三种方式来定义资源:
1、为了适配web servlet,将每个controller接口自动定义为一个资源,资源名称就是接口的路径
2、方法上添加@SentinelResource注解,将整个方法定义为一个资源,资源名称自己定义
3、就是在代码中针对某一个代码块来定义,被SphU.entry()和e0.exit()包裹的代码块就是一个资源,下面给出代码示例:
private void doSomethingWithEntry() { Entry e0 = null; try { e0 = SphU.entry("benchmark"); doSomething(); } catch (BlockException e) { } finally { if (e0 != null) { e0.exit(); } } }
对于已经存在的项目,此时采用方式1就非常方便,基本无代码入侵,整合的工作量小很多,如果是对网关进行流控,则更加的方便,其他的微服务完全不需要修改。
2、依赖的引入
<!--sentinel相关start--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>3.0.1</version> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <!--使其主动对所有的url进行统计,把所有的controller接口识别成资源--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-web-servlet</artifactId> </dependency> <!--sentinel相关end-->
3、增加过滤器配置(将controller自动定义为资源)
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean sentinelFilterRegistration() { FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(); registration.setFilter(new CommonFilter()); registration.addUrlPatterns("/*"); registration.setName("sentinelFilter"); registration.setOrder(1); return registration; } }
4、增加UrlCleaner(url资源清洗)
/** * 一些接口采用了 @PathVariable 注解,每一个url都会被识别成资源,但是sentinel最多支持6000个,所以需要处理 * 例如:/name/{id}可能会有/name/1、/name/2、/name/3,如果不处理就是三个资源,但是其实这是一个资源,所有在这里统一处理 * * @Date 2022/8/3 16:31 */ public class WebUrlCleaner implements UrlCleaner { /** * 正则匹配 */ private static String PATTERN_SENTINEL_TEST_NAME = "^/name/[0-9a-zA-Z]+$"; private static String SENTINEL_RESOURCE_SENTINEL_TEST_NAME = "/name/*"; private static Pattern pattern = Pattern.compile(PATTERN_SENTINEL_TEST_NAME); @Override public String clean(String originUrl) { if (pattern.matcher(originUrl).matches()) { return SENTINEL_RESOURCE_SENTINEL_TEST_NAME; } else { return originUrl; } } }
5、Sentinel的BlockException统一处理
因为其默认的异常提示不友好,也不符合项目中的统一返回定义,所以需要针对该情况做修改,示例代码如下:
public class WebUrlBlockHandler implements UrlBlockHandler { @Override public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException { HashMap<Object, Object> result = new HashMap<>(2); String msg = null; Integer code = 0; if (e instanceof FlowException) { msg = "小主慢一点,处理不过来啦!"; code = 1; } else if (e instanceof DegradeException) { msg = "当前服务不可用,请稍后重试!"; code = 2; } else if (e instanceof ParamFlowException) { msg = "热点参数限流"; code = 3; } else if (e instanceof SystemBlockException) { msg = "系统规则(负载/....)不满足要求"; code = 4; } else if (e instanceof AuthorityException) { msg = "授权规则不通过"; code = 5; } result.put("code", code); result.put("msg", msg); response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); objectMapper.writeValue(response.getWriter(), result); } }
6、WebCallbackManager设置统一异常处理和Url清洗
WebCallbackManager里面提供的set方法都是静态的,所以可以在程序启动时就将自定义的异常处理和Url清洗设置进去
@Configuration public class SentinelConfig { static { //设置自定义的Block异常处理 WebCallbackManager.setUrlBlockHandler(new WebUrlBlockHandler()); //设置url清洗 WebCallbackManager.setUrlCleaner(new WebUrlCleaner()); } }
7、Sentinel控制台和规则数据源(nacos)配置
关于sentinel的配置分为控制台和数据源,这部分的数据中涉及到ip,所以可以将这部分配置放到nocas上,这样就可以实现动态修改了
注意:
1、配置的nacos命名空间需要和sentinel控制台中配置的nacos命名空间保持一致
2、data-id:${spring.application.name}-flow-rules,这些名称,是在改造sentinel控制台源码时自己定义的,名称不重要,重要的是和sentinel控制台源码保持一致,控制台在向Nacos保存规则时是什么data-id,则此处就需要配置什么data-id
spring: application: name: sentinel cloud: sentinel: transport: #Sentinel控制台地址 dashboard: 127.0.0.1:8080 eager: true #当前服务的ip clientIp: 127.0.0.1 port: 8719 datasource: #================流控=============== flow: nacos: server-addr: 127.0.0.1:8848 #与sentinel控制台的namespeace统一 namespace: 6db12247-153b-4d0c-bef6-5c7c5e48faa3 #nacos中存储规则的dataId,对于dataId使用了${spring.application.name}变量,这样可以根据应用名来区分不同的规则配置 data-id: ${spring.application.name}-flow-rules #nacos中存储规则的groupId(可以自己定义) group-id: SENTINEL_GROUP #具体的类型见,org.springframework.cloud.alibaba.sentinel.datasource.RuleType rule-type: flow #nacos的用户名和密码 username: nacos password: nacos #================流控=============== degrade: nacos: server-addr: 127.0.0.1:8848 namespace: 6db12247-153b-4d0c-bef6-5c7c5e48faa3 data-id: ${spring.application.name}-degrade-rules group-id: SENTINEL_GROUP rule-type: degrade username: nacos password: nacos #================系统规则=============== system: nacos: server-addr: 127.0.0.1:8848 namespace: 6db12247-153b-4d0c-bef6-5c7c5e48faa3 data-id: ${spring.application.name}-system-rules group-id: SENTINEL_GROUP rule-type: system username: nacos password: nacos #================授权规则=============== authority: nacos: server-addr: 127.0.0.1:8848 namespace: 6db12247-153b-4d0c-bef6-5c7c5e48faa3 data-id: ${spring.application.name}-authority-rules group-id: SENTINEL_GROUP rule-type: authority username: nacos password: nacos #================热点规则=============== param-flow: nacos: server-addr: 127.0.0.1:8848 namespace: 6db12247-153b-4d0c-bef6-5c7c5e48faa3 data-id: ${spring.application.name}-param-flow-rules group-id: SENTINEL_GROUP rule-type: param-flow username: nacos password: nacos
8、Sentinel整合Feign实现服务降级熔断
Sentinel已经和Feign实现整合,可以采用Feign封装Http请求,然后在sentinel控制台的簇点链路中找到该资源,增加降级和熔断规则,当满足条件时,就可以实现服务的熔断
注意:feign调用的微服务和当前微服务需要在nacos中需要注册在同一个命名空间里面
开启Feign熔断需要开启配置,如下:
feign: sentinel: enabled: true
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通