news 2026/2/26 10:33:08

SpringCloud —— Sentinel详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringCloud —— Sentinel详解

一、前言

在前面的课程中,我们可以发现一个问题,就是即使是低耦合的微服务架构,在微服务和微服务之间依然是有耦合的,比如相互之间的远程调用,这就导致一个微服务出现异常(不一定是崩溃,也有可能是请求处理速度变慢,响应时间过长),另一个微服务也会受到影响,同时,在调用链上的其他微服务也有可能受到影响,所以这是一个安全问题,我们在这里会给出几种方式用于解决这个问题。

二、Sentinel

Sentinel是一个中间件,可以通过流量控制、线程隔离、服务熔断的方式来降低异常发生后的风险。

1.快速入门

首先要在官网下载Sentinel,然后解压,在无中文的目录中使用命令行打开,命令如下:

java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

从这里就可以看出,我们是直接在windows上启动的Sentinel,但是Sentinel的客户端是使用SpringBoot开发的,最终启动后会占用tomcat默认的8080端口,在同一台电脑中,我们的项目网关端口也是8080,所以端口会冲突。

解决办法有两个,第一是用上述配置,在启动时更改端口号为8090,第二是在虚拟机中的docker容器中启动,这样就只会占用宿主机的8080端口。

这里我们选用前一种,比较快捷直观,而且由于之前我把项目也部署到docker容器中了,所以即使将Sentinel放到docker中,也有可能会出现端口冲突的问题。

启动后通过访问8090端口可以看到Sentinel的页面:

向需要进行微服务保护的微服务导入依赖:

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

配置Sentinel:

spring: cloud: sentinel: transport: dashboard: localhost:8090 # sentinel的控制台地址 http-method-specify: true # 是否设置请求方式作为资源名称

在访问一次购物车页面后就可以看得到购物车微服务的服务名称了:

2.流量限制

首先要了解请求被处理的流程:先建立连接,然后再排队,最后被处理

为什么要限制流量?

因为流量会影响请求的响应速度,导致用户使用时会很“卡”,如果流量不被限制,并且变得太大时,SpringBoot默认的Tomcat线程池中的工作线程会被占满,新的请求就只能去排队了,而等待队列如果也被占满了,将会导致新请求被拒绝,这样用户就会完全无法访问网页了。

那为什么会影响响应速度呢?

因为请求超过处理能力后,会自动排队,这就导致许多请求无法被及时处理,也就是:

正常:响应时长=请求被处理的时长

过多:响应时长=请求被处理的时长+排队等待的时长

我们这里为了模拟服务响应超时,我们修改代码,让请求处理时长增加,从而尽可能让更多线程去排队:

@ApiOperation("根据id批量查询商品") @GetMapping public List<ItemDTO> queryItemByIds(@RequestParam("ids") List<Long> ids){ //TODO 模拟业务延迟 ThreadUtil.sleep(500); return itemService.queryItemByIds(ids); }

同时我们将Tomcat的最大线程处理数降低,等待队列的线程数降低,同时将最大连接数降低。

tomcat: threads: max: 25 accept-count: 25 max-connections: 100

这里限制这三个参数就是为了限制请求的处理,也就是降低Tomcat处理请求的能力,让Tomcat线程池尽快饱和,从而模拟大用户量的场景。

接下来,正式开始流量限制,首先先设置流量限制,我们这里配置访问购物车的流量限制:

然后我们使用测试软件jmeter模拟大用户量的情况:

开始测试,我们可以看到,异常率接近百分之四十,这是因为我们限制的流量是每秒6个,而测试案例是每秒十个(1000/100),所以平均每秒会有4个请求被抛出异常429。

在测试过程中,我们自己也访问购物车来测试,发现延迟在522ms,这说明我们访问购物车的时间是没变的,所以流量限制的好处:通过限制请求处理量,来保障被处理请求的质量。

3.线程隔离

线程隔离是指:在线程池中分配指定量线程给某个微服务,如果这个微服务异常,只会影响被分配的几个线程,其他线程不被影响,从而让其他和本微服务无耦合的微服务(不远程调用异常微服务的其他微服务)正常运行。

购物车中有一个功能是增加商品数量,这个是通过远程调用实现的,和购物车查询无关,如果我们将购物车查询功能线程隔离,那按道理说,即使查询异常,也不会影响增加商品的功能。

接下来尝试模拟这个场景:

一样的设置步骤,对于查询购物车的GET请求,在流控中选择并发线程数,我们这里设置为5:

这里我们设置测试的配置:

开始测试后,我们尝试增加商品到购物车,我们会发现,购物车是查不出来了,但是我们增加商品数量是不被影响的。

4.Fallback

我们先前的购物车微服务会远程调用ItemClient,如果远程调用失败就会抛异常,从而影响购物车的功能,Fallback指的是回退,其实就是一个备用方案,如果ItemClient远程调用异常,那么这个时候就会自动进入回退流程,重新创建一个远程调用对象,这个新对象中会重写方法,但是这个方法里面就没有逻辑了,直接返回空,并且报错误日志,这样就可以正常返回了,只是返回的是空,对于用户来讲,这个就不会过多影响其他功能,而报错的日志又对开发人员的维护起到提示作用。

先模拟商品微服务大用户量,方便后续让远程调用异常,从而逼它走fallback策略:

@ApiOperation("根据id批量查询商品") @GetMapping public List<ItemDTO> queryItemByIds(@RequestParam("ids") List<Long> ids){ //TODO 模拟业务延迟 ThreadUtil.sleep(500); return itemService.queryItemByIds(ids); }

首先需要创建一个工厂类,用于生成降级代理对象(替代方案)。

@Slf4j public class ItemClientFallbackFactory implements FallbackFactory<ItemClient> { @Override public ItemClient create(Throwable cause) { return new ItemClient() { @Override public List<ItemDTO> queryItemByIds(Collection<Long> ids) { log.error("查询商品失败:",cause); return CollUtils.emptyList(); } @Override public void deductStock(List<OrderDetailDTO> items) { log.error("扣减商品库存失败:",cause); throw new RuntimeException(cause); } }; } }

然后我们需要将工厂写到配置类中,在远程调用异常的时候生效。

public class DefaultFeignConfig { /** * 配置日志级别 * * @return */ @Bean public Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } @Bean public RequestInterceptor userInfoRequestInterceptor() { return new RequestInterceptor() { @Override public void apply(RequestTemplate requestTemplate) { Long userId = UserContext.getUser(); if (userId != null) { requestTemplate.header("user-info", userId.toString()); } } }; } @Bean public ItemClientFallbackFactory itemClientFallbackFactory(){ return new ItemClientFallbackFactory(); } }

最后将配置类中的工厂方法配置到远程调用接口中去:

@FeignClient(value = "item-service",fallbackFactory = ItemClientFallbackFactory.class) public interface ItemClient { @GetMapping("/items") List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids); @PutMapping("/items/stock/deduct") void deductStock(@RequestBody List<OrderDetailDTO> items); }

