Sentinel目录
Sentinel
Alibaba出品的面向分布式服务架构的轻量级流量控制组件。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
流量控制:
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。例如有时候系统会在某一瞬间接收到大量的请求,并且超过了系统的处理能力,但这个瞬间过后请求量就从峰顶跌入到谷底。此时就可以通过Sentinel 来对这请求流量进行控制。
熔断降级:
除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。
如上图,Service D出现了某些问题,例如请求响应时间长或异常比例升高,为了避免影响到其它的资源而导致级联故障,对这个资源的调用进行限制,让请求快速失败。
流量控制
原理是监控应用流量的QPS或并发线程数等指标,当达到阈值时对流量进行控制,以免服务被瞬间的流量高峰冲垮,从而保障应用的高可用性。
流量控制的两种方式:
- 并发线程数
- QPS
限流规则的组成:
resource:规则作用的对象
count:限流阈值
grade:限流类型(QPS或并发线程数)
limiApp:针对调用来源
strategey:调用关系限流策略
controlBehavior:限流方式(直接拒绝、匀速排队、warm up)
- 直接拒绝:当达到阈值时,新的请求会被立即拒绝,拒绝方式为抛出FlowException。
- 匀速排队:让请求以均匀的速度通过。对应的是漏桶算法。
- warm up:预热/冷启动方式。当流量瞬间增加时,直接将系统拉升到高水位可能会将系统压垮。通过冷启动,让通过的流量缓慢增加,直到达到阈值。
Sentinel初体验
- Sentinel 多样化的限流手段
- 如何所见即所得的配置规则
- 如何有效地使用 Sentinel 的监控数据
- 如何通过机器上报来管理机器
步骤:
-
下载公网demo:https://ahasoss-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/sdk/latest/ahas-sentinel-sdk-demo.jar
-
注册aliyun账户,开启到阿里云控制台开通 AHAS 功能。
-
启动公网demo
java -Dahas.namespace=default -Dproject.name=MyDemo -Dahas.license=53774c5320d9438cb31e5194aa4629a3 -jar ahas-sentinel-sdk-demo.jar
-
当应用开始运行后一段时间,我们刷新一下控制台页面,就可以在 AHAS Sentinel 控制台上看到我们的应用了:
本地应用整合sentinel
本地应用入门
构建本地应用
-
创建一个springBoot的基础工程,导入sentinel需要的依赖。
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.7.2</version> </dependency>
-
编写controller,定义熔断降级规则,并在测试方法使用。
@RestController public class HelloController { @GetMapping("hello") public String hello(){ //使用 Sentinel API,使用限流规则 try{ SphU.entry("HelloWorld"); return "hello Sentinel"; } catch (BlockException e) { e.printStackTrace(); return "系统繁忙"; } } /** * 指定熔断降级规则 */ @PostConstruct //在紧随构造方法之后执行 public void initFlowRule(){ //1.创建容器,用于存放规则 List<FlowRule> rules=new ArrayList<>(); //2.创建规则并指定规则细节 FlowRule rule=new FlowRule(); rule.setResource("HelloWorld"); //设置资源 rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //设置限流规则类型,FLOW_GRADE_QPS:QPS。QPS:表示每秒查询数 rule.setCount(2); //设置QPS上限 //3.将规则存入容器 rules.add(rule); //4.加载规则 FlowRuleManager.loadRules(rules); } }
-
测试:当访问每秒超过两次时:
构建本地应用控制台
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。另外,鉴权在生产环境中也必不可少。
功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
步骤:
-
下载senyinel控制台jar包:https://github.com/alibaba/Sentinel/releases
-
使用如下命令启动控制台
java -Dserver.port=9090 -Dcsp.sentinel.dashboard.server=localhost:9090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.2.jar
-Dserver.port=9090 控制台端口号
-Dcsp.sentinel.dashboard.server=localhost:9090 向控制台发送心跳包的控制台地址
-Dproject.name 指定控制台名称
-
通过浏览器访问:http://localhost:9090/
默认用户名和密码都是 sentinel
本地应用接入本地控制台
-
本地应用导入依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>1.7.2</version> </dependency>
-
设置本地应用启动参数,并重启
-Dcsp.sentinel.dashboard.server=127.0.0.1:9090 设置sentinel控制台的主机地址和端口 -Dproject.name=hello 设置本地应用在Sentinel控制台中的名称
-
此时再访问自定义的本地应用资源,则可以再sentinel进行监控
定义限流规则方式
- 直接定义一个方法
- 控制台页面定义
控制台定义限流规则
之前的规则由于硬编码进程序中了,如果更改规则,则会比较麻烦。因此可以通过控制台页面来定义限流规则。
-
controller层:将定义规则部分除去
@RestController public class HelloController { @GetMapping("hello") public String hello(){ //使用 Sentinel API,使用限流规则 try(Entry entry = SphU.entry("HelloWorld")){ return "hello Sentinel"; } catch (BlockException e) { e.printStackTrace(); return "系统繁忙"; } } }
-
再控制台页面-流控规则-新增
-
测试:在1秒内多测访问资源,成功生效。
定义资源方式
- 抛出异常的方式定义资源
- 返回布尔值
- 异步调用
- 注解
- 主流框架默认适配
抛出异常
本地应用入门案例
返回布尔值
@GetMapping("if")
public String ifHello() {
//使用 Sentinel API,使用限流规则
if (SphO.entry("ifHello")) {
try {
return "ifHello Sentinel";
} finally {
SphO.exit();
}
} else {
return "系统繁忙";
}
}
注意:返回布尔值定义资源所使用的sentinel API与抛出异常方式所使用的API不同。
返回布尔值:SphO
抛出异常:SphU注意:**SphO.entry()和SphO.exit()**必须成双成对出现。
测试:定义流控规则后测试
异步调用
-
在启动类上添加**@EnableAsync**表示springboot支持异步调用。
-
创建AsyncService编写异步方法
方法添加**@Async**表示该方法是一个异步方法@Service public class AsyncService { @Async public void asyncTest(){ System.out.println("异步方法开始-----"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("异步方法结束====="); } }
-
编写controller层,使用senyinel的API。**SphU.asyncEntry()**作为限流入口,exit()作为限流出口。
@RestController public class HelloController { @Autowired private AsyncService asyncService; @GetMapping("async") public void asyncHello() { //使用 Sentinel API,使用限流规则 AsyncEntry asyncEntry = null; try { asyncEntry = SphU.asyncEntry("asyncHello"); //限流入口 asyncService.asyncTest(); } catch (BlockException e) { System.out.println("系统繁忙"); } finally { if (asyncEntry != null) { //限流出口 asyncEntry.exit(); } } } }
-
测试:定义流控规则进行测试
注解
通过@SentinelResource定义注解资源,并配置blockHandler函数来进行限流之后的处理。
-
由于sentinel使用Aspectj的拓展自动定义资源,处理BlockException。所以需要引入依赖
<!--sentinel注解定义资源依赖--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> <version>1.7.2</version> </dependency>
-
定义Aspectj的配置类
@Configuration public class SentinelAspectConfig { @Bean public SentinelResourceAspect sentinelResourceAspect(){ return new SentinelResourceAspect(); } }
-
编写controller,并编写handle方法。
@RestController public class AnnoController { @GetMapping("annoTest") @SentinelResource(value = "annoTest",blockHandler = "exceptionHandle") public String annoTest(){ return "sentinel注解测试"; } public String exceptionHandle(BlockException e){ e.printStackTrace(); return "系统繁忙"; } }
-
测试:定义控流规则后测试
Sentinel整合Springcloud
Spring Cloud Alibaba 默认为 Sentinel 整合了 Servlet、RestTemplate、FeignClient 和 Spring WebFlux。Sentinel 在 Spring Cloud 生态中,不仅补全了 Hystrix 在 Servlet 和 RestTemplate 这一块的空白,而且还完全兼容了 Hystrix 在 FeignClient 中限流降级的用法,并且支持运行时灵活地配置和调整限流降级规则。
Sentinel整合Springcloud入门
-
创建一个springboot工程,并导入依赖spring-cloud-starter-alibaba-sentinel
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.1.0.RELEASE</version> </dependency>
-
项目中创建controller,定义资源以及blockhandler函数。
@RestController public class TestController { @GetMapping("test") @SentinelResource(value = "sentinelTest",blockHandler = "blockExceptionHandler") public String test(){ return "sentinel整合springCloud"; } public String blockExceptionHandler(BlockException e){ e.printStackTrace(); return "系统繁忙,请稍后"; } }
-
在配置文件中定义sentinel控制台的地址和本地应用的名称。
spring.application.name=springCloudSentinel spring.cloud.sentinel.transport.dashboard=localhost:9090
-
启动,在控制台页面添加流控规则测试。
成功
sentinel整合feign
该操作只需要在上个案例(Sentinel整合Springcloud)的基础上做两步即可
-
配置文件打开sentinel对feign的支持
feign.sentinel.enabled=true
-
加入spring-cloud-starter-openfeign依赖,使sentinel starter自动化配置类生效。
案例:创建两个微服务,sentinel_feign_consumer微服务通过feign访问sentinel_feign_provider微服务。
步骤:
-
创建一个父工程,并导入spring-boot、spring-cloud、spring-cloud-alibaba的依赖。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>sentinelparent</artifactId> <version>0.0.1-SNAPSHOT</version> <modules> <module>sentinel_feign_provider</module> <module>sentinel_feign_consumer</module> </modules> <name>sentinelparent</name> <packaging>pom</packaging> <description>Demo project for Spring Boot</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencyManagement> <dependencies> <!--spring-cloud-alibaba的依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring-cloud的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!--spring-boot的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
创建子工程sentinel_feign_provider作为服务的生产者。
-
导入依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>sentinelparent</artifactId> <groupId>com.itheima</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>sentinel_feign_provider</artifactId> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> </project>
-
配置文件:配置nacos的配置,以及sentinel配置,开启对fen的支持
server: port: 8081 #配置端口号 spring: application: name: sentinalfeignpro #配置本地应用名称 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 #配置地址值 namespace: 766053ac-4a74-41c8-a0ae-e981dad0b86d #命名空间:dev sentinel: transport: dashboard: localhost:9090 #配置sentinel地址 feign: sentinel: enabled: true #开启sentinel对enable的支持
-
编写controller
@RestController public class ProviderController { private static final Logger logger= LoggerFactory.getLogger(ProviderController.class); @GetMapping("sentinelFeignTest") public String sentinelFeignTest(){ logger.info("服务生产方被调用"); return "服务生产者被调用"; } }
-
-
创建子工程sentinel_feign_consumer作为服务消费方。细节与生产方大致相同。
-
配置文件端口不同。
-
编写fegin客户端,指定要调用的服务名称以及流控降级的回调类。
@FeignClient(value = "sentinalfeignpro",fallback = FallbackService.class) public interface SentinelFeignProviderClient { @GetMapping("sentinelFeignTest") public String sentinelFeignTest(); }
-
编写流控降级的回调类。
@Component public class FallbackService implements SentinelFeignProviderClient { public String sentinelFeignTest() { return "服务器繁忙,稍后再试"; } }
-
编写controler层,在controller层调用服务生产者。
@RestController public class ConsumerController { @Autowired private SentinelFeignProviderClient sentinelFeignProviderClient; @GetMapping("test") public String test(){ return sentinelFeignProviderClient.sentinelFeignTest(); } }
-
-
将消费方与生产方启动
-
nacos控制台
服务生产方与服务消费方都被注册进nacos中了
-
sentinel控制台
两个服务也都连接到sentinel控制台中去了
-
-
在sentinel控制台中设置服务方的流控规则
资源命名规则:请求方式:请求协议://服务名/请求路径及参数
GET:http://sentinalfeignpro/sentinelFeignTest -
测试:频繁的访问服务消费者,成功
熔断降级
由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。为了避免影响到其它的资源而导致级联故障,对这个资源的调用进行限制,让请求快速失败。当资源被降级之后,在接下来的一段时间内,对该资源的调用都自动熔断。
属性详解
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即限流规则作用的对象 | |
count | 阈值 | |
timeWindow | 降级时间,在此时间内对资源的调用都会被熔断 | |
grade | 熔断策略 秒级RT:平均响应时间(DEGRADE_GRADE_RT),当一秒内有N个请求,如果平均响应时间超过阈值,就会熔断 秒级异常比例:在一秒内异常的总数超过阈值就熔断,异常比例阈值范围[0.0,1.0]。 分钟级异常数:在一分钟内异常数超过阈值,则熔断。 | 秒级RT |
rtSlowRequestAmount | 在秒级RT模式下,连续多少个请求的平均RT超过阈值则熔断。(1.7.0引入) | 5 |
minRequestAmount | 每分钟异常出现的次数如果小于该指定数,则哪怕超过异常比例也不熔断。 | 5 |
**项目演示:**在sentinel整合feign项目的基础上进行演示。
-
在消费方编写一个新的controller
@RestController public class FusingController { @SentinelResource(value = "degrade_Rule",blockHandler = "blockExceptionHandler") @GetMapping("degradeTest") public String degradeTest(){ return "测试熔断"; } public String blockExceptionHandler(BlockException e){ e.printStackTrace(); return "系统繁忙"; } //定义熔断规则 @PostConstruct private void initDegradeRule(){ //1.创建存放规则的容器 List<DegradeRule> rules=new ArrayList<DegradeRule>(); //2.创建规则并制定细节 DegradeRule rule=new DegradeRule(); rule.setResource("degrade_Rule"); rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); //定义熔断类型 rule.setTimeWindow(10); //设置降级时间为10秒 //3.将规则存放入容器 rules.add(rule); //4.加载规则 DegradeRuleManager.loadRules(rules); } }
-
为该controller的方法资源添加控流规则,每秒访问不超过2个。
-
在一秒内连续访问资源超2次,如果接下来在10秒内都无法访问资源,则说明熔断成功。
熔断降级规则也可以在sentinel控制台页面进行定义
降级规则-新增降级规则