12.springCloud AlibabaSentinel实现熔断与限流

news2025/6/6 0:48:50

目录

一、Sentinel简介

1.官网

2.Sentinel 是什么

3.Sentinel 的历史

4.Sentinel 基本概念

资源

规则

5.Sentinel 功能和设计理念

(1).流量控制

什么是流量控制

流量控制设计理念

(2).断降级

什么是熔断降级

熔断降级设计理念

(3).系统自适应保护

6.主要工作机制

7.流控降级与容错标准

8.下载地址:

9.Sentinel的特征

10.Sentinel的主要特性

11.面试题

讲讲什么是缓存穿透?击穿?雪崩?如何解决?

1、缓存穿透:

2、缓存雪崩:

3、缓存击穿:

服务雪崩

服务降级

服务熔断

服务限流

服务隔离

服务超时 

二、安装Sentinel

组成

安装步骤

1.下载

2.运行命令

3.访问sentinel管理界面

三、微服务8401整合Sentinel入门案例

1.启动Nacos8848

2.启动Sentinel8080

3.新建微服务8401

(1).新创建子模块 cloudalibaba-sentinel-service8401

(2).添加pom依赖

(3).YML参数配置

(4).主启动类

(5).业务类FlowLimitController

4.启动8401微服务后查看sentienl控制台

四、流控规则

1.基本介绍

2.流控模式

(1).直接

(2).关联

(3).链路 

3.流控效果

1. 直接 - 快速失败(默认的流控处理)

2 预热WarmUp

(1).限流 冷启动

(2).公式

(3).官网及源码

(4).官网WarmUp配置

(5).官网测试:

(6).官网应用场景:

3 排队等待

(1).解释

(2).修改FlowLimitController

(3).sentinel配置

(4).测试效果:

4.流控效果V2(并发线程数)

(1).sentinel配置

(2).Jmeter模拟多个线程并发+循环请求

(3).测试:

五、熔断规则

基本介绍

熔断策略

新增熔断规则实战

1. 慢调用比例

(1).解释

(2).名词解释

(3).触发条件+熔断状态

(4).测试示例

1).代码

2).配置

3).jmeter压测

4).结论 

2. 异常比例

(1).解释

(2).测试示例

1).代码

2).配置

3).jemeter压测

4).结论

3.异常数

(1).解释

(2).测试示例

(1).代码

(2).配置

(3).jemeter压测

(4).结论

 六、@SentinelResource注解

1.简介

2.源码说明

3.启动Nacos成功

4.启动Sentinel成功

5.按照rest地址限流+默认限流返回

(1).业务类RateLimitController

(2).Sentinel控制台配置

(3).测试

6.按SentinelResource资源名称限流+自定义限流返回

(1).微服务cloudalibaba-sentinel-service8401

(2).测试地址

(3).配置流控规则:

7.按SentinelResource资源名称限流+自定义限流返回+服务器降级处理

(1).微服务cloudalibaba-sentinel-service8401

(2).配置流控规则

(3).测试

七、热点规则

1.基本介绍

2.官网:

3.代码

4.配置 

5.测试

6.参数例外项

特例情况

配置

测试

前提条件

八、授权规则

1.简介

2.官网

3.黑白名单示例

4.配置

5.测试

九、规则持久化

1.简介

Sentiel规则持久化三种模式分析

原始模式

Pull 模式

Push模式

自定义持久化

2.规则的种类

流量控制规则 (FlowRule)

熔断降级规则 (DegradeRule)

系统保护规则 (SystemRule)

访问控制规则 (AuthorityRule)

热点参数规则(ParamFlowRule)

3.配置持久化主要有以下原因:

4.单一持久化示例:

1).POM添加Nacos

2).YML参数配置

3).添加Nacos数据源配置

4).源代码

5).添加Nacos业务规则配置

6).重新启动8401再看sentine

5.全面持久化示例:

1).在Nacos中配置sentinel信息

2).配置信息

2.1 流控配置

2.2 熔断降级配置

2.3 热点参数配置

2.4 系统规则配置

2.5 授权规则配置

十、OpenFeign和Sentinel集成实现fallback服务降级

1.需求说明

2.程序解耦

前述参考

本例说明

3.编码步骤

(1).修改服务器提供方cloudalibaba-provider-payment9001

1).添加POM依赖

2).修改YML

3).主启动类

4).编写业务类

5).启动9001微服务自测一下

(2).修改cloud-api-commons

1).添加POM依赖

2).新增openFeign对外暴露接口

3).为新增远程调用新建全局统一服务降级类

(3).修改cloudalibaba-consumer-nacos-order84

1).添加POM依赖

2).YML参数配置

3).主启动类

4).业务类

(4).测试验证

1).9001正常启动后,再启动84通过feign调用

2).Sentinel流控为例,进行配置

3).9001宕机了,83通过feign调用

十一、GateWay和Sentinel集成实现服务限流

1.需求说明

2.启动nacos服务器8848

3.启动sentienl服务器8080

4.步骤

5.测试


一、Sentinel简介

面向分布式、多语言异构化服务架构的 流量治理组件

1.官网

官网地址: home | Sentinel
gitHub源码地址: GitHub - alibaba/Sentinel: A powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件)
中文指南: 主页 · alibaba/Sentinel Wiki · GitHub
等价对标Spring Cloud Circuit Breaker

2.Sentinel 是什么

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从 流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

3.Sentinel 的历史

  • 2012 年,Sentinel 诞生,主要功能为入口流量控制。
  • 2013-2017 年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。
  • 2018 年,Sentinel 开源,并持续演进。
  • 2019 年,Sentinel 朝着多语言扩展的方向不断探索,推出 C++ 原生版本,同时针对 Service Mesh 场景也推出了 Envoy 集群流量控制支持
  • 2020 年,推出 Sentinel Go 版本
  • 2021 年,Sentinel 正在朝着 2.0 云原生高可用决策中心组件进行演进;同时推出了 Sentinel Rust 原生版本
  • 2022 年,Sentinel 品牌升级为流量治理,领域涵盖流量路由/调度、流量染色、流控降级、过载保护/实例摘除等;同时社区将流量治理相关标准抽出到 OpenSergo 标准

4.Sentinel 基本概念

资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

5.Sentinel 功能和设计理念

(1).流量控制
什么是流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示
流量控制设计理念
流量控制有以下几个角度:
  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
