SpringCloudAlibaba Sentinel
Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel主要功能:熔断、限流(细粒度的)、监控。信号量限流
Sentinel分为两个部分:
1、核心库(Java客户端)不依赖任何框架/库,能够运行于所有Java运行时环境,同时对Dubbo/Spring Cloud等框架也有较好的支持。
2、控制台(DashBoard)基于SpringBoot开发,打包后可以直接运行。
问题
方法限流的次数是根据什么决定的?答:根据业务逻辑的复杂度:1.IO瓶颈、2.计算的瓶颈。
Sentinel 提供了 @SentinelResource 注解用于定义资源,标识资源是否被限流、降级,并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException等。
注解中的配置项解读:
- value:资源名称,必需项(不能为空)
- entryType:entry 类型,可选项(默认为 EntryType.OUT)
- blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
- fallback / fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore
里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
4.1 返回值类型必须与原函数返回值类型一致;
4.2 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
4.3 fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。- defaultFallback(since 1.6.0)
默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback函数签名要求:exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入fallback 逻辑中,而是会原样抛出。
5.1 返回值类型必须与原函数返回值类型一致;
5.2 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
5.2 defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。 特别地,若 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) 来记录业务异常。- 注意点:
6.1 注解方式埋点不支持 private 方法。
6.2 1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理。
6.3 一般推荐将 @SentinelResource 注解加到服务实现上,而在 Web 层直接使用 Spring Cloud Alibaba 自带的 Web 埋点适配。
java -Dserver.port=8086 -Dcsp.sentinel.dashboard.server=localhost:8086 -jar sentinel-dashboard-1.8.1.jar
新建业务模块business
引入 spring-cloud-starter-alibaba-sentinel 和 spring-cloud-openfeign-core
<parent>
<artifactId>alm-cloudartifactId>
<groupId>com.alm.cloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<groupId>com.alm.cloud.businessgroupId>
<artifactId>alm-businessartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
<version>2021.1version>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-openfeign-coreartifactId>
<version>3.0.1version>
dependency>
dependencies>
project>
server:
port: 9011
spring:
application:
name: alm-business
cloud:
sentinel:
transport:
dashboard: localhost:8080
client-ip: 192.168.1.3 #当前项目地址,如果sentinel服务器地址和项目地址一致可不填写
eager: true
feign:
sentinel:
enabled: true
SentinelResource 注解,标识资源是否被限流、降级。
@RestController
public class UserController {
@Resource UserService userService;
@SentinelResource(value = "/business/getUser", blockHandler="fallback")
@GetMapping(value="/business/getUser")
public Object getUser(Integer userId){
//一、真正的业务逻辑,被保护的资源
if(userId == null){
System.out.println("【熔断降级】 远程服务查询异常 null");
throw new RuntimeException("【熔断降级】 远程服务数据查询异常,或用户信息不存在!");
}
User user = userService.getUser(userId);
System.out.println("Business getUser, uid:" + userId);
return Rsp.end(user);
}
@ResponseBody
public Object fallback(Integer userId, BlockException e){ //BlockException 作为参数必须加上
System.out.println("【服务降级】 fallback...");
return Rsp.end(Result.Err.ERR_SYSTEM_EXCEPTION, "【服务降级】 fallback...");
}
}
public interface UserService {
public User getUser(Integer userId);
}
@Service
public class UserServiceImpl implements UserService{
public User getUser(Integer userId){
//一、真正的业务逻辑,被保护的资源
return new User(20636, "张三", "150xxx");
}
}
错误提示的统一配置
在Sentinel进行流量管理控制中,需要统一处理返回异常信息,在1.8版本官方改成了BlockExceptionHandler这个接口与实现。
@Configuration
public class MySentinelConfig implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception{
// BlockException 异常接口,其子类为Sentinel五种规则异常的实现类
// AuthorityException 授权异常
// DegradeException 降级异常
// FlowException 限流异常
// ParamFlowException 参数限流异常
// SystemBlockException 系统负载异常
String msg = "";
if (e instanceof FlowException) {
msg = "限流了";
}else if (e instanceof DegradeException) {
msg = "降级了";
}else if (e instanceof ParamFlowException) {
msg = "热点参数限流";
}else if (e instanceof SystemBlockException) {
msg = "系统规则(负载/...不满足要求)";
}else if (e instanceof AuthorityException) {
msg = "授权规则不通过";
}
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
String error = JSON.toJSONString(Rsp.end(Result.Err.ERR_FAIL, msg));//响应结构体
response.getWriter().write(error);
}
}
下载并启动应用程序 sentinel-dashboard-1.8.1.jar
添加流控规则
统一配置
限流了:请求多次之后,拦截到FlowException
降级了:出现一次异常,拦截到DegradeException
拦截到接口的自定义fallback 错误,通过自定义 throw new RuntimeException使得系统拦截到
使用 Sentinel 实现降级
https://www.jianshu.com/p/fc903afc81c4
sentinel1.8自定义错误信息
https://blog.csdn.net/lovoo/article/details/119082146
Sentinel限流、降级的统一处理
https://zhuanlan.zhihu.com/p/150058613
制定热点限流规则
https://blog.csdn.net/gloamer/article/details/118858762