Sentinel(哨兵),是为微服务提供流量控制、熔断降级的功能,它和Hystrix提供的功能一样,可以有效的解决微服务调用产生的"雪崩"效应,为微服务系统提供了稳定性的解决方案。随着Hytrxi进入了维护期,不再提供新功能,Sentinel是一个不错的替代方案。通常情况,Hystrix采用线程池对服务的调用进行隔离,Sentinel采用了用户线程对接口进行隔离,二者相比,Hystrxi是服务级别的隔离,Sentinel提供了接口级别的隔离,Sentinel隔离级别更加精细,另外Sentinel直接使用用户线程进行限制,相比Hystrix的线程池隔离,减少了线程切换的开销。另外Sentinel的DashBoard提供了在线更改限流规则的配置,也更加的优化。
哨兵是什么?
-
丰富的应用场景:Sentinel 近 10 年的双十一承接控制了阿里巴巴的大型促销活动,例如秒杀(即瞬间传输容量可以承受的范围)、消息削峰控制填谷、集群、实时熔断中断不能应用等。
-
完整的实时监控系统提供了实时监控的情况。可以在台运行的实时监控设备中监测功能甚至应用程序的 500 台实时监控级别的数据。
-
广泛的开源生态:Sentinel 提供开箱即用的与其他开源框架/的集成模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的集成。库只需要引入相应的依赖并进行简单的配置同时Sentinel提供Java/Go/C++等多种语言的惊艳实现。
-
完善的 SPI 扩展机制:提供简单、易用的 SPI 扩展接口。您可以通过实现扩展接口来快速地自定义。定制规则管理、定制动态数据源等。
Sentinel的主要特性
Sentinel 的开源生态
哨兵分为两个部分:
-
核心库(Java客户端)不依赖任何环境框架,能够运行于所有Java运行时,同时对Dubbo/Spring Cloud等框架也有/的支持。
-
内容(Dashboard)基于Spring Boot直接开发,打包后可以运行,不需要额外的Tomcat等应用。
服务保护的相关概念
服务限流/熔断:在高并发情况下,客户端请求达到了一定的极限,也就是我们所设定的阈值,服务就会自动开启自我保护机制,直接走我们的服务降级fallback方法,给客户端一个友好提示。
服务降级:在高并发情况下,为了防止用户一直等待,给用户一个友好提示。
服务的雪崩效应:默认情况下,tomcat/jetty服务器只有一个线程池去处理用户请求。在高并发情况下,如果客户端的所有请求都堆积在同一个接口上,线程池中的所有线程都用来处理这些请求,就会导致其他接口无法访问。
服务隔离机制:服务隔离机制分为两种:信号量隔离和线程池隔离。信号量隔离:最多只能有一定的阈值的线程数来处理我们的请求,超过阈值就会拒绝请求。线程池隔离:每个服务接口都有独立的线程池来处理请求,接口之间互不影响,缺点:占用CPU资源较大。
Sentinel和Hytrix区别
Sentinel | Hytrix | |
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间或失败比率 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于QPS,支持基于调用关系的限流 | 不支持 |
流量整形 | 支持慢启动、匀速器模式 | 不支持 |
系统负载支持 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架适配 | servlet、spring cloud、Dobbo、gRpc等 | servlet、spring cloud netflix |
sentinel官方中文文档地址
https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
spring cloud sentinel实战
安装sentinel** 控制台**
Sentinel 控制台是流量控制、熔断降级规则统一配置和管理的入口,它为用户提供了机器自发现、簇点链路自发现、监控、规则配置等功能。在 Sentinel 控制台上,我们可以配置规则并实时查看流量控制效果。
sentinel控制台安装可以查看官方文档来,文档地址:
https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard
wget https://github.com/alibaba/Sentinel/releases/download/1.8.3/sentinel-dashboard-1.8.3.jar
java -Dserver.port=8999 -Dcsp.sentinel.dashboard.server=localhost:8999 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
-Dserver.port=8999和localhost:8999端口号要一模一样,localhost:就是服务所在地址用于指定 Sentinel 控制台端口为8080,默认用户名和密码都是sentinel,访问浏览器http://127.0.0.1:8999/
上一篇spring cloud fegin服务调用实战与调优,在nacos-feign模块引入如下依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
在application.yml或bootstrap.yml添加如下配置
spring:
application:
name: nacos-feign
cloud:
nacos:
server-addr: 192.168.1.10:8848
discovery:
namespace: 3dbbf06e-9ab7-49eb-b4ab-3118cfbf9dfd
username: nacos
password: nacos
service: ${spring.application.name}
group: DEFAULT_GROUP
sentinel:
transport:
port: 8719
dashboard: 127.0.0.1:8999
spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了一个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。
spring.cloud.sentinel.transport.dashboard控制台的服务地址
在接口方法添加@SentinelResource注解
package com.lmf.cloud.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.lmf.cloud.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Autowired
TestService testService;
@GetMapping("/test")
//SentinelResource注解用来标识资源是否被限流、降级
@SentinelResource("/test")
public String test(){
String str=testService.test();
return str;
}
}
@SentinelResource注解定义项资源,并提供可选的异常处理和回退配置, 不支持私人方法。
value:资源名称,必须项
entryType:entry 类型,可选项(默认为EntryType.OUT)
blockHandler/blockHandlerClass:blockHandler处理BlockException的函数名称,可选项。blockHandler 函数访问范围是public,返回类型需要与原匹配匹配,参数类型需要和原方法匹配并且最后添加一个额外的参数,类型为BlockException。blockHandler 函数默认需要如果希望使用其他类的函数,则指定blockHandlerClass为对应类的Class对象,否则必须是静态函数,否则无法解析。
fallback/ fallbackClass:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对类型的异常(除了exceptionsToIgnore里面丢弃的异常类型)进行所有处理。fallback 函数签名和要求:
返回值类型与原函数返回值类型必须一致;
方法参数列表需要和原函数一致,或者可以额外使用一个Throwable类型的参数接收多个匹配项。
如果希望使用其他类的函数,则可以指定fallbackClass为类的Class对象,注意函数必须为静态函数,否则无法解析。
属性值:fallback/fallbackClass 使用,业务方面的熔断降级
单个fallback熔断降级处理方法配置
//SentinelResource注解用来标识资源是否被限流、降级
@SentinelResource(value = "test",fallback = "testcallback")
public String test(){
String str=testService.test();
return str;
}
public String testcallback(){
return "这是一个熔断降级的方法";
}
blockHandlerClass限流降级处理类配置
为了提高代码的可读性以及解耦,我们将自定义的熔断降级方法专门写入到一个熔断降级类中,需要时再进行调用。
@GetMapping("/test2")
//SentinelResource注解用来标识资源是否被限流、降级
@SentinelResource(value = "test",fallbackClass = FallBack.class,fallback = "fallback")
public String test2(){
String str=testService.test();
return str;
}
package com.lmf.cloud.fallback;
public class FallBack {
//如果希望使用其他类的函数,则可以指定fallbackClass为类的Class对象,
// 注意函数必须为静态函数,否则无法解析。
public static String fallback(){
return "这是熔断降级方法";
}
}
单个blockHandler限流降级处理方法配置,testblock和testHandler
@GetMapping("/testblock")
//SentinelResource注解用来标识资源是否被限流、降级
@SentinelResource(value = "testblock",blockHandler ="testHandler" )
public String testblock(){
String str=testService.test();
return str;
}
public String testHandler(BlockException ex ){
//todo 做一些日志输出
return "这是限流方法";
}
如果请求超过1QPS就会自动限流
blockHandlerClass限流降级处理类配置
为了提高代码的可读性以及解耦,我们将自定义的限流降级方法专门写入到一个限流降级类中,需要时再进行调用。
@GetMapping("/testblock2")
//SentinelResource注解用来标识资源是否被限流、降级
@SentinelResource(value = "testblock2",blockHandlerClass = BlockHandlers.class,blockHandler = "blockHandler")
public String testblock2(){
String str=testService.test();
return str;
}
package com.lmf.cloud.blockHandlers;
import com.alibaba.csp.sentinel.slots.block.BlockException;
public class BlockHandlers {
public static String blockHandler(BlockException ex){
return "这是限流方法";
}
}