(2).断降级
什么是熔断降级
除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。
Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
熔断降级设计理念
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。
Hystrix 通过  线程池隔离 的方式,来对依赖(在 Sentinel 的概念中对应  资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。
Sentinel 对这个问题采取了两种手段:
  • 通过并发线程数进行限制
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
  • 通过响应时间对资源进行降级
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
(3).系统自适应保护
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

6.主要工作机制

Sentinel 的主要工作机制如下:
  • 对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
  • 根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel 提供开放的接口,方便您定义及改变规则。
  • Sentinel 提供实时的监控系统,方便您快速了解目前系统的状态。

7.流控降级与容错标准

Sentinel 社区正在将流量治理相关标准抽出到  OpenSergo 标准中,Sentinel 作为流量治理标准实现。有关 Sentinel 流控降级与容错 spec 的最新进展,请参考  opensergo-specification,也欢迎社区一起来完善标准与实现。

8.下载地址:

Releases · alibaba/Sentinel · GitHub

9.Sentinel的特征

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
  • 完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

10.Sentinel的主要特性

从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

11.面试题

讲讲什么是缓存穿透?击穿?雪崩?如何解决?
详细视频地址: 123_redis高级篇之缓存预热雪崩穿透击穿面试题简介_哔哩哔哩_bilibili
1、缓存穿透:
是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。
2、缓存雪崩:
我们可以简单的理解为:由于原有缓存失效,新缓存未到 时间  (例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。
3、缓存击穿:
某个 key 非常非常热,访问非常的频繁,高并发访问的情况下,当这个 key在失效(可能expire过期了,也可能LRU淘汰了)的瞬间,大量的请求进来,这时候就击穿了缓存,直接请求到了数据库,一下子来这么多,数据库肯定受不了,这就叫缓存击穿。某个key突然失效,然后这时候高并发来访问这个key,结果缓存里没有,都跑到db了。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
所以, 通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。
服务降级
服务降级,说白了就是一种服务托底方案,如果服务无法完成正常的调用流程,就使用默认的托底方案来返回数据。
例如,在商品详情页一般都会展示商品的介绍信息,一旦商品详情页系统出现故障无法调用时,会直接获取缓存中的商品介绍信息返回给前端页面。
服务熔断
在分布式与微服务系统中,如果下游服务因为访问压力过大导致响应很慢或者一直调用失败时,上游服务为了保证系统的整体可用性,会暂时断开与下游服务的调用连接。这种方式就是熔断。 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。 
服务熔断一般情况下会有三种状态:闭合、开启和半熔断;
  • 闭合状态(保险丝闭合通电OK):服务一切正常,没有故障时,上游服务调用下游服务时,不会有任何限制。 
  • 开启状态(保险丝断开通电Error):上游服务不再调用下游服务的接口,会直接返回上游服务中预定的方法。 
  • 半熔断状态:处于开启状态时,上游服务会根据一定的规则,尝试恢复对下游服务的调用。此时,上游服务会以有限的流量来调用下游服务,同时,会监控调用的成功率。如果成功率达到预期,则进入关闭状态。如果未达到预期,会重新进入开启状态。
服务限流
服务限流就是限制进入系统的流量,以防止进入系统的流量过大而压垮系统。其主要的作用就是保护服务节点或者集群后面的数据节点,防止瞬时流量过大使服务和数据崩溃(如前端缓存大量实效),造成不可用;还可用于平滑请求, 类似秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行。 
限流算法有两种,一种就是简单的请求总量计数,一种就是时间窗口限流(一般为1s),如令牌桶算法和漏牌桶算法就是时间窗口的限流算法。 
服务隔离
有点类似于系统的垂直拆分,就按照一定的规则将系统划分成多个服务模块,并且每个服务模块之间是互相独立的,不会存在强依赖的关系。如果某个拆分后的服务发生故障后,能够将故障产生的影响限制在某个具体的服务内,不会向其他服务扩散,自然也就不会对整体服务产生致命的影响。 
互联网行业常用的服务隔离方式有:线程池隔离和信号量隔离。
服务超时 
整个系统采用分布式和微服务架构后,系统被拆分成一个个小服务,就会存在服务与服务之间互相调用的现象,从而形成一个个调用链。
形成调用链关系的两个服务中,主动调用其他服务接口的服务处于调用链的上游,提供接口供其他服务调用的服务处于调用链的下游。服务超时就是在上游服务调用下游服务时, 设置一个最大响应时间,如果超过这个最大响应时间下游服务还未返回结果,则断开上游服务与下游服务之间的请求连接,释放资源。 

二、安装Sentinel

组成

Sentinel 分为两个部分:
  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
Sentinel 社区官方网站: https://sentinelguard.io/
Sentinel介绍网址: 介绍 · alibaba/Sentinel Wiki · GitHub
sentinel启动后各端口:
  • 后台8719默认
  • 前台8080开启

安装步骤

1.下载
Releases · alibaba/Sentinel · GitHub
sentinel-dashboard-1.8.6.jar
2.运行命令
前提
  • java环境已安装(jdk17已安装)
  • 8080端口不能被占用
命令
java -jar sentinel-dashboard-1.8.6.jar
3.访问sentinel管理界面
  • 登录账号密码均为sentinel
  • 访问地址:http://localhost:8080

三、微服务8401整合Sentinel入门案例

1.启动Nacos8848

startup.cmd -m standalone
访问地址: http://localhost:8848/nacos

2.启动Sentinel8080

java -jar sentinel-dashboard-1.8.6.jar
访问地址: http://localhost:8080

3.新建微服务8401

(1).新创建子模块 cloudalibaba-sentinel-service8401
将被哨兵纳入管控的8401微服务提供者
(2).添加pom依赖
springboot通用依赖、自己定义的api通用包、常用工具依赖、以及sentinel、nacos依赖,需要先注册服务器,才能进行限流操作。
 <!--SpringCloud alibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
       
 <dependencies>
        <!--SpringCloud alibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.atguigu.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--SpringBoot通用依赖模块-->
        <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>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <scope>provided</scope>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
(3).YML参数配置
server:
  port: 8401

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扫描,直至找到未被占用的端口
(4).主启动类
启动类添加@S pringBootApplication注解- springboot常用注解,以及 @EnableDiscoveryClient服务器注册与发现
package com.atguigu.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Main8401 {
    public static void main(String[] args) {
        SpringApplication.run(Main8401.class,args);
    }
}
(5).业务类FlowLimitController
package com.atguigu.cloud.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FlowLimitController {
    
    @GetMapping("/testA")
    public String testA(){
        return "-----testA";
    }
    @GetMapping("/testB")
    public String testB(){
        return "-----testB";
    }
}

4.启动8401微服务后查看sentienl控制台

Sentinel采用的懒加载说明
注意:想使用Sentinel对某个接口进行限流和降级操作,一定要先访问下接口,是Sentinel检测相应的接口。
执行一次访问即可:
  • http://localhost:8401/testA
  • http://localhost:8401/testB
效果:

四、流控规则

1.基本介绍

Sentinel能够对流量进行控制,主要是监控应用的QPS流量或者并发线程数等指标,如果达到指定的阈值时,就会被流量进行控制,以避免服务被瞬时的高并发流量击垮,保证服务的高可靠性。参数见最下方:
1资源名
资源的唯一名称,默认就是请求的接口路径,可以自行修改,但是要保证唯一。
2针对来源
具体针对某个微服务进行限流,默认值为default,表示不区分来源,全部限流。
3阈值类型
QPS表示通过QPS进行限流,并发线程数表示通过并发线程数限流。
4单机阈值
与阈值类型组合使用。如果阈值类型选择的是QPS,表示当调用接口的QPS达到阈值时,进行限流操作。如果阈值类型选择的是并发线程数,则表示当调用接口的并发线程数达到阈值时,进行限流操作。
5是否集群
选中则表示集群环境,不选中则表示非集群环境。

2.流控模式

  • 直接
  • 关联
  • 链路 
(1).直接
默认流控模式,当接口达到限流条件时,直接开启限流功能。
配置及说明
表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误
测试:快速点击访问: http://localhost:8401/testA 快速点击超过1秒,则进行限流
结果:Blocked by Sentinel (flow limiting) 表示流量限制,该默认报错为sentinel默认,可进行修改。
(2).关联
  • 当关联的资源达到阈值时,就限流自己
  • 当与A关联的资源B达到阀值后,就限流A自己
B惹事,A挂了
配置A
当关联资源/testB的qps阀值超过1时,就限流/testA的Rest访问地址,当关联资源到阈值后限制配置好的资源名,B惹事,A挂了
Jmeter模拟并发密集访问testB
官网地址: Apache JMeter - Download Apache JMeter
版本:Apache JMeter 5.6.2 (Requires Java 8+)以上
访问testB成功: http://localhost:8401/testB
Run
大批量线程高并发访问B,导致A失效了
测试:
点击访问: http://localhost:8401/testA
结果:Blocked by Sentinel (flow limiting)
(3).链路 
来自不同链路的请求对同一个目标访问时,实施针对性的不同限流措施,比如C请求来访问就限流,D请求来访问就是OK
1.修改微服务cloudalibaba-sentinel-service8401
YML修改 
web-context-unifyfalse  # controller
server:
  port: 8401
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扫描,直至找到未被占用的端口
      web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路
业务类
新建FlowLimitService
@SentinelResource(value = "common")
package com.atguigu.cloud.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;

@Service
public class FlowLimitService {
    @SentinelResource(value = "common")
    public void common()
    {
        System.out.println("------FlowLimitService come in");
    }
}

修改FlowLimitController
package com.atguigu.cloud.controller;

import com.atguigu.cloud.service.FlowLimitService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FlowLimitController {

    @GetMapping("/testA")
    public String testA(){
        return "-----testA";
    }
    @GetMapping("/testB")
    public String testB(){
        return "-----testB";
    }

    @Resource private FlowLimitService flowLimitService;
    @GetMapping("/testC")
    public String testC()
    {
        flowLimitService.common();
        return "------testC";
    }
    @GetMapping("/testD")
    public String testD()
    {
        flowLimitService.common();
        return "------testD";
    }
}
2.sentinel配置
说明:C和D两个请求都访问 flowLimitService.common()方法,对C限流,对D不管。
3.测试
访问地址: http://localhost:8401/testC
C链路:超过一秒钟一次后,就发生限流
D链路Ok

3.流控效果

快速失败:单机阈值超过1秒,则直接失败。
warm Up:单机阈值为10秒(需除以冷却因子3),预热时间为5秒(保护时间阈值为10/3 约为1秒三次),预热时间过后为最高阈值1秒10。
排队等待:按照单机阈值为1秒,一秒钟通过一个请求,10秒后的请求作为超时处理,放弃。10秒的话一般在10、11条左右。
1. 直接 - 快速失败(默认的流控处理)
直接失败,抛出异常 Blocked by Sentinel (flow limiting)
2 预热WarmUp
(1).限流 冷启动
限流 冷启动: 限流 冷启动 · alibaba/Sentinel Wiki · GitHub
概述
当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。
这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等。
(2).公式
公式:阈值除以冷却因子coldFactor(默认值为3),经过预热时长后才会达到阈值
(3).官网及源码
地址: 流量控制 · alibaba/Sentinel Wiki · GitHub
默认 coldFactor 为3,即请求 QPS 从 threshold/3 开始,经预热时长逐渐升至设定的 QPS 阈值。
源码:
com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
(4).官网WarmUp配置
默认 coldFactor 为 3,即请求QPS从(threshold / 3) 开始,经多少预热时长才逐渐升至设定的 QPS 阈值。
案例,单机阈值为10,预热时长设置5秒。
系统初始化的阈值为10 / 3 约等于3,即单机阈值刚开始为3(我们人工设定单机阈值是10,sentinel计算后QPS判定为3开始);
然后过了5秒后阀值才慢慢升高恢复到设置的单机阈值10,也就是说5秒钟内QPS为3,过了保护期5秒后QPS为10
(5).官网测试:
多次点击 http://localhost:8401/testB 刚开始不行,后续慢慢OK
(6).官网应用场景:
如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。
3 排队等待
(1).解释
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考  流量控制 - 匀速器模式,具体的例子可以参见  PaceFlowDemo。
该方式的作用如下图所示:
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
注意:匀速排队模式暂时不支持 QPS > 1000 的场景。
(2).修改FlowLimitController
@GetMapping("/testE")
public String testE()
{
    System.out.println(System.currentTimeMillis()+"      testE,排队等待");
    return "------testE";
}
(3).sentinel配置
先进行访问地址,才能进行配置,在流控规则与簇点链路都可以进行添加
http://localhost:8401/testE
jmeter工具 Thread Group
线程数20 1秒
Http Request 访问地址
sentinel设置规则 
按照单机阈值,一秒钟通过一个请求,10秒后的请求作为超时处理,放弃
(4).测试效果:
http://localhost:8401/testE
按照单机阈值,一秒钟通过一个请求,10秒后的请求作为超时处理,放弃,10秒的话一般在10、11、12条左右。

4.流控效果V2(并发线程数)

(1).sentinel配置
(2).Jmeter模拟多个线程并发+循环请求
(3).测试:
http://localhost:8401/testB
Jmeter给它打满了,大部分我们自己访问都不好使,偶尔Jmeter线程切换系统判定没访问,我们自己的点击才有点机会。

五、熔断规则

官网地址: 熔断降级 · alibaba/Sentinel Wiki · GitHub

基本介绍

Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。

熔断策略

Sentinel 提供以下几种熔断策略:
  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
注意:异常降级 仅针对业务异常 ,对 Sentinel 限流降级本身的异常(BlockException )不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex)  记录业务异常。

新增熔断规则实战

1.慢调用比例:
例:1秒钟最小请求5个,超过超过20%比例,最大RT200毫秒的为慢调用,则进入熔断,熔断时间为5s,熔断时间过后在进行尝试恢复,成功则继续使用,恢复失败则在此进入熔断时长。调用比例0.1也就是为10分之一。
2. 异常比例:
例:1秒钟最小请求5个,超过20%的异常,则为异常比例调用,则进入熔断,熔断时间为5s,熔断时间过后在进行尝试恢复,成功则继续使用,恢复失败则在此进入熔断时长,调用比例0.2也就是为五分之一。
3.异常数:
例:1秒内最小请求5次,异常数达到1个,则进入熔断,熔断时间为5s,熔断时间过后在进行尝试恢复,成功则继续使用,恢复失败则在此进入熔断时长。
1. 慢调用比例
(1).解释
慢调用比例(SLOW REQUEST RATI0 ): 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间)请求的响应时间大于该值则统计为慢调用。当单位统计时长(statInterva1Ms)内请求数目 大于设置的最小请求数目,并且 慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
例:1秒钟最小请求5个,超过超过20%比例,最大RT200毫秒的为慢调用,则进入熔断,熔断时间为5s,熔断时间过后在进行尝试恢复,成功则继续使用,恢复失败则在此进入熔断时长。调用比例0.1也就是为10分之一。
(2).名词解释
进入熔断状态判断依据:在统计时长内,实际请求数目>设定的最小请求数    且      实际慢调用比例>比例阈值 ,进入熔断状态。
1.调用:一个请求发送到服务器,服务器给与响应,一个响应就是一个调用。
2.最大RT:即最大的响应时间,指系统对请求作出响应的业务处理时间。
3.慢调用:处理业务逻辑的实际时间>设置的最大RT时间,这个调用叫做慢调用。
4.慢调用比例:在所以调用中,慢调用占有实际的比例=慢调用次数➗总调用次数
5.比例阈值:自己设定的 , 比例阈值=慢调用次数➗调用次数
6.统计时长:时间的判断依据
7.最小请求数:设置的调用最小请求数,上图比如1秒钟打进来10个线程(大于我们配置的5个了)调用被触发。
(3).触发条件+熔断状态
进入熔断状态判断依据:在统计时长内,实际请求数目>设定的最小请求数    且      实际慢调用比例>比例阈值 ,进入熔断状态。
1熔断状态(保险丝跳闸断电,不可访问):在接下来的熔断时长内请求会自动被熔断
2探测恢复状态(探路先锋):熔断时长结束后进入探测恢复状态
3结束熔断(保险丝闭合恢复,可以访问):在探测恢复状态,如果接下来的一个请求响应时间小于设置的慢调用 RT,则结束熔断,否则继续熔断。
(4).测试示例
1).代码
/**
 * 新增熔断规则-慢调用比例
 * @return
 */
