sentinel概述
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性
sentinel的两个部分
核心库(Java 客户端): 不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持
控制台(Dashboard): 基于 Spring Boot 开发,打包后可以直接运行,默认访问端口8080,用户名密码均为sentinel
sentinel项目搭建
环境介绍
我这里的搭建三个服务
cloud-gateway-service 网关服务,集成sentinel,这里转发到cloud-feign-client
cloud-feign-client feign的客户端,在这里将调用cloud-test-service
cloud-test-service 测试服务,主要提供一个controller访问
项目采用nacos作为注册中心
cloud-gateway-service搭建
依赖引入
<dependencies>
<!-- 网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos客户端依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--spring cloud gateway整合sentinel的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!--sentinel的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
项目配置文件
server:
port: 10010
spring:
application:
name: could-gateway-server
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: cloud-feign-client
uri: lb://cloud-feign-client
predicates:
- Path=/test/**
filters:
- StripPrefix=1
discovery:
locator:
enabled: true
sentinel:
transport:
dashboard: 127.0.0.1:8080
cloud-feign-client搭建
此服务中也加入了sentinel流控规则,对服务上的sentinel和gateway上的sentinel之间还是有着不同的
网关上做粗粒度的限流,而服务上能更精细化的限流
加入依赖
<!--sentinel的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
配置文件
spring:
application:
name: cloud-feign-client
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
dashboard: 127.0.0.1:8080
server:
port: 9300
feign:
httpclient:
connection-timeout: 5000
下面的代码块是一个feign调用测试服务的代码
package com.slbuildenv.cloud.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(value="cloud-test-service" )
public interface TestFeign {
@GetMapping("/find/date")
String findDate();
}
package com.slbuildenv.cloud.controller;
import com.slbuildenv.cloud.client.TestFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/feign")
public class TestFeignRemote {
@Autowired
private TestFeign testFeign;
@GetMapping("/date")
public String getRemoteDate() throws InterruptedException {
return testFeign.findDate();
}
}
cloud-test-service搭建
该服务仅仅是提供访问数据,目前不涉及service和mapper,只有一个controller,别忘了注册nacos,这里不列举配置啦
package com.slbuildenv.cloud.controller;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@RestController
@RequestMapping("/find")
@RefreshScope
public class TestFeign {
@GetMapping("/date")
public String getDate(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
}
启动项目
启动三个项目向nacos注册,nacos控制台查看服务注册
需要下载sentinel dashbord 的jar包,由于该死的github太慢啦,我从别人网盘下载的,我这里下载的版本1.8.4 如有需要可以在传送门这里找云盘下载链接
下载完毕,java -jar sentinel-dashbord 1.8.4.jar 即可,访问8080端口登录,用户名密码均为
sentinel
Sentinel的资源定义方式
定义资源
对于资源的定义有两种,一种是硬编码的方式,一种是通过 @SentinelResource 注解的方式,推荐使用注解方式,避免造成业务入侵
硬编码方式
抛出异常的方式定义资源:SphU
Entry entry = null;
try {
// 定义一个sentinel保护的资源,
entry = SphU.entry(resourceName);
// 被保护的业务逻辑
} catch (BlockException e) {
// 如果被保护的资源被限流或者降级了,就会抛出BlockException
log.warn("资源被限流或降级了", e);
} catch (InterruptedException e) {
log.error("发生InterruptedException",e);
} finally {
if (entry != null) {
entry.exit();
}
}
try-with-resources 来定义资源
public static void main(String[] args) {
// 配置规则.
initFlowRules();
// 1.5.0 版本开始可以直接利用 try-with-resources 特性
try (Entry entry = SphU.entry(resourceName)) {
// 被保护的逻辑
System.out.println("hello world");
} catch (BlockException ex) {
// 处理被流控的逻辑
System.out.println("blocked!");
}
}
返回布尔值的方式定义资源 SphO.entry(“资源名”)
// 资源名可使用任意有业务语义的字符串
if (SphO.entry("自定义资源名")) {
// 务必保证finally会被执行
try {
/**
* 被保护的业务逻辑
*/
} finally {
SphO.exit();
}
} else {
// 资源访问阻止,被限流或被降级
// 进行相应的处理操作
}
@SentinelResource注解方式
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "block_testHotKey")
public String testHotKey(@RequestParam(value = "test1")String test1,
@RequestParam(value = "test2")String test2){
return "testHotKey....";
}
value:资源名称,必需项
entryType:entry 类型,可选项(默认为 EntryType.OUT)
blockHandler / blockHandlerClass:blockHandler 指定函数负责处理 BlockException 异常,可选项。blockHandler 函数默认需要和原方法在同一个类中,通过指定 blockHandlerClass 为对应类的 Class 对象,则可以指定其他类中的函数,但注意对应的函数必需为 static 函数,否则无法解析
fallback /fallbackClass:fallback 指定的函数负责处理业务运行的异常,可选项,fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。fallback 函数默认需要和原方法在同一个类中,通过指定 fallbackClass 为对应类的 Class 对象,则可以指定指定为其他类的函数,但注意对应的函数必需为 static 函数,否则无法解析
defaultFallback:默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑。defaultFallback 函数默认需要和原方法在同一个类中,通过指定 fallbackClass 为对应类的 Class 对象,则可以指定指定为其他类的函数,但注意对应的函数必需为 static 函数,否则无法解析
exceptionsToIgnore:用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
Sentinel的规则
流控规则
资源名: 唯一名称,默认请求路径,表示对该资源进行流控
针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)阈值类型/单击阈值:
- QPS(每秒钟的请求数量):当调用该api的QPS达到阈值时,进行限流
- 线程数:当调用该线程数达到阈值的时候,进行限流
是否集群:不需要集群
流控模式:
- 直接: api达到限流条件时,直接限流
- 关联: 当关联的资源达到阈值时,就限流自己
- 链路: 只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
流控效果:
- 快速失败: 直接失败,抛异常
- Warm Up: 根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFctor,经过预热时长,才达到设置的QPS阈值
- 排队等待: 匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效
添加流控为每秒请求数为1的时候进行流控,目前流控效果如下:
http://localhost:9300/feign/date 多次点击触发此效果
降级规则
RT 平均响应时间: 当1s内持续进入5个请求,且对应请求的平均响应时间(秒级)均超过阈值,那么在接下来的时间窗口期内,对该方法的调用都会自动的熔断。
注意Sentinel默认统计的RT上限是4900ms,超出此阈值的都会算作4900ms,若需要更改上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xxx来配置
异常比例: 当资源的每秒请求大于5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,在接下来的时间窗口内,对该方法的调用都会自动的返回。异常的取值在[0.1,1.0]
异常数: 当资源近1分钟的异常数超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若时间小于60s,则结束熔断状态后仍可能再进入熔断状态
热点key规则
sentinel可以根据当前经常被访问的数据,统计其被访问次数,然后进行降级操作,在cloud-feign-client中加入测试热点key的controller
@SentinelResource注解和Hystrix中的@HystrixCommand类似,之前的案例,限流、降级出问题了,都是用的sentinel默认的提示信息,这个注解就是类似hystrix的注解,自定义兜底方法,某个方法出问题,就找对应的兜底方法
value = “testHotKey”:就是该资源的唯一标识,blockHandler = “block_testHotKey”:就是兜底方法
package com.slbuildenv.cloud.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.slbuildenv.cloud.client.TestFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/feign")
public class TestFeignRemote {
@Autowired
private TestFeign testFeign;
@GetMapping("/date")
public String getRemoteDate() throws InterruptedException {
return testFeign.findDate();
}
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "block_testHotKey")
public String testHotKey(@RequestParam(value = "test1")String test1,
@RequestParam(value = "test2")String test2){
return "testHotKey....";
}
public String block_testHotKey(String p1, String p2, BlockException exception){
return "testHotKey被限流了...";
}
}
通过测试得知,我们的第一个参数被降级限流啦
系统规则
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量
系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
Sentinel的规则持久化
将持久化规则放入Nacos中持久化
加入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
加入配置
spring:
cloud:
sentinel:
datasource:
flow:
nacos:
server-addr: localhost:8848 # nacos地址
dataId: orderservice-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow # 还可以是:degrade、authority、param-flow
更加详细配置请参考sentinel规则持久化