这样,我们就可以看到这个远程调用的资源名了,这就意味着我们可以单独对远程调用进行线程隔离了(远程调用和微服务共享一个线程池,所以是有隔离的必要的),隔离后,这个远程调用服务异常就不会对购物车微服务本身产生影响了,同时由于远程调用服务异常,会执行fallback,于是会返回空响应,从而让购物车其他功能不受影响。

我们对购物车进行测试,发现不会出现异常了

同时将响应空值回去。

5.服务熔断

服务熔断通常会和fallback策略一起使用,服务熔断指当远程调用发生异常时,就直接拒绝远程调用的请求了,这个时候远程调用会走fallback策略(此时熔断器处于关闭状态),同时,熔断器会在指定时间后尝试放行一次请求到已经异常的远程调用服务(半开状态)

如果这次请求无异常了,熔断器就会重新启用正常远程调用服务(熔断器恢复打开)。

如果这次请求依旧有异常,就继续等待指定时间,然后再次尝试。

我们对远程调用配置熔断规则,直接在Sentinel中配置:

开始测试,可以看到,这个时候商品远程调用已经异常了,所以执行的是fallback策略:

停止测试后,会发现又恢复了,因为熔断器进入半开状态后又向商品远程调用发出了少量请求,这次由于没有大流量测试了,所以直接通过了,所以熔断器恢复打开状态,远程调用也就不再执行fallback策略了,服务恢复。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/22 12:37:52

49、Bash编程:模式匹配、命令操作与示例代码详解

Bash编程:模式匹配、命令操作与示例代码详解 1. extglob扩展模式匹配运算符 在使用 shopt -s extglob 时,以下运算符会生效。匹配默认区分大小写,但可以使用 shopt -s nocasematch (bash 3.1+)来改变这一特性,该选项会影响 case 和 [[ 命令。 分组 含义 @( …

作者头像 李华
网站建设 2026/2/20 5:07:25

2、深入探索Bash编程:从基础到实用技巧

深入探索Bash编程:从基础到实用技巧 代码获取与结构 代码可从网站(http://www.bashcookbook.com )下载,下载格式为 .tgz 或 .zip 。代码文件通常位于类似 ./chXX/snippet_name 的路径下,其中 chXX 代表章节, snippet_name 是文件名。 “无用的cat使用”探讨…

作者头像 李华
网站建设 2026/2/24 13:08:53

40、计算机日常维护与管理任务实用指南

计算机日常维护与管理任务实用指南 在计算机使用和管理过程中,我们常常会遇到各种任务和问题。本文将为大家介绍一些常见问题的解决方案,涵盖文件重命名、文档查看、文件解压、会话恢复、会话共享、日志记录以及屏幕清理等方面。 1. 批量重命名文件 在实际操作中,我们可能…

作者头像 李华
网站建设 2026/2/14 14:48:11

Kotaemon重排序模型(Re-Ranker)集成教程

Kotaemon重排序模型集成深度指南 在构建企业级智能问答系统时&#xff0c;一个常见的痛点是&#xff1a;即便使用了强大的大语言模型&#xff08;LLM&#xff09;&#xff0c;系统仍可能给出看似合理却与实际政策或知识不符的回答。这种“幻觉”问题在金融、医疗、人力资源等高…

作者头像 李华
网站建设 2026/2/24 22:15:24

Unity学习笔记(二十)PlayerPrefs(一)

目录 PlayerPrefs是什么 存储原理 读取相关 删除数据 PlayerPrefs数据唯一性 PlayerPrefs是什么 是Unity提供的可以用于存储读取玩家数据的公共类 存储原理 PlayerPrefs的数据存储&#xff0c;类似键值对存储&#xff0c;一个键对应一个值 提供了存储3种数据的方法 &am…

作者头像 李华
网站建设 2026/2/18 10:09:21

书籍-严羽《沧浪诗话》

严羽《沧浪诗话》详细介绍 书籍基本信息 书名&#xff1a;沧浪诗话 作者&#xff1a;严羽&#xff08;南宋&#xff09; 成书时间&#xff1a;南宋理宗时期&#xff08;约公元1230-1250年&#xff09; 卷数&#xff1a;1卷&#xff08;分五章&#xff09; 类别&#xff1a;诗歌…

作者头像 李华