@GetMapping("/testF")
public String testF()
{
    //暂停几秒钟线程
    try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
    System.out.println("----测试:新增熔断规则-慢调用比例 ");
    return "------testF 新增熔断规则-慢调用比例";
}
10个线程,在一秒的时间内发送完。又因为服务器响应时长设置:暂停1秒,所以响应一个请求的时长都大于1秒综上符合熔断条件,所以当线程开启1秒后,进入熔断状态。
2).配置
进入熔断状态判断依据:在统计时长内,实际请求数目>设定的最小请求数    且      实际慢调用比例>比例阈值 ,进入熔断状态。 
3).jmeter压测
4).结论 
 按照上述配置,熔断触发:
多次循环,一秒钟打进来10个线程(大于5个了)调用/testF,我们希望200毫秒处理完一次调用,和谐系统;^_^
假如在统计时长内,实际请求数目>最小请求数且慢调用比例>比例阈值 ,断路器打开(保险丝跳闸)微服务不可用(Blocked by Sentinel (flow limiting)),进入熔断状态5秒 后续我停止jmeter,没有这么大的访问量了,单独用浏览器访问rest地址,断路器关闭(保险丝恢复,合上闸口),
微服务恢复OK
2. 异常比例
(1).解释
异常比例(ERROR RATIO):当单位统计时长(statInterva1ms )内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是[0.8,1.8],代表 0%-100%。
Blocked by Sentinel (flow limiting)
(2).测试示例
1).代码
/**
 * 新增熔断规则-异常比例
 * @return
 */
@GetMapping("/testG")
public String testG(){
    System.out.println("----测试:新增熔断规则-异常比例");
    int age= 10/0;
    return "------testG,新增熔断规则-异常比例";
}
2).配置
  • 不配置Sentinel,对于int age=10/0,调一次错一次报错error,页面报【Whitelabel Error Page】或全局异常 
  •  配置Sentinel,对于int age=10/0,如符合如下异常比例启动熔断,页面报【Blocked by Sentinel (flow limiting)】
例:1秒钟最小请求5个,超过20%的异常,则为异常比例调用,进行熔断,熔断时间5s,熔断时间过后在进行尝试恢复,成功则继续使用,恢复失败则在此进入熔断时长,调用比例0.2也就是为五分之一。
3).jemeter压测
1秒 20线程数
4).结论
按照上述配置,单独访问一次,必然来一次报错一次(int age  = 10/0)达到100%,调一次错一次报错error;
 开启jmeter后,直接高并发发送请求,多次调用达到我们的配置条件了。
断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务熔断+服务降级,出提示Blocked by Sentinel (flow limiting)。等时长达到熔断时长才会重新尝试恢复。
注意:需将全局异常注释掉GlobalExceptionHandler,否则就被全局异常捕获了,看不到效果。
3.异常数
(1).解释
异常数(ERROR COUNT ):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢
复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
(2).测试示例
(1).代码
/**
 * 新增熔断规则-异常数
 * @return
 */
@GetMapping("/testH")
public String testH()
{
    System.out.println("----测试:新增熔断规则-异常数 ");
    int age = 10/0;
    return "------testH,新增熔断规则-异常数 ";
}
(2).配置
例:1秒内最小请求5次,异常数达到1则,进行熔断,熔断时间结束后尝试进行恢复。恢复则继续使用,未恢复则继续等待熔断时长,在进行尝试。
(3).jemeter压测
(4).结论
http://localhost:8401/testH,第一次访问绝对报错,因为除数不能为零,我们看到error窗口;
开启jmeter后,直接高并发干爆他发送请求,多次调用达到我们的配置条件了。
但是jmeter开工,上述配置表示,在1秒钟内最少请求2次,当异常数大于1时,会触发熔断操作断路器开启(保险丝跳闸),微服务不可用了,熔断的时长为5秒,不再报错error而是服务降级了出提示Blocked by Sentinel (flow limiting) 

 六、@SentinelResource注解

1.简介

SentinelResource是一个流量防卫防护组件注解用于指定防护资源,对配置的资源进行流量控制、熔断降级等功能。

2.源码说明

@SentinelResource注解说明(源码):
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {

    //资源名称
    String value() default "";

    //entry类型,标记流量的方向,取值IN/OUT,默认是OUT
    EntryType entryType() default EntryType.OUT;
    //资源分类
    int resourceType() default 0;

    //处理BlockException的函数名称,函数要求:
    //1. 必须是 public
    //2.返回类型 参数与原方法一致
    //3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置blockHandlerClass ,并指定blockHandlerClass里面的方法。
    String blockHandler() default "";

    //存放blockHandler的类,对应的处理函数必须static修饰。
    Class<?>[] blockHandlerClass() default {};

    //用于在抛出异常的时候提供fallback处理逻辑。 fallback函数可以针对所
    //有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。函数要求:
    //1. 返回类型与原方法一致
    //2. 参数类型需要和原方法相匹配
    //3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass ,并指定fallbackClass里面的方法。
    String fallback() default "";

    //存放fallback的类。对应的处理函数必须static修饰。
    String defaultFallback() default "";

    //用于通用的 fallback 逻辑。默认fallback函数可以针对所有类型的异常进
    //行处理。若同时配置了 fallback 和 defaultFallback,以fallback为准。函数要求:
    //1. 返回类型与原方法一致
    //2. 方法参数列表为空,或者有一个 Throwable 类型的参数。
    //3. 默认需要和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass ,并指定 fallbackClass 里面的方法。
    Class<?>[] fallbackClass() default {};
 

    //需要trace的异常
    Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};

    //指定排除忽略掉哪些异常。排除的异常不会计入异常统计,也不会进入fallback逻辑,而是原样抛出。
    Class<? extends Throwable>[] exceptionsToIgnore() default {};
}

3.启动Nacos成功

startup.cmd -m standalone

4.启动Sentinel成功

java -jar sentinel-dashboard-1.8.8.jar

5.按照rest地址限流+默认限流返回

通过访问的rest地址来限流,会返回Sentinel自带默认的限流处理信息。
rest地址----- @GetMapping("/rateLimit/byUrl")
(1).业务类RateLimitController
@RestController
@Slf4j
public class RateLimitController {
    
    @GetMapping("/rateLimit/byUrl")
    public String byUrl(){
        return  "按rest地址限流测试OK";
    }
}
访问一次: http://localhost:8401/rateLimit/byUrl
(2).Sentinel控制台配置
(3).测试
:点击速度超过每秒1次: http://localhost:8401/rateLimit/byUrl
结果:会返回Sentinel自带的限流处理结果,默认 

6.按SentinelResource资源名称限流+自定义限流返回

不想用默认的限流提示(Blocked by Sentinel(flow limiting)),想返回 自定义限流的提示
@SentinelResource(value = "byResourceSentinelResource",blockHandler = "handleException")
资源名称----byResourceSentinelResource
自定义限流返回-----handleException
(1).微服务cloudalibaba-sentinel-service8401
业务类RateLimitController
@GetMapping("/rateLimit/byResource")
@SentinelResource(value = "byResourceSentinelResource",blockHandler = "handleException")
public String byResource()
{
    return "按资源名称SentinelResource限流测试OK";
}
public  String handleException(BlockException exception)
{
    return "服务不可用@SentinelResource启动"+"\t"+"o(╥﹏╥)o";
}
(2).测试地址
http://localhost:8401/rateLimit/byResource
(3).配置流控规则:
配置步骤
设置流控时选择的不是地址而是@SentinelResource value值进行参数设置。
图形配置和代码关系
(4).测试
1秒钟点击1下,OK
超过上述,疯狂点击,返回了 自定义的限流处理信息,限流发生。
sentinel默认
自定义限流提示

7.按SentinelResource资源名称限流+自定义限流返回+服务器降级处理

按SentinelResource配置,点击超过限流配置返回自定义限流提示+程序异常返回fallback服务降级
@SentinelResource(value = "doActionSentinelResource",
            blockHandler = "doActionBlockHandler", fallback = "doActionFallback")
