基础
介绍
Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
基本概念
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容
可以理解我们平常的接口就是资源了
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
工作机制
- 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
- 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
- Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。
在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain)
插槽的职责:
- **NodeSelectorSlot **负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级;
- **ClusterBuilderSlot **则用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据;
- **StatisticSlot **则用于记录、统计不同纬度的 runtime 指标监控信息;
- **FlowSlot **则用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制;
- **AuthoritySlot **则根据配置的黑白名单和调用来源信息,来做黑白名单控制;
- **DegradeSlot **则通过统计信息以及预设的规则,来做熔断降级;
- **SystemSlot **则通过系统的状态,例如 load1 等,来控制总的入口流量;
总体框架
控制台
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能
功能
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
安装
1、下载
方式一:公众号获取
关注I am Walker
回复sentinel控制台
即可获取jar包
方式二:github下载
https://github.com/alibaba/Sentinel/releases
2、启动
- 记得需要先安装jdk,至少是8以上
- 进入到该jar包的路径下
java -Dserver.port=9088 -Dcsp.sentinel.dashboard.server=localhost:9088 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar&
这里的端口可以进行更改
启动成功,之后可以访问host:port
默认账号密码都是sentinel
使用场景
账号密码配置
java -Dserver.port=9088 -Dcsp.sentinel.dashboard.server=localhost:9088 -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=123456 -Dserver.servlet.session.timeout=7200 -jar sentinel-dashboard-1.8.6.jar&
- -Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel;
- -Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel;
- -Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;
功能场景
springcloud简单整合,实现流控
前提条件
- 启动dashboard
1、添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2、配置yaml
server:
port: 10111
servlet:
context-path: /order
spring:
application:
name: walker-order
cloud:
sentinel:
transport:
# dashboard的ip和端口
dashboard: localhost:9088
3、调用接口
package com.walker.order.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Map;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/get")
public String get(HttpServletRequest request){
return "you get order";
}
}
调用接口
调用之后,就可以看到出现的服务以及我们刚才调用的接口
4、流控设置
直接模式
- 配置流控设置
我们这里先设置每秒1次,之后点击新增
- 测试
多次访问请求地址,之后可以看见返回Blocked by Sentinel (flow limiting)
翻译:Sentinel堵塞(限流)
可以看到,返回的Status Code是429
关联模式
这个代表,如果关联的接口超过阈值了,那么本接口也会被控制
- 编写/A、/B接口
package com.walker.order.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Map;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/A")
public String A(){
return "A";
}
@GetMapping("/B")
public String B(){
return "B";
}
}
- 访问/A /B接口 显示链路
- 对/test/A 流控设置
这里对/test/B设置单机阈值为1,也就是当/test/B访问的qps=1时,/test/A会被限流
- 测试
先执行/test/B
再执行/test/A
因为没有使用jmeter进行并发测试,所以手速可以快一些
链路模式
只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【API级别的针对来源】
熔断设置
先看一下新增熔断规则的相关字段
熔断策略
主要分为:
- 慢调用比例
- 异常比例
- 异常数
慢调用比例
慢调用比例 (SLOW_REQUEST_RATIO):
选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。
当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。
经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
实践
1、接口编写
@GetMapping("/slow")
public String slow() throws InterruptedException {
Thread.sleep(1000);
return "ok";
}
2、规则设定
规则代表着,统计时长2s内,如果有2个请求数,且有0.5的比例响应时长超过500ms的,则熔断5s
3、测试
第一次调用
再次调用,则被熔断了
异常比例
异常比例 (ERROR_RATIO):
当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
实践
1、controller编写
@GetMapping("/errorPercent")
public String errorPercent(){
int i=1/0;
return "ok";
}
2、熔断规则
代表着2s内如果请求数量大于2条,且有0.1的比例是异常的,那么将熔断5s
3、测试
快速调用2次,都能获取到
调用两次之后,就出现了5s的熔断了
异常数
异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
实践
- 编写接口
package com.walker.order.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Map;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/fusing")
public String fusing(){
// 报错
int a=1/0;
return "fusing";
}
}
- 请求获取链路
- 设置链路规则
熔断策略有3种,这里选择异常数进行测试
- 测试 请求多次
就会出现阻断的信息了
热点key
介绍
首先先看看控制台上的新增热点规则
,下面进行各个字段的介绍
资源:
资源名就是我们的路径了,也可以在代码中使用注解@SentinelResource进行备注
限流方式:这里只支撑QPS
参数索引:代表的是我们接口中使用的参数的下标
例如我们要对下面的接口k1有值的时候进行限流,那么参数索引就填写0,如果对k2进行限制,那么就填1
**单机阈值:**代表的是当QPS达到多少的时候,进行限流
**统计窗口时长:**代表的是链路被限流的时长
实践
1、controller编写
/**
* 热点key
*/
@GetMapping("/hotkey")
@SentinelResource(value = "hotkey",blockHandler = "hotkeyHandler")
public String hotkey(String k1,String k2){
return "hotkey";
}
public String hotkeyHandler(String k1, String k2, BlockException exception){
return "该热点key已经被限流";
}
**hotkeyHandler:**阻断处理器,可以自定义阻断的时候,对链路进行拦截,返回需要的信息,或者进行记录之类的
2、热点规则编写
这里设置了参数0,QPS达到1s请求数=1的时候,进行5s的窗口时长
3、测试
测试k1有值的时候
第一次请求是没有问题的
之后再请求就被限流了
测试k2
发现如何调用都没有影响,因为没有进行限制
自定义流控返回信息
使用@SentinelResource的blockHandler属性,然后编写方法
统一处理异常信息
1、配置BlockExceptionHandler
package com.walker.order.config;
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 com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Component
// 1、实现BlockExceptionHandler
public class MyBlockExceptionHandler implements BlockExceptionHandler {
// 2、重写handle方法
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
String msg="";
if(e instanceof FlowException)
msg="接口限流";
else if(e instanceof DegradeException)
msg="服务降级了";
else if(e instanceof ParamFlowException)
msg="参数限流了";
else if(e instanceof AuthorityException)
msg="权限规则不通过";
else if(e instanceof SystemBlockException)
msg="系统保护";
httpServletResponse.setContentType("application/json;charset=utf-8");
httpServletResponse.getWriter().write(JSON.toJSONString(msg));
}
}
2、测试
设置过程便省略了,这边可以自己配置哈
问题
接口请求之后控制台没有监控数据
原因:
因为我的dashboard是部署在云服务上的,然后我的微服务放在本地,
但是本地和云服务器的网络不同,导致失败
可以查看sentinel-dashboard的日志
打通网络就可以了
参考
https://blog.csdn.net/qq_51409098/article/details/126068253
https://sentinelguard.io/zh-cn/docs/introduction.html