在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
标签:name,流控,spring,nacos,sentinel,Sentinel,id,Springboot
From: https://www.cnblogs.com/zhaodalei/p/16647683.html