资源名称--------------doActionSentinelResource
自定义限流返回-----doActionBlockHandler
程序异常---------------fallback
(1).微服务cloudalibaba-sentinel-service8401
RateLimitController
@GetMapping("/rateLimit/doAction/{p1}")
    @SentinelResource(value = "doActionSentinelResource",
            blockHandler = "doActionBlockHandler", fallback = "doActionFallback")
    public String doAction(@PathVariable("p1") Integer p1) {
        if (p1 == 0){
            throw new RuntimeException("p1等于零直接异常");
        }
        return "doAction";
    }

    public String doActionBlockHandler(@PathVariable("p1") Integer p1,BlockException e){
        log.error("sentinel配置自定义限流了:{}", e);
        return "sentinel配置自定义限流了";
    }

    public String doActionFallback(@PathVariable("p1") Integer p1,Throwable e){
        log.error("程序逻辑异常了:{}", e);
        return "程序逻辑异常了"+"\t"+e.getMessage();
    }
未添加图形配置前测试: http://localhost:8401/rateLimit/doAction/2
(2).配置流控规则
图形配置和代码关系
设置流控时选择的不是地址而是@SentinelResource value值进行参数设置。
表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流
(3).测试
http://localhost:8401/rateLimit/doAction/2
1秒钟点击1下,OK
超过上述,疯狂点击,返回了 自己定义的限流处理信息,限流发生,配合了sentinel设定的规则
http://localhost:8401/rateLimit/doAction/0
p1参数为零,异常发生,返回了 自己定义的服务降级处理
小结
  • blockHandler,主要针对sentinel配置后出现的违规情况处理
  • fallback,程序异常了JVM抛出的异常服务降级
  • 两者可以同时共存

七、热点规则

1.基本介绍
2.官网
3.代码
4.配置
5.测试
6.参数例外项

1.基本介绍

何为热点
热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作

2.官网:

官网地址: 热点参数限流 · alibaba/Sentinel Wiki · GitHub

3.代码

/**
 * 热点参数限流示例
 * @param p1
 * @param p2
 * @return
 */
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
public String testHotKey(@RequestParam(value="p1",required = false)String p1,@RequestParam(value = "p2",required = false)String p2)
{
    return "----testHotKey";
}
public String dealHandler_testHotKey(String p1,String p2,BlockException exception){
    return "----dealHandler_testHotKey";
}
 sentinel系统默认的提示:Blocked by Sentinel (flow limiting)

4.配置 

限流模式只支持QPS模式,固定写死了。(这才叫热点)
@SentinelResource注解的方法 参数索引0代表第一个参数,1代表第二个参数,以此类推
单机阀值以及统计窗口时长表示在此窗口时间超过阀值就限流。
上面的抓图就是第一个参数有值的话,1秒的QPS为1,超过就限流,限流后调用dealHandler_testHotKey支持方法。
  • 方法testHotKey里面第一个参数P1只要QPS超过每秒1次,马上降级处理
  • http://localhost:8401/testHotKey

5.测试

测试一:
  • http://localhost:8401/testHotKey?p1=abc
  • 含有参数P1,当每秒访问的频率超过1次时,会触发Sentinel的限流操作
测试二:
  • http://localhost:8401/testHotKey?p1=abc&p2=33
  • 含有参数P1且包括其他参数,当每秒访问的频率超过1次时,也会触发Sentinel的限流操作
测试三:
  • http://localhost:8401/testHotKey?p2=abc
  • 没有热点参数P1,不断访问则不会触发限流操作
总结: 只要含有参数P1(设置热点规则的参数),当每秒访问的频率超过1次(指定秒数)时,便会触发Sentinel的限流操作。

6.参数例外项

上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流
参数例外项:当参数等于特定某个值时,参数阈值会发生变化,其他值时仍然会被。
特例情况
(1).普通正常限流
  • 含有P1参数,超过1秒钟一个后,达到值1后马上被限流
(2).例外特殊限流
  • 我们期望p1参数当它是某个特殊值时,到达某个约定值后【普通正常限流】规则突然例外、失效了,它的限流值和平时不一样
  • 假如当p1的值等于5时,它的阈值可以达到200或其它值
配置
备注:
1.图形中的参数类型string要与代码p1的参数类型相同。
2.添加按钮不能忘。
测试
测试一:
  • http://localhost:8401/testHotKey?p1=5
  • 超过1秒钟一个后,达到阈值200后才会被限流
  • 当p1等于5的时候,阈值变为200
测试二:
  • http://localhost:8401/testHotKey?p1=3
  • 超过1秒钟一个后,达到阈值后马上被限流
  • 当p1不等于5的时候,阈值就是平常的【普通正常限流】规则
前提条件
热点参数的注意点,参数必须是基本类型或者String

八、授权规则

1.简介

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。 来源访问控制根据资源的请求来源( origin )限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
在某些场景下,需要根据调用接口的来源判断是否允许执行本次请求。此时就可以使用Sentinel提供的授权规则来实现,Sentinel的授权规则能够根据请求的来源判断是否允许本次请求通过。  在Sentinel的授权规则中,提供了 白名单与黑名单 两种授权类型。白放行、黑禁止。
调用方信息通过 ContextUtil.enter(resourceName, origin) 方法中的 origin 参数传入。

2.官网

官网地址: 黑白名单控制 · alibaba/Sentinel Wiki · GitHub

3.黑白名单示例

演示授权规则,黑白名单静止
EmpowerController
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Empower授权规则,用来处理请求的来源
 */
@RestController
@Slf4j
public class EmpowerController {

    @GetMapping(value = "/empower")
    public String requestSentinel4(){
        log.info("测试Sentinel授权规则empower");
        return "Sentinel授权规则";
    }
}
MyRequestOriginParser
调用方信息通过 ContextUtil.enter(resourceName, origin) 方法中的 origin 参数传入。
如何在实际应用中设置:
RequestOriginParser (转换请求参数类)可以转换ip、用户、appName等。
我们需要重写该类中的parseOrigin方法来说实现 origin参数的传入,告诉httpServletRequest携带的是什么参数,是黑名单还是白名单,放行还是静止。
package com.atguigu.cloud.controller.handle;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
/**
 *  RequestOriginParser 中的- parseOrigin方法来说实现 origin参数的传入,告诉httpServletRequest携带的是什么参数,是黑名单还是白名单,放行还是静止。
 */
@Component
public class MyRequestOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        return httpServletRequest.getParameter("serverName");
    }
}
启动8401后先访问成功,Sentinel才能识别到
http://localhost:8401/empower

4.配置

5.测试

测试1:
  • http://localhost:8401/empower?serverName=test
  • Blocked by Sentinel (flow limiting)
测试2:
  • http://localhost:8401/empower?serverName=test2
  • Blocked by Sentinel (flow limiting)
不断在浏览器中刷新 http://localhost:8401/empower?serverName=test
不断在浏览器中刷新 http://localhost:8401/empower?serverName=test2
上述2个rest地址,serverName=test或serverName=test2是处于黑名单的状态无法访问,会发现无法访问,被Sentinel限流了
测试3:
  • http://localhost:8401/empower?serverName=ab
  • 访问正常 返回参数:Sentinel授权规则

九、规则持久化

1.简介

一旦我们重启微服务应用,sentinel规则将消失,生产环境需要将配置 规则进行持久化
Sentiel规则持久化三种模式分析
推送模式
说明
优点
缺点
原始模式
API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource)
简单,无任何依赖
不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境
Pull 拉取模式
扩展写数据源(WritableDataSource), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等,还需要实现文件的读数据源(ReadableDataSource)
简单,无任何依赖;规则持久化
不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。
Push 推送模式
扩展读数据源(ReadableDataSource),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。
规则持久化;一致性;快速
引入第三方依赖
原始模式
原始模式
  • 在这种模式下,规则是直接通过 Sentinel 控制台定义,并且通过 Sentinel 的 API 推送到客户端。规则被保存在客户端的内存中,因此如果客户端重启,规则就会丢失。这种方式不适合生产环境,因为它缺乏持久化能力。
如果不做任何修改,Dashboard 的推送规则方式是通过 API 将规则推送至客户端并直接更新到内存中:
这种做法的好处是简单,无依赖;坏处是应用重启规则就会消失,仅用于简单测试,不能用于生产环境。
2.1、控制台是如何推送规则?
  1. 在控制台界面新增规则后。
  2. 将规则存储到内存中:通过InMemoryRuleRepositoryAdapter#save() 存储到内存中。
  3. 将规则发布到客户端:通过SentinelApiClient#executeCommand() 发起异步的http调用,利用的是HttpClient发起的http调用。
  4. Http请求的路径就是Sentinel客户端的ServerSocket监听的端口。
2.2、客户端是如何接收控制台推送的规则?
  1. sentinel-transport-common-1.8.0.jar这个jar包是用来实现控制台和客户端的通信的jar。
  2. CommandCenter的实现类SimpleHttpCommandCenter的start()方法会创建ServerSocket,默认8719端口,用来实时监听sentinel-dashboard发送过来的请求。
  3. 客户端解析sentinel dashboard发送的请求数据,解析为不同类型检验规则。
  4. 将规则更新到客户端内存中:DynamicSentinelProperty#updateValue()
  5. 将规则持久化到数据源中,但是这个数据源是空的,没有实现,这是一个扩展点,实现持久化。WritableDataSource#write()
Pull 模式
  • 在 Pull 模式中,客户端会定期从一个规则管理中心(如数据库、文件系统或其他配置中心)拉取最新的规则。这种方式可以保证规则的持久化,但是需要客户端主动去拉取规则,可能会引入额外的网络延迟,并且需要谨慎配置拉取频率以避免性能问题。
Sentinel客户端需要将规则持久化到文件,那么久需要写数据源和读数据源。这就是拉模式的两个扩展点。分别是:
  • WritableDataSource
    • 写数据源的实现类:FileWritableDataSource
  • ReadableDataSource
    • 读数据源的实现类:FileRefreshableDataSource
    • 读数据源的功能:监听文件数据的变化,及时的更新到Sentinel客户端。实现原理是FileRefreshableDataSource的父类AutoRefreshDataSource数据源内部新建了一个定时任务,每隔3000ms就判断一次文件是否改变。
Push模式
  • Push 模式是 Sentinel 推荐的一种持久化方式,它通过一个中央管理系统(如 Nacos、Apollo、Zookeeper、Redis 等)来管理规则,并将规则推送到客户端。这种方式可以实现实时性较好的规则更新,同时减少了客户端的轮询负担。
