目录
一、前言
1、什么是Sentinel?
Sentinel的生态圈
Sentinel 主要特性
2、安装与启动
打开网址:https://github.com/alibaba/Sentinel/releases
找到合适的版本进行下载
下载本地后保存到任意目录(不要中文目录)然后在该目录下打开cmd使用命令打开
windows版本
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.0.jar
linux版本
java -jar sentinel-dashboard-1.8.1.jar
有上图的界面就是已经启动成功了,在浏览器输入 http://localhost:8080/ (注意端口号占用问题,默认的8080与tomcat默认的端口号相同)
账号与密码都是 sentinel
看到这界面就启动成功了
二、SpringBoot整合Sentinel
1、说明
sentinel组件由2部分构成:核心库与控制台
2、将服务注册到Sentinel
pom文件要导入的依赖
<dependencies>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- SpringBoot整合Web组件+actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--日常通用jar包配置-->
<!-- Spring Boot 提供了一组开发工具 spring-boot-devtools 可以提高开发者的工作效率,开发者可以将该模块包含在任何项目中,spring-boot-devtools 最方便的地方莫过于热部署了。-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.6.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
.yaml文件
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
#Nacos服务注册中心地址
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: '*'
主启动类
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class, args);
}
}
业务类FlowLimitController
@RestController
public class FlowLimitController
{
@GetMapping("/testA")
public String testA()
{
return "------testA";
}
@GetMapping("/testB")
public String testB()
{
return "------testB";
}
}
启动我们的项目,访问路径 http://localhost:8401/testA,效果如下
此时服务已经注册进来了
三、功能展示
1、实时监控
同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展示在"实时监控"下。
2、流量控制
什么是QPS?
3、配置流控效果
具体可查看下图
4、降级规则
降级规则就是设置当满足什么条件的时候,对服务进行降级。Sentinel提供了三个衡量条件:
咋在200ms内搞定,搞不定就1秒中内关闭匝道
异常比例:当资源的每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的 时间窗口(以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0]。
在异常比例超过0.2,未来的1秒内不可用
异常数 :当资源近 1 分钟的异常数目超过阈值之后会进行服务降级。注意由于统计时间窗口是分钟级别的,若时间窗口小于 60s,则结束熔断状态后仍可能再进入熔断状态。
在异常数超过5个时,未来的70秒内不可用
5、热点规则
热点参数流控规则是一种更细粒度的流控规则, 它允许将规则具体到参数上。
简单来说就是,参数只要QPS超过每秒n次,马上降级处理
eg:
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
//int age = 10/0;
return "------testHotKey";
}
public String deal_testHotKey(String p1, String p2, BlockException exception) {
return "------deal_testHotKey,o(╥﹏╥)o"; //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
}
访问路径是testHotKey时,如果参数只要QPS超过每秒n次,马上降级处理,调用deal_testHotKey方法。(超过一秒一下就寄了,参数索引就是参数的下标)
将p1去掉,剩下p2,快速访问,http://localhost:8401/testHotKey?p2=1,发现没有作出限制,这是就要配置参数例外项了
当我们p1=5时,就会有问题,http://localhost:8401/testHotKey?p1=5
6、系统规则
属性 | 作用 |
---|---|
value | 资源名称 |
entryType | entry类型,标记流量的方向,取值IN/OUT,默认是OUT |
blockHandler | 处理BlockException的函数名称,函数要求: 1. 必须是 public 2.返回类型 参数与原方法一致 3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 blockHandlerClass ,并指定blockHandlerClass里面的方法。 |
blockHandlerClass | 存放blockHandler的类,对应的处理函数必须static修饰。 |
fallback | 用于在抛出异常的时候提供fallback处理逻辑。fallback函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。函数要求: 1. 返回类型与原方法一致 2. 参数类型需要和原方法相匹配 3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 fallbackClass ,并指定fallbackClass里面的方法。 |
fallbackClass | 存放fallback的类。对应的处理函数必须static修饰。 |
defaultFallback | 用于通用的 fallback 逻辑。默认fallback函数可以针对所有类型的异常进行处理。若同时配置了 fallback 和 defaultFallback,以fallback为准。函数要求: 1. 返回类型与原方法一致 2. 方法参数列表为空,或者有一个 Throwable 类型的参数。 3. 默认需要和原方法在同一个类中。若希望使用其他类的函数,可配置 fallbackClass ,并指定 fallbackClass 里面的方法。 |
exceptionsToIgnore | 指定排除掉哪些异常。排除的异常不会计入异常统计,也不会进入 fallback逻辑,而是原样抛出。 |
exceptionsToTrace | 需要trace的异常 |
在实际开发当中经常出现,服务限流,但是超出规则的默认返回提示,这样不太符合业务逻辑。
所以就有了兜底方法。
注:千万注意,兜底的方法的参数,和原来方法的参数必须一致,并且兜底的方法里面需要增加一个【BlockException exception】参数。定义全局兜底的类,里面写如全局兜底的方法,注意,返回类型,参数,一致,且都需要添加异常类,并且方法的修饰符必须是public
6.1、代码
@GetMapping("/byResource")
@SentinelResource(value = "byResource", blockHandler = "handleException")
public CommonResult byResource() {
return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
}
public CommonResult handleException(BlockException exception) {
return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
}
6.2、效果
sentinel默认的错误信息是:Blocked by Sentinel (flow limiting);如何自定义一个错误信息呢?
6.3、代码
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
// int age = 10/0;
return "------testHotKey";
}
public String deal_testHotKey(String p1, String p2, BlockException exception) {
return "------deal_testHotKey,o(╥﹏╥)o"; //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
}
6.4、添加流控规则
6.5、触发效果
我们将// int age = 10/0; 取消注释跑一下
报错了
7、熔断
直接贴代码
@RestController
@Slf4j
public class CircleBreakerController
{
public static final String SERVICE_URL = "http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
// @SentinelResource(value = "fallback") //没有配置
// @SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
// @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
exceptionsToIgnore = {IllegalArgumentException.class})
public CommonResult<Payment> fallback(@PathVariable Long id)
{
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);
if (id == 4) {
throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
}else if (result.getData() == null) {
throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
//本例是fallback
public CommonResult handlerFallback(@PathVariable Long id,Throwable e) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
//本例是blockHandler
public CommonResult blockHandler(@PathVariable Long id,BlockException blockException) {
Payment payment = new Payment(id,"null");
return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
}
//==================OpenFeign
@Resource
private PaymentService paymentService;
@GetMapping(value = "/consumer/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id)
{
return paymentService.paymentSQL(id);
}
}
id为1看看
我们这里id只有1,2,3数据,其他的都会报错,例如这样的错
用户使用时,肯定不会显示这样的错误信息,但我们配置之后,哪怕出错了,都可以更好的解决
注:fallback只负责业务异常,blockHandler只负责sentinel控制台配置违规
四、规则持久化
1、规则丢失
2、如何做?
然后添加流控规则
重启一下,规则还在,我们的持久化成功了。