news 2026/10/17 6:33:30

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/10/16 7:14:07

开发者的AI破局指南:从困境到实战,3步掌握大模型应用开发

文章指出AI技术将取代大量岗位&#xff0c;开发者面临转型挑战。文章分析了开发者面临的三重障碍&#xff1a;硬件门槛高、启动策略复杂、存在"知识陷阱"。解决方案包括&#xff1a;使用CPU云实例降低硬件门槛&#xff0c;选择RAG作为入门方向&#xff0c;接受系统化…

作者头像 李华
网站建设 2026/10/16 15:33:34

OpenHarmony Linux 环境 SDK 使用说明(进阶--依赖库的解决方法)

OpenHarmony Linux 环境 SDK 使用说明(进阶–依赖库的解决方法) ​ 我们在移植三方库的时候&#xff0c;很多库是有依赖的。面对这种情况我们应该如何处理。下面以libzip为例讲解下如何为ohos编译带依赖的库。 编译libzip 源码准备 下载最新版本的 libzip 和 xz &#xff08;l…

作者头像 李华
网站建设 2026/10/16 17:27:44

深入理解Golang并发模型与CSP理论

lang 在设计上另辟蹊径&#xff0c;其并发哲学的核心信条是&#xff1a;“不要通过共享内存来通信&#xff0c;而要通过通信来共享内存。” (Do not communicate by sharing memory; instead, share memory by communicating.) 这一理念源自通信顺序进程&#xff08;Communicat…

作者头像 李华
网站建设 2026/10/16 10:49:56

48、Linux 命令操作与格式化输出全解析

Linux 命令操作与格式化输出全解析 在 Linux 系统的操作中,有许多实用的命令和操作符,它们能帮助我们更高效地完成各种任务。下面将详细介绍测试操作符、I/O 重定向、 echo 选项与转义序列、 printf 命令以及日期时间格式化等内容。 测试操作符 测试操作符常用于 tes…

作者头像 李华
网站建设 2026/10/16 20:45:53

43、高效Shell操作技巧与实践

高效Shell操作技巧与实践 1. 数据处理与日志记录 在处理数据时,我们经常需要将合适的数据通过管道输入到 while read 循环中,并根据需要使用 printf 进行输出。例如,要打印主机名 $HOSTNAME ,后面跟一个制表符,再跟上 last 命令输出的非空行,可以使用以下命令:…

作者头像 李华
网站建设 2026/10/16 8:51:57

测试技术创新:驱动软件质量的新引擎‌

在软件行业高速发展的今天&#xff0c;测试技术已从传统的手工检查演变为智能、自动化的核心驱动力。随着人工智能、云原生和DevOps实践的普及&#xff0c;测试创新正重塑质量保障体系&#xff0c;帮助从业者应对快速迭代、复杂系统的挑战。本文结合当前行业实践&#xff0c;探…

作者头像 李华