4.1、大体原理
生产环境下一般更常用的是push模式的数据源。对于push模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由Sentinel客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。因此推送规则正确做法应该是配置中心控制台/Sentinel控制台 → 配置中心 → Sentinel数据源 → Sentinel,而不是经Sentinel数据源推送至配置中心。这样的流程就非常清晰了:
  1. 控制台推送规则:将规则推送到Nacos或其他远程配置中心。Sentinel客户端链接Nacos,获取规则配置;并监听Nacos配置变化,如发生变化,就更新本地缓存(从而让本地缓存总是和Nacos一致)
  2. 控制台监听Nacos配置变化,如发生变化就更新本地缓存(从而让控制台本地缓存总是和Nacos一致)
自定义持久化
  • Sentinel允许开发人员编写自己的DataSource适配器来与不同的持久化存储系统集成。
  • 提供高度的灵活性,可以与各种外部系统(如数据库、缓存系统等)集成,实现规则的动态加载和更新。
  • 需要配置Sentinel与外部系统的连接,并编写必要的代码来处理规则的加载和更新。

2.规则的种类

Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
Sentinel 支持以下几种规则: 流量控制规则熔断降级规则系统保护规则来源访问控制规则 和  热点参数规则
  • 流量控制规则 FlowRule
  • 熔断降级规则 DegradeRule
  • 系统保护规则 SystemRule
  • 访问控制规则 AuthorityRule
  • 热点规则 ParamFlowRule
流量控制规则 (FlowRule)
Field
说明
默认值
resourceName
资源名,资源名是限流规则的作用对象
limitApp
流控针对的调用来源,若为 default 则不区分调用来源
default,代表不区分调用来源
grade
限流阈值类型,QPS 模式(1)或并发线程数模式(0)
QPS 模式
count
限流阈值
strategy
调用关系限流策略:直接、链路、关联
根据资源本身(直接)
controlBehavior
流量控制效果(直接拒绝、Warm Up、匀速排队)
直接拒绝
clusterMode
是否集群限流
同一个资源可以同时有多个限流规则。
通过代码定义流量控制规则
理解上面规则的定义之后,我们可以通过调用  FlowRuleManager.loadRules() 方法来用 硬编码的方式定义流量控制规则,比如:
private static void initFlowQpsRule() {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule1 = new FlowRule();
    rule1.setResource(resource);
    // Set max qps to 20
    rule1.setCount(20);
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setLimitApp("default");
    rules.add(rule1);
    FlowRuleManager.loadRules(rules);
}
熔断降级规则 (DegradeRule)
熔断降级规则包含下面几个重要的属性:
Field
说明
默认值
resource
资源名,即规则的作用对象
grade
熔断策略,支持慢调用比例/异常比例/异常数策略
慢调用比例
count
慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow
熔断时长,单位为 s
minRequestAmount
熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)
5
statIntervalMs
统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)
1000 ms
slowRatioThreshold
慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
同一个资源可以同时有多个降级规则。
理解上面规则的定义之后,我们可以通过调用 DegradeRuleManager.loadRules() 方法来用硬编码的方式定义流量控制规则。
private static void initDegradeRule() {
    List<DegradeRule> rules = new ArrayList<>();
    DegradeRule rule = new DegradeRule(resource);
        .setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType());
        .setCount(0.7); // Threshold is 70% error ratio
        .setMinRequestAmount(100)
        .setStatIntervalMs(30000) // 30s
        .setTimeWindow(10);
    rules.add(rule);
    DegradeRuleManager.loadRules(rules);
}
熔断器事件监听
Sentinel 支持注册自定义的事件监听器监听熔断器状态变换事件(state change event)。示例:
EventObserverRegistry.getInstance().addStateChangeObserver("logging",
    (prevState, newState, rule, snapshotValue) -> {
        if (newState == State.OPEN) {
            // 变换至 OPEN state 时会携带触发时的值
            System.err.println(String.format("%s -> OPEN at %d, snapshotValue=%.2f", prevState.name(),
                TimeUtil.currentTimeMillis(), snapshotValue));
        } else {
            System.err.println(String.format("%s -> %s at %d", prevState.name(), newState.name(),
                TimeUtil.currentTimeMillis()));
        }
    });
系统保护规则 (SystemRule)
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统规则包含下面几个重要的属性:
Field
说明
默认值
highestSystemLoad
load1
触发值,用于触发自适应控制阶段
-1 (不生效)
avgRt
所有入口流量的平均响应时间
-1 (不生效)
maxThread
入口流量的最大并发数
-1 (不生效)
qps
所有入口资源的 QPS
-1 (不生效)
highestCpuUsage
当前系统的 CPU 使用率(0.0-1.0)
-1 (不生效)
理解上面规则的定义之后,我们可以通过调用 
SystemRuleManager.loadRules()  方法来用硬编码的方式定义流量控制规则:
private void initSystemProtectionRule() {
    List<SystemRule> rules = new ArrayList<>();
    SystemRule rule = new SystemRule();
    rule.setHighestSystemLoad(10);
    rules.add(rule);
    SystemRuleManager.loadRules(rules);
  }
访问控制规则 (AuthorityRule)
很多时候,我们需要根据调用方来限制资源是否通过,这时候可以使用 Sentinel 的访问控制(黑白名单)的功能。黑白名单根据资源的请求来源( origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
授权规则,即黑白名单规则( AuthorityRule)非常简单,主要有以下配置项:
  • resource:资源名,即限流规则的作用对象
  • limitApp:对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB
  • strategy:限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式
更多详情可以参考  来源访问控制
热点参数规则ParamFlowRule
热点参数规则( ParamFlowRule)类似于流量控制规则( FlowRule):
属性
说明
默认值
resource
资源名,必填
count
限流阈值,必填
grade
限流模式
QPS 模式
durationInSec
统计窗口时间长度(单位为秒),1.6.0 版本开始支持
1s
controlBehavior
流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持
快速失败
maxQueueingTimeMs
最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持
0ms
paramIdx
热点参数的索引,必填,对应
SphU.entry(xxx, args)
中的参数索引位置
paramFlowItemList
参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面
count
阈值的限制。
仅支持基本类型和字符串类型
clusterMode
是否是集群参数流控规则
false
clusterConfig
集群流控相关配置
我们可以通过  ParamFlowRuleManager 的  loadRules 方法更新热点参数规则,下面是一个示例:
ParamFlowRule rule = new ParamFlowRule(resourceName)
    .setParamIdx(0)
    .setCount(5);
// 针对 int 类型的参数 PARAM_B,单独设置限流 QPS 阈值为 10,而不是全局的阈值 5.
ParamFlowItem item = new ParamFlowItem().setObject(String.valueOf(PARAM_B))
    .setClassType(int.class.getName())
    .setCount(10);
rule.setParamFlowItemList(Collections.singletonList(item));

ParamFlowRuleManager.loadRules(Collections.singletonList(rule));

3.配置持久化主要有以下原因:

  1. 数据安全性:持久化配置可以保证在系统或者应用重启后,重要的配置数据不会丢失,可以确保数据的安全性和稳定性。
  2. 数据可恢复性:持久化配置可以在数据丢失或者损坏时进行恢复,保证系统的正常运行。
  3. 支持分布式系统:对于分布式系统来说,配置的持久化可以确保各个节点的一致性,避免因为节点的临时变动导致的问题。
  4. 可扩展性:持久化配置易于进行扩展和修改,可以适应不同的应用场景和业务需求。
  5. 提高系统性能:通过实现配置的持久化,可以有效减少读取配置文件的次数,提高系统的运行效率。
  6. 降低耦合性:持久化配置可以使得应用和配置之间松散耦合,方便系统的维护和升级。

4.单一持久化示例:

将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到, 只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效。
备注:因为生成环境Nacos很少重新启动。
3.步骤:
修改cloudalibaba-sentinel-service8401
1.POM
2.YML
3.添加Nacos业务规则配置 快速访问测试接口
4.停止8401再看sentinel
5.重新启动8401再看sentine
修改cloudalibaba-sentinel-service8401
1).POM添加Nacos
<!--SpringCloud ailibaba sentinel-datasource-nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<?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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.atguigu.cloud</groupId>
        <artifactId>mscloudV5</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <artifactId>cloudalibaba-sentinel-service8401</artifactId>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--SpringCloud ailibaba sentinel-datasource-nacos -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud alibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.atguigu.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--SpringBoot通用依赖模块-->
        <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>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <scope>provided</scope>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
2).YML参数配置
server:
  port: 8401
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扫描,直至找到未被占用的端口
      web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路
      datasource:   #数据持久化规则以json的方式进行存储到nacos中
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow # com.alibaba.cloud.sentinel.datasource.RuleType
代码格式如下
server:
  port: 8401
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扫描,直至找到未被占用的端口
      web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow # com.alibaba.cloud.sentinel.datasource.RuleType
3).添加Nacos数据源配置
  rule-type: flow
spring:
  cloud:
    sentinel:
      datasource:
        ds1: 
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
备注:rule-type是什么?看看源码
  • 流量控制规则 FlowRule
  • 熔断降级规则 DegradeRule
  • 访问控制规则 AuthorityRule
  • 系统保护规则 SystemRule
  • 热点规则 ParamFlowRule
4).源代码
进一步说明
5).添加Nacos业务规则配置
内容解析:
[
    {
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]
解释:
  • resource:资源名称;
  • limitApp:来源应用;
  • grade:阈值类型,0表示线程数,1表示QPS;
  • count:单机阈值;
  • strategy:流控模式,0表示直接,1表示关联,2表示链路;
  • controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
  • clusterMode:是否集群。
快速访问测试接口
http://localhost:8401/rateLimit/byUrl
上面地址访问后等待3秒钟
启动8401后刷新sentinel发现业务规则有了
默认
  • 停止8401再看sentinel
6).重新启动8401再看sentine
乍一看还是没有,稍等一会儿,多次调用 http://localhost:8401/rateLimit/byUr
重新配置出现了,持久化验证通过

5.全面持久化示例:

