sentinel
一.概述
1.介绍及简介
(1) 官网
官网地址: https://github.com/alibaba/Sentinel
中文文档: https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
spring-alibaba-sentinel 地址:
https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel
(2) sentinel是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
(3) sentinel有什么特点?
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10
年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。 - 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500
台以下规模的集群的汇总运行情况。 - 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC
的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。 - 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI
扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
(4) 解决微服务调用的问题
- 服务降级
当微服务之间调用出现错误,或者超时,则怎么处理结果,保护服务不发生雪崩效应. - 服务熔断
当微服务之间的调用发生的错误次数过多时,为了避免多次的错误调用,提供服务的稳定性,是服务调用发生服务熔断效果,并且在一定的时间窗口期可以重新尝试恢复服务调用. - 服务限流
当高并发,大流量时,保证服务的稳定性,不受大量请求的冲击而采用服务限流策略.
2.下载及安装
sentinel也是采用的server+client模式:
说明:
server端作为服务监控,平台,提供监控功能.
server端作为服务降级,熔断,流控等配置平台,可配置相关信息.
client端连接server端.
(1) 下载
下载地址: https://github.com/alibaba/Sentinel/releases
(2) 解压并运行
(3) 检查是否安装成功
登陆控制台: localhost:8080
登录账号密码均为sentinel
控制台首页:
二.功能演示
1.搭建基础项目
- 建module
略 - 改pom
因为我们本module的设计的注册中心是nacos,所以添加了nacos的依赖和sentinel的依赖
<!--nacos的注册中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--sentinel服务熔断-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- 写yml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos: #nacos的server端地址
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080 #监控面板的server端地址
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
management:
endpoints:
web:
exposure:
include: '*'
- 主启动
没有什么特别的注解代码,并不像hystrix(@EnableHystrix)一样需要添加启动注解
@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class, args);
}
}
- 业务类
添加测试业务类,用于测试sentinel功能
@RestController
public class FlowLimitController
{
@GetMapping("/testA")
public String testA() {
return "------testA";
}
@GetMapping("/testB")
public String testB() {
return "------testB";
}
}
- 测试
(1) 依次启动nacos,sentinel,本module服务
(2) 调用依次本服务的接口
查看sentinel控制台显示如下,则表示监控到了,我们刚刚调用的接口服务.
接下来,结合实际的场景解释每一个功能按钮的作用.
2.流控(流量控制)
流控: 针对访问资源api接口的QPS或者是并发线程数做控制,其实也就是并发数做控制策略.
(1) 添加流控规则
(2) 流控规则介绍
-
1 资源名
表示本规则,针对的资源,也就是限制的资源路劲是哪个. -
2 针对来源
是否是针对特殊来源请求的流控规则 -
3 阈值
流控有两方面,一个是并发数QPS(每秒访问的次数),一个是并发线程数,同一时刻访问本api的线程数. -
4 流控模式
- 直接(默认): 自己的事情,自己负责.
- 关联: 关联的资源达到阈值,则限流自己;常被用来资源限流,如果资源A调用资源B,如果资源B被限流了,则A肯定也无法调用,所以也就限流了A,这就是关联.
- 链路: 多个请求调用了同一个微服务
-
5 流控效果
- 快速失败(默认): 如果本资源达到阈值,流控了,则直接响应失败,抛出异常.异常默认是flow limited.
源码com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController - Warm up: 如果本资源达到阈值,流控了,则进入预热 .
公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值
例如:
- 排队: 匀速排队,阈值必须设置为QPS
- 快速失败(默认): 如果本资源达到阈值,流控了,则直接响应失败,抛出异常.异常默认是flow limited.
3.服务降级
服务降级: 服务降级的意思就是该资源发生错误或者超时等情况的时候,我们怎么处理错误或者超时.
(1) 添加降级规则
(2) 降级规则介绍
- 资源名
配置服务降级的资源api路劲 - 降级策略
什么情况下发生服务降级.-
RT: 平均响应时间
-
异常比例: 当请求达到多少QPS时,如果错误请求的占比达到多少时,发生服务降级
-
异常数: 当请求达到多少QPS时,如果错误请求的数量达到多少时,发生服务降级
-
4.热点规则
热点规则: 这个控制更加的细粒度了,前面的是针对的接口api,这个是针对访问api携带某个或者某些参数值的请求做流控,可以降低热点商品对系统的冲击.
(1) 热点规则测试
- 添加一个测试的业务方法
/**
* 测试热点key
* @param p1 添加了热点规则的参数p1
* @param p2 未添加热点参数规则的p2
* 类似于hystrix的@HystrixCommand
* @SentinelResource
* value: 资源名
* blockHandler: 发生热点.流控等规则的时候回调的方法名
* fallback: 发生超时/异常等时候调用的方法名
*/
@SentinelResource(value = "testHotKey",blockHandler = "deal_hotKey",fallback = "fallback_method")
@GetMapping("/testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2){
log.info("===========testHotKey");
return "===========testHotKey";
}
/**
*这是热点规则之后调用的方法
*/
public String deal_hotKey(String p1, String p2, BlockedException ex){
log.info(ex.getMessage());
return "**************deal_hotKey";
}
/**
* 这是出现runtimeException出现服务降级,调用的方法
* @return
*/
public String fallback_method(){
return "**************fallback_method";
}
- 添加热点规则
- 测试
- http://localhost:8401/testHotKey?p1=abc
带有第一个参数p1的时候,如果请求QPS超过1则被限流 - http://localhost:8401/testHotKey?p1=abc&p2=33
带有第一个参数p1的时候,如果请求QPS超过1则被限流 - http://localhost:8401/testHotKey?p2=abc
不带有第一个参数p1的时候,任意的QPS都不会被限流.
- http://localhost:8401/testHotKey?p1=abc
参数例外项: 表示我们对一个参数进行流控,但是当参数值等于某个数的时候,我们则使用另外的阈值限流.
5.系统规则
(1) 官网地址: https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81
(2) 官网说明
(3) 总之
配置全局QPS
三.@SentinelResource
@SentinelResource注解的属性说明.
代码说明:
RateLimitController.class
@RestController
public class RateLimitController {
/**
* 按照url路劲限流,限流后走系统自带的方法
* @return
*/
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public CommonResult byUrl()
{
return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
}
/**
* 按照资源限流,限流后走我们配置的处理方法
* @return
*/
@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 服务不可用");
}
/**
* 调用全局处理的限流类
* @return
*/
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler", //资源名
blockHandlerClass = CustomerBlockHandler.class, //调用限流类
blockHandler = "handleException2") //调用该类的哪个方法
public CommonResult customerBlockHandler()
{
return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}
}
/**
* @author gl
* @time 2020-06-27 1:06
* @function :全局限流异常处理类
* @step :
*/
public class CustomerBlockHandler {
/**
* BlockException处理方法1
* @param exception
* @return
*/
public static CommonResult handleException(BlockException exception) {
return new CommonResult(2020, "自定义限流处理信息....CustomerBlockHandler");
}
/**
* BlockedException 异常处理方法2
* @param exception
* @return
*/
public static CommonResult handleException2(BlockedException exception)
{
return new CommonResult(2020,"自定义限流处理信息....handlerException2----2");
}
}
四.sentinel整合ribbon+openFeign
1.模块搭建
- 建module
略 - 改pom
添加sentinel依赖
<!--整合feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--整合nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--整合sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- 写yml
注意一定要开启feign对sentinel的支持.
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
service-url:
nacos-user-service: http://nacos-payment-provider
#对Feign的支持
feign:
sentinel:
enabled: true
- 主启动
@SpringBootApplication
@EnableDiscoveryClient //nacos的连接客户端
@EnableFeignClients //openfeign的客户端
public class OrderNacosMain84 {
public static void main(String[] args) {
SpringApplication.run(OrderNacosMain84.class,args);
}
}
- 业务类
(1) restTemplate + ribbon + sentinel的方式
注入RestTemplate类.
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //ribbon的注解
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
业务controller类
/**
* @author gl
* @time 2020-06-27 23:35
* @function : 测试sentinel配合ribbon
* @step :
*/
@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);
}
(2) feign + ribbon + sentinel的方式
feign接口类
@FeignClient(value = "nacos-payment-provider", fallback = PaymentServiceHandler.class)
public interface PaymentService {
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
fallback服务降级类
/**
* @author gl
* @time 2020-06-28 0:05
* @function : fallback服务降级类
* @step :
*/
@Component
public class PaymentServiceHandler implements PaymentService{
@Override
public CommonResult<Payment> paymentSQL(Long id) {
return new CommonResult<>(4444,"服务降级!!");
}
}
五.服务降级/熔断框架比较
六.服务规则持久化
1.是什么?
一旦我们重启应用,Sentinel规则将消失,生产环境需要将配置规则进行持久化
2.怎么玩?
(1) 说明
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel就能从nacos读取配置文件作为规则文件,然后只要刷新8401某个rest地址,就能读取规则文件.
(2) 步骤
- 添加pom依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
- 修改yml
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 #注册到nacos的地址
sentinel:
transport:
dashboard: localhost:8080 #sentinel的dashboard的位置
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
datasource: #sentinel的持久化,默认读取nacos(localhost:8848)中的这个文件(cloudalibaba-sentinel-service),这个文件是json格式的
ds1:
nacos: #sentinel规则持久化到nacos的配置文件信息中
server-addr: localhost:8848 #nacos的地址
dataId: cloudalibaba-sentinel-service #文件名
groupId: DEFAULT_GROUP #分组
data-type: json #数据格式
rule-type: flow
-
在nacos中添加sentinel的持久化文件
-
测试
重启sentinel的微服务该项目,刷新查看是否读取到nacos中的规则文件