目录
概念
Sentinel是阿里开源的一套用于服务容错的解决方案,它以流量为切入点,从流量控制,熔断降级,系统负载保护等多个维度来保护服务的稳定性
特征
-
应用场景多,例如消息削峰,熔断降级等
-
完呗监控控制台
-
和spring、Dubbo很好的整合
核心部分
-
核心库(Java客户端)
-
控制台
使用
1.下载jar包https://github.com/alibaba/Sentinel/releases
2. 导入依赖
<!--sentinel组件--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
3.配置文件application.yml
spring: cloud: sentinel: web-context-unify: false transport: port: 9999 #跟控制台交流的端⼝,随意指定⼀个未使⽤的端⼝即可 dashboard: localhost:8080 # 指定控制台服务的地址
4.在jar包下载位置打开命令行输入以下命令启动控制台
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
5.通过浏览器访问localhost:8080 进⼊控制台 ( 默认⽤户名密码是 sentinel/sentinel ) 注意: 默认是没显示order-service的,需要访问⼏次接⼝,然后再刷新sentinel管控台才可以看到.
规则
流控规则
直连
关联
链路
@Service
@Slf4j
public class TraceServiceImpl {
@SentinelResource(value = "tranceService")
public void tranceService(){
log.info("调⽤tranceService⽅法");
}
}
@RequestMapping("/test")
public String test() throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
traceService.tranceService();
return "测试";
}
@RequestMapping("/test2")
public String test2() {
traceService.tranceService();
return "测试2";
}
流控效果
- 快速失败(默认): 直接失败,抛出异常,不做任何额外的处理,是最简单的效果
- Warm Up:它从开始阈值到最⼤QPS阈值会有⼀个缓冲阶段,⼀开始的阈值是最⼤QPS阈值的 1/3,然后慢慢增⻓,直到最⼤阈值,适⽤于将突然增⼤的流量转换为缓步增⻓的场景。
- 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设 置⼀个超时时间,当请求超过超时间时间还未处理,则会被丢弃。
熔断降级规则
慢调用比列
1. 在shop-order-server项⽬中新增FallBackController.java类,代码如下:
@RequestMapping("/test")
public String test() throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
return "测试";
}
2. 新增降级规则: 上⾯配置表示,如果在1S之内,有【超过1个的请求】且这些请求中【响应时间>最⼤RT】的【请求 数量⽐例>10%】,就会触发熔断,在接下来的10s之内都不会调用真实方法,直接⾛降级⽅法。
比如: 最⼤RT=900,⽐例阈值=0.1,熔断时⻓=10,最小请求数=10
- 情况1: 1秒内的有20个请求,只有10个请求响应时间>900ms, 那慢调⽤⽐例=0.5,这种情况 就会触发熔断
- 情况2: 1秒内的有20个请求,只有1个请求响应时间>900ms, 那慢调⽤⽐例=0.05,这种情况 不会触发熔断
- 情况3: 1秒内的有8个请求,只有6个请求响应时间>900ms, 那慢调⽤⽐例=0.75,这种情况不 会触发熔断,因为最⼩请求数这个条件没有满⾜. 注意: 我们做实验的时候把最⼩请求数设置为1,因为在1秒内,⼿动操作很难在1s内发两个请求过 去,所以要做出效果,最好把最⼩请求数设置为1。
异常比列
异常数
热点规则
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最⾼的 Top K 数 据,并对其访问进⾏限制。⽐如:
- 商品 ID 为参数,统计⼀段时间内最常购买的商品 ID 并进⾏限制
- ⽤户 ID 为参数,针对⼀段时间内频繁访问的⽤户 ID 进⾏限制
热点参数限流会统计传⼊参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调 ⽤进⾏限流。热点参数限流可以看做是⼀种特殊的流量控制,仅对包含热点参数的资源调⽤⽣效。
@RequestMapping("/test3/{pid}")
@SentinelResource("hotSpot")
public String test3(@PathVariable("pid") Long pid) {
return "测试3";
}
授权规则
自定义异常返回
- FlowException 限流异常
- DegradeException 降级异常
- ParamFlowException 参数限流异常
- AuthorityException 授权异常
- SystemBlockException 系统负载异常
@Component
public class ExceptionHandlerPage implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse response, BlockException e) throws Exception {
response.setContentType("application/json;charset=utf-8");
ResultData data = null;
if (e instanceof FlowException) {
data = new ResultData(-1, "接⼝被限流了");
} else if (e instanceof DegradeException) {
data = new ResultData(-2, "接⼝被降级了");
}else if (e instanceof ParamFlowException) {
data = new ResultData(-3, "参数限流异常");
}else if (e instanceof AuthorityException) {
data = new ResultData(-4, "授权异常");
}else if (e instanceof SystemBlockException) {
data = new ResultData(-5, "接⼝被降级了...");
}
response.getWriter().write(JSON.toJSONString(data));
}
@Data
@AllArgsConstructor//全参构造
@NoArgsConstructor
//⽆参构造
class ResultData {
private int code;
private String message;
}
}
特殊异常输出
@RestController
@Slf4j
public class AnnoController {
@RequestMapping("/anno1")
@SentinelResource(value = "anno1",
blockHandler="anno1BlockHandler",
fallback = "anno1Fallback"
)
public String anno1(String name){
if("wolfcode".equals(name)){
throw new RuntimeException();
}
return "anno1";
}
public String anno1BlockHandler(String name,BlockException ex){
log.error("{}", ex);
return "接⼝被限流或者降级了";
}
//Throwable时进⼊的⽅法
public String anno1Fallback(String name,Throwable throwable) {
log.error("{}", throwable);
return "接⼝发⽣异常了";
}
}
Sential应用场景
当产品服务不可用时,给订单服务提供一个兜底的产品数据,以防止服务报错
1.添加配置
feign: sentinel: enabled: true
2.实现fegin接口
@Component
public class ProductFeignFallBack implements FeignApi {
@Override
public Product findByPid(Long pid) {
System.out.println("返回兜底数据");
return new Product();
}
}
3.使用fallback指定需要返回的兜底数据
@FeignClient(value = "product-service",fallback = ProductFeignFallBack.class)
public interface FeignApi {
@RequestMapping("/product/{pid}")
Product findByPid(@PathVariable("pid") Long pid);
}