1).在Nacos中配置sentinel信息
       flux-control: # 流控管理(这个名称可以自定义)
          nacos: # 告诉sentinel用nacos作为数据源
            data-id: feign-test_flux-control_config.json # 配置中心里执行文件的dataId
            server-addr: localhost:8848 # nacos的地址
            rule-type: flow # 指定文件配置的是那种规则
        degrade-control: # 熔断管理(这个名称可以自定义)
          nacos:
            data-id: feign-test_degrade-control_config.json
            server-addr: localhost:8848
            rule-type: degrade
        param-flow-control: # 热点参数管理(这个名称可以自定义)
          nacos:
            data-id: feign_test-hot_flux-config.json
            server-addr: localhost:8848
            rule-type: param-flow
application整体代码及格式
server:
  port: 8401
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扫描,直至找到未被占用的端口
      web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路
      datasource: # sentinel用nacos作为数据源的配置
        flux-control: # 流控管理(这个名称可以自定义)
          nacos: # 告诉sentinel用nacos作为数据源
            data-id: feign-test_flux-control_config.json # 配置中心里执行文件的dataId
            server-addr: localhost:8848 # nacos的地址
            rule-type: flow # 指定文件配置的是那种规则
        degrade-control: # 熔断管理(这个名称可以自定义)
          nacos:
            data-id: feign-test_degrade-control_config.json
            server-addr: localhost:8848
            rule-type: degrade
        param-flow-control: # 热点参数管理(这个名称可以自定义)
          nacos:
            data-id: feign_test-hot_flux-config.json
            server-addr: localhost:8848
            rule-type: param-flow
我们使用nacos配置文件来对服务进行流控、熔断等操作,所以就需要有以下几个必须的参数:
  1. data-id:需要告诉sentinel读取配置中心中的哪个配置文件。
  2. rule-type:告诉sentinel配置文件配置的控制规则,flow:流控、degrade:熔断、param-flow热点参数,想看有哪些规则参数可以查看com.alibaba.cloud.sentinel.datasource包下的枚举类:RuleType
public enum RuleType {
    FLOW("flow", FlowRule.class),
    DEGRADE("degrade", DegradeRule.class),
    PARAM_FLOW("param-flow", ParamFlowRule.class),
    SYSTEM("system", SystemRule.class),
    AUTHORITY("authority", AuthorityRule.class),
    GW_FLOW("gw-flow", "com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),
    GW_API_GROUP("gw-api-group", "com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
   //省略部分代码
}
2).配置信息
我们这里使用的是配置文件的形式对sentinel的控制信息进行持久化,所以会存在一个问题: nacos中的配置文件对于sentinel来讲是单项数据读入,sentinel能监听到nacos中配置的变化,但是我们在sentinel中修改了配置,nacos是不会监听到并进行修改。
如果想进行双向绑定,就需要对sentinel的代码进行修改。
2.1 流控配置
流控指的是 流量控制,也称作限流。它主要是用来限制每单位时间进入系统的请求数量,主要用来保证系统的可用性,防止大流量把系统压死。
[
  {
    "resource": "/test", // 资源名
    "limitApp": "default", // // 针对来源,若为 default 则不区分调用来源
    "grade": 1, // 限流阈值类型(1:QPS;  0:并发线程数)
    "count": 1, // 阈值
    "clusterMode": false, // 是否是集群模式
    "controlBehavior": 0, // 流控效果 (0:快速失败;  1:Warm Up(预热模式);  2:排队等待)
    "strategy": 0,  // 流控模式(0:直接; 1:关联; 2:链路)
    "warmUpPeriodSec": 10, // 预热时间(秒,预热模式需要此参数)
    "maxQueueingTimeMs": 500, // 超时时间(排队等待模式需要此参数)
    "refResource": "rrr" // 关联资源、入口资源(关联、链路模式)
  }
]
2.2 熔断降级配置
在微服务中,熔断降级是一种保障服务稳定性的策略
熔断降级可以简单理解为一个“保险丝”的作用。当某个服务发生严重故障(例如超时、异常等),为了防止整个系统的崩溃,会切断对这个服务的调用。这就像电流过大,保险丝会熔断以保护电路。
具体来说,熔断降级有两个目的:
  • 防止应用程序不断地尝试执行可能会失败的操作给系统造成“雪崩”。
  • 当某个服务提供者发生故障的时候,向调用方返回一个错误响应或者替代响应,而不是让调用方等待超时。
这样,即使个别服务出现问题,整个系统的运行也不会受到影响,这就是熔断降级的作用。
[
    {
        "resource": "/degrade",
        "grade": 0, // 熔断策略,支持慢调用比例(0),异常比例(1),异常数(2)策略
        "count": 1000, // 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用,单位ms);异常比例/异常数模式下为对应的阈值
        "slowRatioThreshold": 0.1,// 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
        "minRequestAmount":  10, //熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断
        "timeWindow": 10, // 熔断时长,单位为 s
        "statIntervalMs": 1000 // 统计时长(单位为 ms),如 60*1000 代表分钟级
    }
]   
2.3 热点参数配置
在微服务中,热点参数限流是一种特殊的限流方法
nacos
Nacos是由阿里巴巴开源的服务治理中间件,集成了动态服务发现、配置管理和服务元数据管理功能,广泛应用于微服务架构中,简化服务治理过程。
项目地址: GitCode - 全球开发者的开源社区,开源代码托管平台
热点参数限流主要是对参数值相同的请求进行分别统计,判断是否超过每秒事务处理量(QPS)的阈值。这种方法相较于传统的限流方式,更精细化和个性化,可以针对具体的应用和服务的瓶颈进行限流。
例如,在一个微服务系统中,“查询用户信息”这个服务可能存在一个热点参数“用户ID”,我们可以通过热点参数限流来控制单位时间内对同一个用户ID的查询请求数量,防止因为某个热点的参数导致整体服务的故障。
[
  {
    "resource": "/test1",
    "grade": 1, // 限流模式(QPS 模式,不可更改)
    "paramIdx": 0, // 参数索引
    "count": 13, // 单机阈值
    "durationInSec": 6, // 统计窗口时长
    "clusterMode": false, // 是否集群 默认false
    "controlBehavior": 0, // 流控效果(支持快速失败和匀速排队模式)
    "limitApp": "default",
    // 高级选项
    "paramFlowItemList": [{
        "classType": "int", // 参数类型
        "count": 222, // 限流阈值
        "object": "2" // 参数值
      }]
  }
]
2.4 系统规则配置
系统规则是用于定义和配置分布式系统的流量控制和防护的一种策略。
可以根据不同的维度(如Load、CPU使用率、总体平均RT、入口QPS和并发线程数等)来设定系统保护规则,以保证系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
[
  {
    "avgRt": 1, // RT
    "highestCpuUsage": -1, // CPU 使用率
    "highestSystemLoad": -1, // LOAD
    "maxThread": -1, // 线程数
    "qps": -1, // 入口 QPS
    "count": 55, // 阈值,在CPU使用率中是百分比
  }
]
2.5 授权规则配置
授权规则是用于控制服务请求者访问受保护资源的一种权限判断。它可以基于请求的来源或其他因素,对请求进行授权或者拒绝。
授权规则有多种实现方式,例如白名单和黑名单。白名单是允许来源在白名单内的调用者访问受保护资源,而黑名单则是禁止来源在黑名单内的调用者访问受保护资源。
在Sentinel中,可以通过自定义RequestOriginParser接口,从请求对象中获取请求者的来源,并按照白名单或黑名单的规则进行授权判断。
[
  {
    "resource": "sentinel_spring_web_context",
    "limitApp": "/test",
    "strategy": 0 // 授权类型(0代表白名单;1代表黑名单。)
  }
]

十、OpenFeign和Sentinel集成实现fallback服务降级

1.需求说明
2.程序解耦
3.编码步骤
4.测试验证

1.需求说明

cloudalibaba-consumer-nacos-order83   通过OpenFeign调用    cloudalibaba-provider-payment9001 
1 84   通过OpenFeign调用  9001微服务,正常访问OK 
2 84   通过OpenFeign调用  9001微服务, 异常访问error
  访问者要有fallback服务降级的情况,不要持续访问9001加大微服务负担,但是通过feign接口调用的又方法各自不同,
  如果每个不同方法都加一个fallback配对方法,会导致代码膨胀不好管理,工程埋雷....../(ㄒoㄒ)/~~ 
3   public  @ interface  FeignClient
   通过fallback属性进行统一配置,feign接口里面定义的 全部方法都走统一的服务降级 一个搞定即可 。 
4 9001微服务自身还带着sentinel内部配置的流控规则,如果满足也会被触发,也即本例有2个Case
  4.1 OpenFeign接口的统一fallback服务降级处理
  4.2 Sentinel访问触发了自定义的限流配置,在注解@SentinelResource里面配置的blockHandler方法。
总结:每个方法都写fallback造成了代码冗余,对fallback进行统一服务降级处理,如果sentinel触发自定义限流则走@SentinelResource里面配置的blockHandler方法。

2.程序解耦

前述参考
本例说明

3.编码步骤

启动nacos服务器8848
startup.cmd -m standalone
启动Sentinel成功
java -jar sentinel-dashboard-1.8.8.jar
该实例主要思想:
1.编写9001服务提供方,主要编写业务内容。
2.将服务纳入到 openfeign( cloud-api-commons)中进行管理,并对外暴露服务9001外所提供的服务接口。
3.消费者通过openfeign( -api-commons)进行调用服务,在调用的过程中需要fallBack服务器降级则进行降级,该进行流量监控则进行流量监控。
1.编写9001服务提供方,主要编写业务内容。
2.将服务纳入到 openfeign( cloud-api-commons)中进行管理,并对外暴露服务9001外所提供的服务接口。
3.消费者通过openfeign( api-commons)进行调用服务,在调用的过程中需要fallBack服务降级则进行降级(降级的编码是在 api-commons中),该进行流量监控则进行流量监控。
(1).修改服务器提供方cloudalibaba-provider-payment9001
1).添加POM依赖
重点依赖:
<!--openfeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--alibaba-sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 引入自己定义的api通用包 -->
<dependency>
    <groupId>com.atguigu.cloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
pom详细maven依赖(全)
 <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--alibaba-sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.atguigu.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--SpringBoot通用依赖模块-->
        <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>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <scope>provided</scope>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>3.2.0</version>
        </dependency>
    </dependencies>

    <build>
