Sentinel

目录

Sentinel流量控制

[1. 雪崩问题](#1. 雪崩问题)

[​2. 服务保护技术对比](#2. 服务保护技术对比)

[3. 认识Sentinel](#3. 认识Sentinel)

[4. 安装启动Sentinel](#4. 安装启动Sentinel)

[5. 微服务整合sentinel](#5. 微服务整合sentinel)

[6. 限流规则-直接模式](#6. 限流规则-直接模式)

[7. jmeter测试工具](#7. jmeter测试工具)

[8. 限流规则-关联模式](#8. 限流规则-关联模式)

[9. 限流规则-链路模式](#9. 限流规则-链路模式)

[10. 流控效果-预热模式](#10. 流控效果-预热模式)

[11. 流控效果-排队等待](#11. 流控效果-排队等待)

[12. 热点参数限流](#12. 热点参数限流)

高级篇-sentinel隔离和降级

[1. Feign整合Sentinel](#1. Feign整合Sentinel)

[2. 线程隔离](#2. 线程隔离)

[3. 熔断降级](#3. 熔断降级)

[4. 熔断降级-慢调用](#4. 熔断降级-慢调用)

[5. 熔断降级-异常比例或异常数](#5. 熔断降级-异常比例或异常数)

高级篇-sentinel授权规则

[1. 授权规则](#1. 授权规则)

[2. 自定义异常结果](#2. 自定义异常结果)

[​3. 规则持久化](#3. 规则持久化)

[3.1. 规则管理模式](#3.1. 规则管理模式)

[3.2. 实现push模式](#3.2. 实现push模式)


Sentinel流量控制

sentinel是用来做限流、隔离、降级、熔断的功能。本质要做的就是统计数据和规则判断

1. 雪崩问题

在微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,称为雪崩

解决雪崩问题的常见方式有四种

  • 1、超时处理: 设定超时时间,请求超过时间没有响应就返回错误信息,不会无休止等待。新的超时连接数/s 大于 释放的超时连接数/s 时,还是会雪崩
  • 2、舱壁模式: 限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。完全解决雪崩,但是资源利用不好
  • 3、熔断降级: 由熔断器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。完全解决雪崩
  • 4、流量控制: 限制业务访问的QPS(每秒钟处理的请求数量),避免服务因流量的突增而故障。根源解决雪崩,使用的是Sentinel

  1. 服务保护技术对比

Sentinel读 sēn tǐ nǒu,Hystrix读 hēi sǐ trǐ kě

|---------|---------------------------------|------------------------------|
| | Sentinel | Hystrix |
| 隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
| 熔断降级策略 | 基于慢调用比例或异常比例 | 基于失败比率 |
| 实时指标实现 | 滑动窗口 | 滑动窗口 (基于 RxJava) |
| 规则配置 | 支持多种数据源 | 支持多种数据源 |
| 扩展性 | 多个扩展点 | 插件的形式 |
| 基于注解的支持 | 支持 | 支持 |
| 限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
| 流量整形 | 支持慢启动、匀速排队模式 | 不支持 |
| 系统自适应保护 | 支持 | 不支持 |
| 控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
| 常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC | Servlet、Spring Cloud Netflix |

3. 认识Sentinel

Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址:https://sentinelguard.io/zh-cn/index.html

Sentinel 具有以下特征:

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

4. 安装启动Sentinel

sentinel官方提供了UI控制台,方便我们对系统做限流设置

sentinel-dashboard-1.8.1.jar  下载: https://cowtransfer.com/s/14e414d742ae4b

在D盘新建sentinel-dashboard目录,把下载的jar包粘贴进sentinel-dashboard目录,输入CMD如下

d:
cd sentinel-dashboard
java -jar sentinel-dashboard-1.8.1.jar

localhost:8080

登录sentinel控制台

修改sentinel的默认端口、用户、密码

|----------------------------------|----------|-------|
| 配置项 | 默认值 | 说明 |
| server.port | 8080 | 服务端口 |
| sentinel.dashboard.auth.username | sentinel | 默认用户名 |
| sentinel.dashboard.auth.password | sentinel | 默认密码 |

java -jar sentinel-dashboard-1.8.1.jar -Dserver.port=8090 #这条命令我这边运行是无效的,指定不了端口

java -jar sentinel-dashboard-1.8.1.jar --server.port=8090

5. 微服务整合sentinel

提供了一个写好的cloud-demo微服务项目,下载后解压得到cloud-demo文件夹,里面有两个sql文件,导入进自己的数据库

https://cowtransfer.com/s/acdf30714d5741

cloud-demo项目结构如下图

第一步: 用idea打开cloud-demo微服务项目,修改application.yml的数据库连接信息

第二步: 本地启动nacos注册中心(默认是8848端口)。m表示启动模式,standalone表示单机启动。除了单机启动模式,还有集群启动的模式

第三步: 为避免端口冲突,关闭sentinel,重新启动sentinel(指定为8090端口)

java -jar sentinel-dashboard-1.8.1.jar -Dserver.port=8090 #这条命令我这边运行是无效的,指定不了端口
java -jar sentinel-dashboard-1.8.1.jar --server.port=8090

第四步: 先运行nacos注册中心运行cloud-demo微服务项目的UserApplication(8081端口)、OrderApplication(8088端口)、GatewayApplication(10010端口)引导类

第四步: 浏览器访问

http://localhost:8081/user/3

第五步: 在order-service中整合sentinel,并且连接sentinel的控制台。需要在order-service的pom.xml添加如下

<!--整合sentinel-->
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

第六步: 在order-service中整合sentinel,并且连接sentinel的控制台。需要在order-service的application.yml添加如下

spring:
 cloud:
	# 配置sentinel
    sentinel:
      transport:
        dashboard: localhost:8090 # 你启动sentinel控制台jar包的端口,默认是8080,但是我设置成了8090

第七步: 重新运行order-service的OrderApplication引导类

第八步: 浏览器访问(多访问几次,等下sentinel监控曲线会更明显)order-service微服务的任意端点(也就是任意地址),触发sentinel监控

第九步: 浏览器访问sentinel控制台,查看是否能监控到order-service微服务项目,也就是order-service有没有整合sentinel成功

如果你order-service被访问的少,或者没访问量,那么上图的 '实时监控' 曲线不显示,解决就是使劲访问你的order-service,例如访问下面那个地址

下面我们会详细学习如何使用sentinel的控制台,去管理我们的order-service项目

6. 限流规则-直接模式

簇点链路:

就是项目内的调用链路,链路中被监控的每个接口就是一个资源。默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源

流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后面的按钮来设置规则,如下图

案例: 给 /order/{orderId}这个资源设置流控规则,QPS不能超过 5。然后利用jemeter测试

第一步: 浏览器访问sentinel控制台,并设置 '流控' 规则,也就是流量控制

第二步: 第一种测试方法。疯狂访问http://localhost:8088/order/101。需要1秒钟手点5次

第三步: 第二种测试方法。下一节来学

7. jmeter测试工具

jmeter 读 jēi mī tě。 使用jmeter测试工具。jmeter下载如下

下载之后解压,在bin目录中找到 jmeter.properties,添加下面配置

然后打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter

为了方便,我们下载下面这个文件,下载到桌面,然后用jemeter打开这个文件

下载并配置好jmeter之后,紧接着上一节的测试

8. 限流规则-关联模式

1、启动nacos(默认8848端口)。在命令行输入如下。m表示启动模式,standalone表示单机启动。除了单机启动模式,还有集群启动的模式

d:
cd D:\Nacos\nacos\bin
startup.cmd -m standalone

2、启动sentinel(指定为8090端口)

d:
cd sentinel-dashboard
java -jar sentinel-dashboard-1.8.1.jar --server.port=8090

3、运行cloud-demo微服务项目的UserApplication(8081端口)、OrderApplication(8088端口)、GatewayApplication(10010端口)引导类

4、浏览器访问(多访问几次,等下sentinel监控曲线会更明显)order-service微服务的任意端点(也就是任意地址),触发sentinel监控

5、sentinel监控。浏览器访问 http://localhost:8090

在添加限流规则时,点击高级选项,可以选择三种流控模式,分别是直接模式、关联模式、链路模式

  • ●直接: 统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式 (我们在 '6. 限流规则' 演示的,默认就是直接模式)
  • ●关联: 统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流 ○使用场景:比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是有限支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流
  • ●链路: 统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流 ○使用场景: 只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值

演示其中的关联 模式,需求如下

1、在OrderController新建两个端点:/order/query和/order/update,无需实现业务

2、配置流控规则,当/order/ update资源被访问的QPS超过5时,对/order/query请求限流

具体操作如下

第一步: 在order-service的OrderController添加如下

@GetMapping("/query")
public String queryOrder(){
	return "查询订单成功";
}

@GetMapping("/update")
public String updateOrder(){
	return "更新订单成功";
}

第二步: 重新运行OrderApplication引导类,然后浏览器访问 http://localhost:8088/order/query

第三步: 浏览器访问sentinel控制台 http://localhost:8090/

第四步: 添加流控规则,选择关联模式

第五步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter

第六步: 查看jmeter的请求情况

第七步: 查看被关联的那个服务,也就是去访问一下 order/query,看有没有被限流

总结: 什么时候需要在限流规则里使用 '关联模式'

  • 1、两个有竞争关系的资源
  • 2、一个优先级高,另一个优先级低,当优先级高的被大量访问时,对限流优先级低的那个做限流

9. 限流规则-链路模式

在添加限流规则时,点击高级选项,可以选择三种流控模式,分别是直接模式、关联模式、链路模式

●直接: 统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式 (我们在 '6. 限流规则' 演示的,默认就是直接模式)

●关联: 统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流

○使用场景:比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是有限支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流

●链路: 统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

○使用场景: 只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值,例如有两条请求

链路: /test1 -> /common、/test2 -> /common。只希望统计从 /test2 进入到 /common 的请求

演示其中的链路模式,需求如下

需求: 有查询订单和创建订单业务,两者都需要查询商品。针对从查询订单进入到查询商品的请求统计,并设置限流

具体步骤如下

1、在OrderService中添加一个queryGoods方法,不用实现业务

2、在OrderController中,改造/order/query端点,调用OrderService中的queryGoods方法

3、在OrderController中添加一个/order/save的端点,调用OrderService的queryGoods方法

4、给queryGoods设置限流规则,从/order/query进入queryGoods的方法限制QPS必须小于2

具体操作如下

第一步: 在order-service的OrderService类添加如下

@SentinelResource("goods")
public void xxqueryGoods(){
	System.out.println("查询商品");
}

第二步: 在order-service的application.yml修改一下

web-context-unify: false # 关闭context整合

第三步: 在order-service的的OrderController类的xxqueryOrder、xxupdateOrder方法修改为如如下

@GetMapping("/query")
public String xxqueryOrder(){
    //查询商品
	orderService.xxqueryGoods();
	System.out.println("查询订单");
	return "查询订单成功";
}

@GetMapping("/save")
public String xxsaveOrder(){
    //查询商品
    orderService.xxqueryGoods();
    System.out.println("新增订单");
    return "新增订单成功";
}

@GetMapping("/update")
public String xxupdateOrder(){
    return "更新订单成功";
}

第四步: 重新运行OrderApplication引导类,然后浏览器访问 http://localhost:8088/order/query、save

第五步: 在浏览器的sentinel添加限流规则,模式为链路模式

第六步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter

第七步: 查看jmeter的请求情况

10. 流控效果-预热模式

流控效果是指请求达到流控阈值时应该采取的措施,包括三种

  • ●快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。默认是这种
  • ●warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值
  • ●排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长

warm up也叫预热模式,是应对服务冷启动的一种方案。请求阈值初始值是 threshold / coldFactor,持续指定时长后,逐渐提高到threshold值。而coldFactor的默认值是3。例如,我设置QPS的threshold为10,预热时间为5秒,那么初始阈值就是 10 / 3 ,取整之后也就是3,然后在5秒后逐渐增长到10

需求: 给/order/{orderId}这个资源设置限流,最大QPS为10,利用warm up效果,预热时长为5秒。具体操作如下

第一步: 浏览器打开sentinel,在 /order/{orderId} 设置流控规则。

如果没有找到 /order/{orderId} ,就先疯狂访问http://localhost:8088/order/101,触发sentinel

第二步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter

第三步: 查看jmeter的请求情况

11. 流控效果-排队等待

当请求超过QPS阈值时,快速失败和warm up 会拒绝新的请求并抛出异常。而排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝

例如:QPS = 5,意味着每200ms处理一个队列中的请求;timeout = 2000,意味着预期等待超过2000ms的请求会被拒绝并抛出异常

案例: 给/order/{orderId}这个资源设置限流,最大QPS为10,利用排队的流控效果,超时时长设置为5s。具体操作如下

第一步: 浏览器打开sentinel,在 /order/{orderId} 设置流控规则

第二步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter

第三步: 查看jmeter的请求情况

12. 热点参数限流

之前的限流是统计访问某个资源的所有请求,判断是否超过QPS阈值。而热点参数限流是分别统计参数值相同的请求,判断是否超过QPS阈值

需求: 给/order/{orderId}这个资源添加热点参数限流,规则如下

1、默认的热点参数规则是每1秒请求量不超过2

2、给102这个参数设置例外:每1秒请求量不超过4

3、给103这个参数设置例外:每1秒请求量不超过10

具体操作如下

第一步: 由于热点 '参数限流' 对默认的SpringMVC资源无效,所以我们要先去order-service项目的OrderController类的queryOrderByUserId方法添加如下注解

@SentinelResource("hot")

第二步: 重新运行OrderApplication引导类,然后浏览器访问 http://localhost:8088/order/101,触发sentinel

第三步: 浏览器打开sentinel,在 /order/{orderId} 设置热点规则

第四步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter

第五步: 查看jmeter的请求情况

总结: 热点参数限流是一种更细粒度的限流,可以精细到参数级别,如果有更细粒度限流的需求,就可以使用热点参数限流

高级篇-sentinel隔离和降级

  • 1、启动nacos(默认8848端口)。在命令行输入如下。m表示启动模式,standalone表示单机启动。除了单机启动模式,还有集群启动的模式

    d:
    cd D:\Nacos\nacos\bin
    startup.cmd -m standalone

  • 2、启动sentinel(指定为8090端口)

    d:
    cd sentinel-dashboard
    java -jar sentinel-dashboard-1.8.1.jar --server.port=8090

  • 3、运行cloud-demo微服务项目的UserApplication(8081端口)、OrderApplication(8088端口)、GatewayApplication(10010端口)引导类

  • 4、浏览器访问(多访问几次,等下sentinel监控曲线会更明显)order-service微服务的任意端点(也就是任意地址),触发sentinel监控

    http://localhost:8088/order/101

  • 5、sentinel监控。浏览器访问 http://localhost:8090

  • 6、启动jemeter

    d:
    cd D:\apache-jmeter-5.4.1\bin
    jmeter.bat

1. Feign整合Sentinel

虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了

不管是线程隔离还是熔断降级,都是对客户端(调用方)的保护,避免坏的微服务拖垮

SpringCloud中,微服务调用都是通过Feign来实现的,因此做客户端保护必须整合Feign和Sentinel。整合的具体操作如下

第一步: 在order-service项目的application.yml添加如下,开启Feign的Sentinel功能

feign:
  sentinel:
    enabled: true #开启Feign的sentinel功能

第二步: 在feign-api项目的clients目录新建fallback.UserClientFallbackFactory类,实现FallbackFactory工厂

package cn.itcast.feign.clients.fallback;

import cn.itcast.feign.clients.UserClient;
import cn.itcast.feign.pojo.User;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;


//实现FallbackFactory接口,泛型是我们关联的Feign客户端接口,也就是UserClient
@Slf4j
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable throwable) {
        ///创建UserClient接口实现类,实现其中的方法,编写失败降级的处理逻辑
        return new UserClient() {
            @Override
            //在这个方法里面编写降级的逻辑,可以是返回友好的提示,也可以是返回默认结果
            public User findById(Long id) {
                log.error("查询用户异常",throwable);
                //返回空的用户对象
                return new User();
            }
        };
    }
}

第三步: 把刚刚的UserClientFallbackFactory类注册为一个bean。在feign-api项目的DefaultFeignConfiguration类添加如下

@Bean
public UserClientFallbackFactory userClientFallbackFactory(){
	return new UserClientFallbackFactory();
}

第四步: 在feign-api项目的UserClient接口的FeignClient注解添加如下

fallbackFactory = UserClientFallbackFactory.class

第五步: 重启order-service项目

第六步: 多访问几次 http://localhost:8088/order/101,触发sentinel

第七步: 浏览器访问sentinel页面 http://localhost:8090/

2. 线程隔离

先把上面那节做完,再做这一节

线程隔离有两种方式实现

  • 线程池隔离
  • 信号量隔离(Sentinel默认采用)

两种线程隔离方式的区别如下表。
扇出: 依赖的服务越多、扇出就越高、调用的就越多,线程要开启的就越多,消耗就越大。例如网关的扇出就很高

|----|----------------------|-----------------|
| | 信号量隔离 | 线程池隔离 |
| 优点 | 轻量级,无额外开销 | 支持主动超时、支持异步调用 |
| 缺点 | 不支持主动超时、异步调用 | 线程的额外开销比较大 |
| 场景 | 高频调用、高扇出的时候适合使用信号量隔离 | 低扇出的时候适合使用线程池隔离 |

Sentinel如何实现信号量隔离(是线程隔离的其中一种方式),相关概念如下

1、QPS:就是每秒的请求数,在快速入门中已经演示过

2、线程数:是该资源能使用用的tomcat线程数的最大值。也就是通过限制线程数量,实现舱壁模式

需求: 给UserClient的查询用户接口设置流控规则,线程数不能超过 2。然后利用jmeter测试。具体操作如下

第一步: 浏览器访问sentinel页面 http://localhost:8090/

第二步: 启动jmeter(读 jēi mī tě)。打开里面bin目录的jmeter.bat文件,即可运行,运行期间不要关闭黑窗口,会弹出一个可视化页面来操作jemeter

第三步: 查看jmeter的请求情况。虽然后面几个没报错,但是本质是报错的,只是被我们降级处理过,如可去idea看降级的处理代码

第四步: 由于在feign-api项目的UserClient接口添加了降级策略,所以当线程超出的时候,不会报错,而是会走UserClientFallbackFactory类写好的降级方法,也就是findById方法。如下图

3. 熔断降级

熔断降级是解决雪崩问题的重要手段。其思路是由断路器(也叫状态机,包含下图的三个状态Closed、Open、Half-Open)统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。Sentinel如何实现熔断降级

断路器熔断策略有三种:慢调用、异常比例、异常数

4. 熔断降级-慢调用

慢调用:业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。'调用' 也叫 '慢调用比例'

上图表示: RT超过500ms的调用是慢调用,统计最近10000ms内的请求,如果请求量超过10次,并且慢调用比例不低于0.5,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试

需求: 给 UserClient的查询用户接口设置降级规则,慢调用的RT阈值为50ms,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5

具体操作如下

第一步: 为了触发慢调用规则,我们需要修改UserService中的业务,增加业务耗时。把user-service项目的UserController类的queryById方法修改为如下

@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id,
		@RequestHeader(value = "Truth", required = false) String truth) throws InterruptedException {
        
	if(id == 1){
		//休眠,触发熔断
		Thread.sleep(60);
	}
    return userService.queryById(id);
}

第二步: 重新启动user-service的UserApplication引导类,访问UserService中id为1的数据,看一下是否是会慢60毫秒

第三步: 浏览器访问sentinel页面 http://localhost:8090/,设置降级规则

第四步: 测试。浏览器不断刷新http://localhost:8088/order/101

5. 熔断降级-异常比例或异常数

上面刚学的慢调用,总结就是只要你请求的数据出现慢返回的情况,sentinel就会熔断该请求对应的服务。下面要学的异常比例,也就是只要你请求的数据出现多次返回异常的情况,sentinel就会熔断该请求对应的服务。'异常数' 也叫 '异常比例'

异常比例或异常数:统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断

上面两张图是同样的作用,也就是 '异常比例' 和 '异常数',其实只有一个地方的区别,一个是填小数(占总比例),另一个是填整数(填多少是多少)

上面两张图的作用是: 统计最近1000ms内的请求,如果请求量超过10次,异常次数超过4次,则触发熔断,熔断时长为5秒。然后进入half-open状态,放行一次请求做测试

需求: 给 UserClient的查询用户接口设置降级规则,统计时间为1秒,最小请求数量为5,失败阈值比例为0.4,熔断时长为5。具体操作如下

第一步: 为了触发异常统计,我们需要修改UserService中的业务,抛出异常。把user-service项目的UserController类的queryById方法修改为如下

@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id,
@RequestHeader(value = "Truth", required = false) String truth) throws InterruptedException {
	if(id == 1){
		//休眠,触发熔断
		Thread.sleep(60);
    } else if(id == 2){
		//当查询UserService微服务id=2的数据时,就抛一次异常
		throw new RuntimeException("故意出错,作用是触发熔断");
	}
	return userService.queryById(id);
}

第二步: 重新启动user-service的UserApplication引导类,访问UserService中id为2的数据,看一下是否是会报异常导致查不出数据

第三步: 浏览器访问sentinel页面 http://localhost:8090/,设置降级规则

第四步: 测试。浏览器不断刷新http://localhost:8088/order/102,访问5次以上

高级篇-sentinel授权规则

  • 1、启动nacos(默认8848端口)。在命令行输入如下。m表示启动模式,standalone表示单机启动。除了单机启动模式,还有集群启动的模式

    d:
    cd D:\Nacos\nacos\bin
    startup.cmd -m standalone

  • 2、启动sentinel(指定为8090端口)

    d:
    cd sentinel-dashboard
    java -jar sentinel-dashboard-1.8.1.jar --server.port=8090

  • 3、运行cloud-demo微服务项目的UserApplication(8081端口)、OrderApplication(8088端口)、GatewayApplication(10010端口)引导类

  • 4、浏览器访问(多访问几次,等下sentinel监控曲线会更明显)order-service微服务的任意端点(也就是任意地址),触发sentinel监控

    http://localhost:8088/order/101

  • 5、sentinel监控。浏览器访问 http://localhost:8090

  • 6、启动jemeter

    d:
    cd D:\apache-jmeter-5.4.1\bin
    jmeter.bat

1. 授权规则

授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式

  • 白名单:来源 (origin) 在白名单内的调用者允许访问
  • 黑名单:来源 (origin) 在黑名单内的调用者不允许访问

案例: 给/order/{orderId} 配置授权规则。具体操作如下

第一步: 在order-service项目的cn.itcast.order目录新建sentinel.HeaderOriginParser类,写入如下

package cn.itcast.order.sentinel;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;


@Component
//新建的这个类要去实现RequestOriginParser接口
public class HeaderOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest xxrequest) {
        //尝试获取请求头
        String y_origin = xxrequest.getHeader("yyorigin");
        //非空判断
        if(StringUtils.isEmpty(y_origin)){
            //如果请求头为空,就给一个默认的值,避免为空
            y_origin="blank";
        }
        //有请求头的话,就下一行return返回
        return y_origin;
    }
}

第二步: 在gateway项目的application.yml添加如下,例如网关的过滤器给请求加一个请求头叫yyorigin,值是yyorigin_value

- AddRequestHeader=yyorigin,yyorigin_value #所有经过网关的请求都会带上yyorigin请求头,值是yyorigin_value

第三步: 重启GatewayApplication引导类、OrderApplication引导类

第四步: 浏览器访问sentinel页面 http://localhost:8090/,设置授权规则

第五步: 测试。访问 http://loalhost:8088/order/101,查看从浏览器直接访问是否被允许访问

第六步: 测试。访问 http://localhost:10010/order/101,查看从网关访问是否被允许访问

如果还是不行就访问 http://localhost:10010/order/101?authorization=admin

2. 自定义异常结果

在前面所有不符合我们在sentinel指定的规则的请求,都会在页面报错,但是报错不雅观,而且不管是什么问题都是同一个报错页面在浏览器

下面我们将学习自定义异常,默认情况下,发生限流、降级、授权拦截时,都会抛出异常到调用方。如果要自定义异常时的返回结果,需要实现BlockExceptionHandler接口。而BlockException包含很多个子类,分别对应不同的场景

|----------------------|-----------|
| 异常 | 说明 |
| FlowException | 限流异常 |
| ParamFlowException | 热点参数限流的异常 |
| DegradeException | 降级异常 |
| AuthorityException | 授权规则异常 |
| SystemBlockException | 系统规则异常 |

具体操作如下

第一步: 在order-service项目的sentinel目录新建SentinelExceptionHandler类,写入如下

package cn.itcast.order.sentinel;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
//在这个类实现BlockExceptionHandler接口
public class SentinelExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        String msg = "未知异常";
        int status = 429;

        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            status = 401;
        }

        response.setContentType("application/json;charset=utf-8");
        response.setStatus(status);
        response.getWriter().println("{\"msg\": " + msg + ", \"status\": " + status + "}");
    }
}

第二步: 重新启动OrderApplication引导类

第三步: 浏览器访问sentinel页面 http://localhost:8090/,设置一些规则

第四步: 查看这次的错误页面长什么样

  1. 规则持久化

在前面学习的所有为sentinel配置规则时,只要是服务重启,那么规则就失效,需要重新配置一次,原因是sentinel默认会把这些规则保存在内存里,当重启的时候就丢失了。下面就来学如何让规则持久化的相关知识,分几节来学

3.1. 规则管理模式

Sentinel的控制台规则管理有三种模式

|---------|------------------------------------------------------------------------------------------------------------|----------------|-----------------------------------|
| 推送模式 | 说明 | 优点 | 缺点 |
| 原始模式 | API 将规则推送至客户端并直接更新到内存中,扩展写数据源,默认就是这种 | 简单,无任何依赖 | 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 |
| Pull 模式 | 扩展写数据源,客户端主动向某个规则管理中心定时轮询拉取规则,,这个规则中心可以是RDBMS文件 | 简单,无任何依赖;规则持久化 | 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题 |
| Push 模式 | 扩展读数据源,规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源 | 规则持久化;一致性 | 引入第三方依赖 |

原始模式: 控制台配置的规则直接推送到Sentinel客户端,也就是我们的应用。然后保存在内存中,服务重启则丢失

pull模式: 控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则

push模式: 控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新

3.2. 实现push模式

push模式实现最为复杂,依赖于nacos,并且需要改在Sentinel控制台。整体步骤如下:

  • 1、修改order-service服务,使其监听Nacos配置中心
  • 2、修改Sentinel-dashboard源码,配置nacos数据源
  • 3、修改Sentinel-dashboard源码修改前端页面
  • 4、重新编译、打包-dashboard源码

具体操作如下

第一步: 在order-service的pom.xml添加如下,作用是引入sentinel监听nacos的依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

第二步: 在order-service中的application.yml修改相关配置为如下,作用是配置nacos地址及监听的配置信息

spring:
  cloud:
    sentinel:
      datasource:
        flow:
          nacos:
            server-addr: localhost:8848 # nacos地址
            dataId: orderservice-flow-rules
            groupId: SENTINEL_GROUP
            rule-type: flow # 还可以是:degrade、authority、param-flow

第三步: 重新启动OrderApplication引导类

第四步: 下载sentinel-dashboard.jar包。下载到你的sentinel目录,例如我的是 'D:\sentinel-dashboard'

https://cowtransfer.com/s/26e336459c5247

第五步: 停止官方sentinel的运行,去运行上面你下载的这个sentinel。注意启动时Nacos要修改成你的Nacos地址,sentinel启动端口自定义为8090

d:
cd sentinel-dashboard
java -jar sentinel-dashboard.jar --nacos.addr=localhost:8848 --server.port=8090

第六步: 浏览器访问sentinel页面 http://localhost:8090

如果进入什么都没有,就访问 http://localhost:8088/order/101,多访问几次触发sentinel,然后再回来访问就行了

第七步: 在sentinel添加一个流控规则(限流规则),注意必须在 '流控规则-NACOS' 加才行

第八步: 浏览器访问nacos页面

第九步: 测试。验证这个流控规则有没有生效。疯狂访问 http://localhost:8088/order/101,超出1秒1次就会限流,我们在第七步设置的QPS为1

第十步: 测试。重启order-service项目服务(重启OrderApplication),看一下流控规则还会不会生效

也就是我们通过实现push模式,实现了规则持久化

相关推荐
爱加瓦小瑞小瑞2 小时前
Sentinel服务保护
sentinel
转测试啦转测试啦4 天前
Redis哨兵(sentinel)
redis·sentinel·php
wclass-zhengge5 天前
SpringCloud篇(服务保护 - Sentinel)
spring·spring cloud·sentinel
cui_win9 天前
Redis高可用-Sentinel(哨兵)
redis·bootstrap·sentinel
FIN技术铺11 天前
Redis集群模式之Redis Sentinel vs. Redis Cluster
数据库·redis·sentinel
cyt涛12 天前
Sentinel — 微服务保护
微服务·架构·sentinel·限流·熔断·降级·隔离
ketil2714 天前
Redis - 哨兵(Sentinel)
数据库·redis·sentinel
阿伟*rui15 天前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
茶馆大橘16 天前
微服务系列五:避免雪崩问题的限流、隔离、熔断措施
java·jmeter·spring cloud·微服务·云原生·架构·sentinel
Shenqi Lotus16 天前
Redis-“自动分片、一定程度的高可用性”(sharding水平拆分、failover故障转移)特性(Sentinel、Cluster)
redis·sentinel·cluster·failover·sharding·自动分片·水平拆分