<!--        <plugins>-->
<!--            <plugin>-->
<!--                <groupId>org.springframework.boot</groupId>-->
<!--                <artifactId>spring-boot-maven-plugin</artifactId>-->
<!--            </plugin>-->
<!--        </plugins>-->
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>16</source>
                    <target>16</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
2).修改YML
配置sentinel参数
server:
  port: 9001
spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
        discovery:
          server-addr: localhost:8848 #配置Nacos地址
    sentinel:
      transport:
        dashboard: localhost:8080 #配置Sentinel dashboard 控制台服务器地址
        port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
3).主启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Main9001
{

    public static void main(String[] args)
    {
        SpringApplication.run(Main9001.class,args);
    }
}
4).编写业务类
controller
package com.atguigu.cloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.cloud.entities.PayDTO;
import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.resp.ReturnCodeEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;

@RestController
public class PayAlibabaController {

    @GetMapping("/pay/nacos/get/{orderNo}")
    @SentinelResource(value = "getPayByOrderNo",blockHandler = "handlerBlockHandler")
    public ResultData getPayByOrderNo(@PathVariable("orderNo")String orderNo)
    {
        //模拟从数据库查询出数据并赋值给DTO
        PayDTO payDTO= new PayDTO();
        payDTO.setId(1024);
        payDTO.setOrderNo(orderNo);
        payDTO.setAmount(BigDecimal.valueOf(9.9));
        payDTO.setUserId(1);
        return ResultData.success("查询返回值:"+payDTO);
    }
    public ResultData handlerBlockHandler(@PathVariable("orderNo")String orderNo, BlockException exception)
    {
        return ResultData.fail(ReturnCodeEnum.RC500.getCode(), "getPayByOrderNo服务器不可用,"+"触发sentinel流控配置规则"+"\t"+"o(╥﹏╥)o");
    }
        /*
    fallback服务降级方法纳入到Feign接口统一处理,全局一个
    public ResultData myFallBack(@PathVariable("orderNo") String orderNo,Throwable throwable)
    {
        return ResultData.fail(ReturnCodeEnum.RC500.getCode(),"异常情况:"+throwable.getMessage());
    }
    */
}

5).启动9001微服务自测一下
http://localhost:9001/pay/nacos/get/ord1024
(2).修改cloud-api-commons
1).添加POM依赖
重点依赖:
<!--openfeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--alibaba-sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
    <!--openfeign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--alibaba-sentinel-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!--SpringBoot通用依赖模块  actuator 是spring boot提供的对应用系统的自省和监控的集成功能,可以对应用系统进行配置查看、相关功能统计等-->
    <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>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!--hutool-->
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
    </dependency>
</dependencies>
2).新增openFeign对外暴露接口
PayFeignSentinelApi
package com.atguigu.cloud.apis;
import com.atguigu.cloud.resp.ResultData;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
 * openFeign 与Sentinel整合-open调用服务提供者如9001,
 * 服务器调用失败,找allback 进行处理全局fallback处理服务器降级
 */
@FeignClient(value = "nacos-payment-provider",fallback = PayFeignSentinelApiFallBack.class)
public interface PayFeignSentinelApi
{
    @GetMapping("/pay/nacos/get/{orderNo}")
    public ResultData getPayByOrderNo(@PathVariable("orderNo")String orderNo);
}
3).为新增远程调用新建全局统一服务降级类
fallback = PayFeignSentinelApiFallBack.class
package com.atguigu.cloud.apis;
import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.resp.ReturnCodeEnum;
import org.springframework.stereotype.Component;

/**
 * 为新增远程调用新建全局统一服务降级类 fallback = PayFeignSentinelApiFallBack.class
 */
@Component
public class PayFeignSentinelApiFallBack implements PayFeignSentinelApi
{
    @Override
    public ResultData getPayByOrderNo(String orderNo) {
        return ResultData.fail(ReturnCodeEnum.RC500.getCode(), "对方服务器宕机或不可用,fallBack服务降级o(╥﹏╥)o");
    }
}
4).gav坐标
哪个子模块需要openFeign 对外暴露且进行调用接口,则将该依赖进行引入,则可以使用。
<!-- 引入自己定义的api通用包 -->
<dependency>
    <groupId>com.atguigu.cloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
(3).修改cloudalibaba-consumer-nacos-order84
1).添加POM依赖
重点依赖:
<!-- 引入自己定义的api通用包 -->
<dependency>
    <groupId>com.atguigu.cloud</groupId>
    <artifactId>cloud-api-commons</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<!--openfeign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--alibaba-sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
pom具体依赖代码(全):
<?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>cloud2024</artifactId>
        <groupId>com.atguigu.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-consumer-nacos-order84</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.atguigu.cloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--alibaba-sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--loadbalancer-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!--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>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
<!--        <plugins>-->
<!--            <plugin>-->
<!--                <groupId>org.springframework.boot</groupId>-->
<!--                <artifactId>spring-boot-maven-plugin</artifactId>-->
<!--            </plugin>-->
<!--        </plugins>-->
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>16</source>
                    <target>16</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
2).YML参数配置
# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true
server:
  port: 84
spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        service-u
#消费者将要去访问的微服务名称(nacos微服务提供者叫什么你写什么)
service-url:
  nacos-user-service: http://nacos-payment-provider

# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true
3).主启动类
package com.atguigu.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients
@SpringBootApplication
@EnableDiscoveryClient
public class Main84 {
    public static void main(String[] args) {
        SpringApplication.run(Main84.class,args);
    }
}
@EnableFeignClients 注解在 Spring Cloud 中的作用是启动 Feign客户端 的自动扫描和创建。 ‌ 当你在一个Spring Boot应用中添加了@EnableFeignClients注解,Spring Boot会自动扫描指定包路径下的所有标记了@FeignClient的接口,并为每个接口创建一个实现类,这个实现类实际上就是一个HTTP客户端,能够以声明式的方式调用远程服务‌
@EnableDiscoveryClient注解是用于将服务注册到服务发现组件上,比如Eureka、consul、nacos、zookeeper等。使用这个注解后,服务会在启动时自动向注册中心注册自己的信息,其他服务通过查询注册中心获取可用的服务列表
4).业务类
orderNacosController
package com.atguigu.cloud.controller;

import com.atguigu.cloud.apis.PayFeignSentinelApi;
import com.atguigu.cloud.resp.ResultData;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderNacosController 
{
    @Resource
    private PayFeignSentinelApi payFeignSentinelApi;
/**
 * 消费着调用openFeign封装的接口(PayFeignSentinelApi)
 */
    @GetMapping(value = "/consumer/pay/nacos/get/{orderNo}")
    public ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo)
    {
        return  payFeignSentinelApi.getPayByOrderNo(orderNo);
    }
}

(4).测试验证

  • 业务模块测试正常访问
  • 自动降级测试是否起效
  • 服务降级是否起效
1).9001正常启动后,再启动84通过feign调用
测试业务模块是否正常访问
服务提供者:测试正常
http://localhost:9001/pay/nacos/get/ord1024
消费者:调用成功
http://localhost:84/consumer/pay/nacos/get/ord1024
2).Sentinel流控为例,进行配置
测试自动降级是否起效
图形界面进行配置
  • http://localhost:84/consumer/pay/nacos/get/ord1024
  • 频繁访问后触发了Sentinel的流控规则 blockHandler起效
3).9001宕机了,83通过feign调用
测试服务提供方故障,服务降级是否起效
  • 测试83调用9001,此时故意关闭9001微服务提供者,看84消费侧自动降级,不会被耗死
  • 降级效果

十一、GateWay和Sentinel集成实现服务限流

1.需求说明
2.启动nacos服务器8848
3.启动sentienl服务器8080
4.步骤
5.测试

1.需求说明

cloudalibaba-sentinel-gateway9528        保护           cloudalibaba-provider-payment9001

2.启动nacos服务器8848

startup.cmd -m standalone

3.启动sentienl服务器8080

java -jar sentinel-dashboard-1.8.8.jar

4.步骤

(1).建Module
(2).改POM
(3).写YML
(4).业务类
(5).主启动
(6).业务类
(1).建Module
cloudalibaba-sentinel-gateway9528
(2).添加POM 依赖
<?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>cloud2024</artifactId>
        <groupId>com.atguigu.cloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloudalibaba-sentinel-gateway9528</artifactId>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.6</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
            <version>1.8.6</version>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
(3).写YML
application.yml
server:
  port: 9528
spring:
  application:
    name: cloudalibaba-sentinel-geteway   # sentinel+gataway整合Case
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8080
    gateway:
      routes:
        - id: pay_routh1 #pay_routh1   #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
          url: https://localhost:9001   #匹配后提供服务的路由地址
          predicates:
            - Path=/pay/**                # 断言,路径相匹配的进行路由
(5).主启动类
package com.atguigu.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class Main9528 {
    public static void main(String[] args) {
        SpringApplication.run(Main9528.class,args);
    }
}
(6).业务类
配置config
gateway网关配置自定义路由规则,限流返回值定制
1.自定义sentinel路由规则:控、熔断、热点、授权
2.自定了限流返回参数定制:BlockRequestHandler
package com.atguigu.cloud.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import org.springframework.http.codec.ServerCodecConfigurer;
import javax.annotation.PostConstruct;
import java.util.*;

@Configuration
public class GatewayConfiguration
{
    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer)
    {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
    @PostConstruct //javax.annotation.PostConstruct
    public void doInit() {
        initBlockHandler();
    }
//=========================================================================================以上为网关默认配置
    /**
     * =================================================================gateway网关配置自定义
     * gateway网关配置自定义路由规则,限流返回值定制
     * 1.自定义sentinel路由规则:控、熔断、热点、授权
     * 2.自定了限流返回参数定制:BlockRequestHandler
      */
    private  void  initBlockHandler()
    {
        Set<GatewayFlowRule> rules = new HashSet<>();
        //可在此添加多过自定义规则要与 Gateway routes中的id相对应,规则参数为sentinel中的流控、熔断、热点、授权等规则。
        rules.add(new GatewayFlowRule("pay_routh1")
                .setCount(2)//根据流控参数进行定义规则
                .setIntervalSec(1)
        );
        //可在此添加多过自定义规则要与 Gateway routes中的id相对应
//        rules.add(new GatewayFlowRule("httpbin_route")

        GatewayRuleManager.loadRules(rules);//将编写的sentinel路由规则加载到网关中.
        BlockRequestHandler handler = new BlockRequestHandler() {//设置的自定义限流响应值定制
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map<String, String> map = new HashMap<>();
                map.put("errorCode", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());//访问太多
                map.put("errorMessage","请求太过频繁,系统忙不过来,触发限流(sentinel+gataway整合Case)");
                return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue(map));
            }
        };
        GatewayCallbackManager.setBlockHandler(handler);//gateway回调方法-添加设置的自定义限流响应值定制
    }
}
参考官网案例地址: Sentinel/sentinel-demo/sentinel-demo-spring-cloud-gateway/src/main/java/com/alibaba/csp/sentinel/demo/spring/sc/gateway/GatewayConfiguration.java at master · alibaba/Sentinel · GitHub
官网参数配置:
使用时只需注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例即可(若使用了 Spring Cloud Alibaba Sentinel,则只需按照 文档进行配置即可,无需自己加 Configuration)。比如:
@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}
Demo 示例: sentinel-demo-spring-cloud-gateway
您可以在 GatewayCallbackManager 注册回调进行定制:
  • setBlockHandler:注册函数用于实现自定义的逻辑处理被限流的请求,对应接口为 BlockRequestHandler。默认实现为 DefaultBlockRequestHandler,当被限流时会返回类似于下面的错误信息:Blocked by Sentinel: FlowException。
注意
  • Sentinel 网关流控默认的粒度是 route 维度以及自定义 API 分组维度,默认不支持 URL 粒度。若通过 Spring Cloud Alibaba 接入,请将 spring.cloud.sentinel.filter.enabled 配置项置为 false(若在网关流控控制台上看到了 URL 资源,就是此配置项没有置为 false)。
  • 若使用 Spring Cloud Alibaba Sentinel 数据源模块,需要注意网关流控规则数据源类型是 gw-flow,若将网关流控规则数据源指定为 flow 则不生效。

5.测试

  • 服务模块原生url访问:http://localhost:9001/pay/nacos/333
  • 加网关模块(gateway)url:http://localhost:9528/pay/nacos/333 点击时:1秒没超过2次 正常
  • sentinel+gateway:加快点击频率,出现限流容错
点击时:1秒超过2次,触发网关配置的sentinel路由规则,进入网关自定义限流返回值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2397991.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vSOME/IP与ETAS DSOME/IP通信的问题解决方案

✅ 一、服务版本不匹配导致 Handover 问题 —— 需要更新 VSOMEIP 代码逻辑 📌 问题描述: 在 SOME/IP 通信中,发布者(offer)与订阅者(subscribe)之间存在服务版本不一致的问题,导致 Handover(切换)失败。 ✅ 解决方案: 需要在 offer_service 和 subscribe 接口中…

软考-系统架构设计师-第十五章 信息系统架构设计理论与实践

信息系统架构设计理论与实践 15.2 信息系统架构风格和分类15.3 信息系统常用的架构模型15.4 企业信息系统总体框架15.5 信息系统架构设计方法 15.2 信息系统架构风格和分类 信息系统架构风格 数据流体系结构风格&#xff1a;批处理、管道-过滤器调用/返回体系结构风格&#x…

MySQL 8 完整安装指南(Ubuntu 22.04)

MySQL 8 完整安装指南&#xff08;Ubuntu 22.04&#xff09; 本教程详细说明如何在 Ubuntu 22.04 上安装和配置 MySQL 8&#xff0c;包含安全优化及远程访问设置。 1️⃣ 添加 MySQL 官方 APT 仓库 官网仓库下载地址&#xff1a;MySQL APT 仓库下载页 下载仓库配置包&#…

安卓jetpack compose学习笔记-UI基础学习

哲学知识应该用哲学的方式学习&#xff0c;技术知识也应该用技术的方式学习。没必要用哲学的态度来学习技术。 学完安卓技术能做事就ok了&#xff0c;安卓技术肯定是有哲学的&#xff0c;但是在初学阶段没必要讨论什么安卓哲学。 学习一们复杂技术的路径有很多&#xff0c;这里…

蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析

目录 一、引言 DS18B20的原理图 单总线简介&#xff1a; ​编辑暂存器简介&#xff1a; DS18B20的温度转换与读取流程 二、代码配置 maic文件 疑问 关于不同格式化输出符号的使用 为什么要rd_temperature()/16.0&#xff1f; onewire.h文件 这个配置为什么要先读lo…

C++中锁与原子操作的区别及取舍策略

文章目录 锁与原子操作的基本概念锁&#xff08;Lock&#xff09;原子操作&#xff08;Atomic Operations&#xff09; 锁与原子操作的区别1. **功能**2. **性能**3. **复杂性**4. **适用场景** 锁与原子操作的取舍策略1. **简单变量操作**2. **复杂共享资源**3. **性能敏感场景…

C++语法系列之类型转换

前言 类型转换是经常存在的情况&#xff0c;类型转换分为隐式类型转化 和 显式类型转化 隐式类型转化&#xff1a;编译器在编译阶段自动进行&#xff0c;能转就转&#xff0c;不能转就编译失败 double i 3.3; int b i; //隐式类型转化 double -> intC搞出来了四种强制类…

详解开漏输出和推挽输出

开漏输出和推挽输出 以上是 GPIO 配置为输出时的内部示意图&#xff0c;我们要关注的其实就是这两个 MOS 管的开关状态&#xff0c;可以组合出四种状态&#xff1a; 两个 MOS 管都关闭时&#xff0c;输出处于一个浮空状态&#xff0c;此时他对其他点的电阻是无穷大的&#xff…

【八股消消乐】索引失效与优化方法总结

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本专栏《八股消消乐》旨在记录个人所背的八股文&#xff0c;包括Java/Go开发、Vue开发、系统架构、大模型开发、具身智能、机器学习、深度学习、力扣算法等相关知识点&#xff…

一步一步配置 Ubuntu Server 的 NodeJS 服务器详细实录——4. 配置服务器终端环境 zsh , oh my zsh, vim

前言 通过前面几篇文章&#xff0c;我们顺利的 安装了 ubuntu server 服务器&#xff0c;并且配置好了 ssh 免密登录服务器&#xff0c;也安装好了 服务器常用软件安装,接下来&#xff0c;我们要仔细的配置一下我们的终端环境&#xff0c;让服务器的终端更加好用。 一般情况下…

数据安全合规体系构建的“三道防线“

引言 "三道防线"模型架构图 #mermaid-svg-wbeppAbwa3Vb3nL2 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wbeppAbwa3Vb3nL2 .error-icon{fill:#552222;}#mermaid-svg-wbeppAbwa3Vb3nL2 .error-text{fi…

【Spring底层分析】Spring AOP基本使用+万字底层源码阅读分析

一、AOP基本使用 三步&#xff1a; 将业务逻辑组件和切面类都加入到容器中&#xff0c;告诉Spring哪个是切面类&#xff08;Aspect&#xff09;在切面类上的每一个通知方法上标注通知注解&#xff0c;告诉Spring何时&#xff08;Before、After、Around……&#xff09;何地运…

新德通科技:以创新驱动光通信一体化发展,赋能全球智能互联

在数字经济与AI技术高速发展的今天&#xff0c;光通信作为信息传输的核心基础设施&#xff0c;正迎来前所未有的升级浪潮。深圳新德通科技有限公司&#xff08;以下简称“新德通科技”&#xff09;凭借其深厚的技术积累与一体化产品布局&#xff0c;成为行业内的中坚力量。本文…

C++ 内存泄漏检测器设计

文章目录 1. C中的动态内存分配2. 什么是内存泄漏3. 内存泄漏的代码案例4. 内存泄漏检查器的设计模块1&#xff1a;位置信息捕获&#xff1a;模块2&#xff1a;内存分配跟踪&#xff1a;模块3&#xff1a;内存释放跟踪&#xff1a;模块4&#xff1a;泄漏记录存储&#xff1a;模…

破局与进阶:ueBIM 在国产 BIM 赛道的差距认知与创新实践

作为国产BIM领域的探索者&#xff0c;斯维尔ueBIM自诞生以来始终以追赶国际头部技术为目标&#xff0c;但不可否认的是&#xff0c;在核心功能覆盖、行业生态成熟度以及全球市场占有率等方面&#xff0c;我们与Autodesk Revit、Bentley Systems等国际巨头仍存在显著差距。这种差…

分布式流处理与消息传递——向量时钟 (Vector Clocks) 算法详解

Java 实现向量时钟 (Vector Clocks) 算法详解 一、向量时钟核心原理 #mermaid-svg-JcZ1GT0r1ZNSy6W7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JcZ1GT0r1ZNSy6W7 .error-icon{fill:#552222;}#mermaid-svg-JcZ…

20250603在荣品的PRO-RK3566开发板的Android13下的命令行查看RK3566的温度

20250603在荣品的PRO-RK3566开发板的Android13下的命令行查看RK3566的温度 2025/6/3 11:58 RK3566的cpu运行效率 top rk3566_t:/ # rk3566_t:/ # rk3566_t:/ # cd /sys/class/thermal/ rk3566_t:/sys/class/thermal # ls -l rk3566_t:/sys/class/thermal # cd thermal_zone0/ r…

帝可得 - 设备管理

一. 需求说明 设备管理主要涉及到三个功能模块&#xff0c;业务流程如下&#xff1a; 新增设备类型: 允许管理员定义新的售货机型号&#xff0c;包括其规格和容量。 新增设备: 在新的设备类型定义后&#xff0c;系统应允许添加新的售货机实例&#xff0c;并将它们分配到特定的…

【iOS安全】使用LLDB调试iOS App | LLDB基本架构 | LLDB安装和配置

LLDB基本架构 参考&#xff1a; https://crifan.github.io/ios_re_dynamic_debug/website/debug_code/lldb_debugserver.html https://book.crifan.org/books/ios_re_debug_debugserver_lldb/website/ LLDB安装和配置 1. 让iPhone中出现/Developer/usr/bin/debugserver 最初…

Idea 配置 Maven 环境

下载 Maven 官网&#xff1a;https://maven.apache.org/index.html 点击左侧 Downloads&#xff0c;然后选择 Files 中的 zip 包下载&#xff08;下载慢可以使用迅雷&#xff09; 配置 Maven 将压缩包解压&#xff0c;比如我解压后放到了 D:\developer\environment\apache-…