【SpringCloud】微服务 Sentinel 详解

Sentinel

Sentinel 是微服务里非常典型的一类保护组件。它负责的是流量管控:当流量突然变大、某个下游接口变慢、异常开始扩散时,系统不要被一路拖垮。

如果说 Spring Cloud 核心概念解决的是"服务怎么拆、怎么找、怎么调",那么 Sentinel 更像是在这些调用链外面再加一层保险。微服务拆开后,请求就不再只经过一个系统,而是会在网关、服务 A、服务 B、数据库、缓存之间层层传递。任何一个点出问题,都有可能变成整条链路的雪崩。

这也是为什么 Sentinel 的知识点看起来很多,既有流控规则,也有热点参数限流、熔断降级、授权规则、FallbackFactory、规则持久化。表面上它们是不同章节,本质上其实都在回答同一个问题:系统变复杂之后,怎么把风险拦在局部,而不是让故障扩散到全局。

主线

  1. 先理解为什么微服务需要限流,以及流控规则怎么配。
  2. 再区分基于 QPS 和基于并发线程数的两种限流思路。
  3. 然后继续往下看流控模式,直接、关联、链路分别适合什么场景。
  4. 再往后是流控效果,warm up 和排队等待本质上是在控制"放行的节奏"。
  5. 当普通流控还不够精细时,就需要热点参数限流。
  6. 如果问题已经不是"流量太大",而是"服务本身变慢、变脆",就要进入熔断降级。
  7. 熔断之后,调用方不能直接报错给用户,所以又引出了 fallbackFallbackFactory 和自定义异常返回结果。
  8. 最后,学习环境里可以靠 Dashboard 临时配规则,但生产环境必须考虑规则持久化,也就是 pull / push 模式。

为什么微服务需要 Sentinel

在微服务里,一个请求可能会先经过网关,再调用订单服务,订单服务再调用户服务、库存服务、支付服务。只要中间有一个节点响应慢了,上游线程就会被占住;如果大量线程一起等待,下游故障很快就会影响到上游。

  • 如果是流量太大,就先做限流。
  • 如果是某个依赖明显不稳定,就做熔断降级。
  • 如果不同来源的请求优先级不同,就做授权控制。
  • 如果请求被拦下来了,就返回一个可控、可读的降级结果。
  • 如果系统已经准备上线,就把这些规则从"内存里的临时配置"变成"可以持久化管理的正式规则"。

一、流量控制

1. 为什么先学流控

Sentinel 最核心的起点就是流量控制。因为很多线上问题,单位时间内进来的请求太多,或者请求处理得太慢,导致系统承受不住。

比如某个查询接口平时每秒只有 20 个请求,数据库完全顶得住。但活动一开始,流量瞬间变成每秒 2000 个请求,这时数据库、线程池、连接池都可能先后被打满。流控做的事,就是在系统快到极限之前,主动拒绝一部分请求,保持系统正常运行。

基于流量控制的算法有木桶算法、漏斗算法和令牌算法。此处不过多展开。

2. 基于 QPS 和基于并发线程数的流控

  • QPS 是每秒请求数,限流策略是限制"请求进入速度"。比如一个接口每秒最多只希望处理 100 次调用,那么就可以基于 QPS 配规则。

  • 并发线程数的限流策略为关注同一时刻有多少请求正在处理中。它适合保护那些执行时间较长、线程占用明显的接口。因为有些接口虽然每秒请求数不高,但每个请求都很慢,此时就要考虑线程占用限制与释放的问题。

3. 流控规则的核心字段

配置流控规则时,不管是在代码里还是在控制台里配置,有几个核心参数是必须了解的

  • resource,针对哪个资源生效,通常就是某个接口、某个方法、某个服务调用点。
  • grade,按什么维度限流,是 QPS 还是并发线程数。
  • count,规定了 QPS 的阈值。
  • strategy,三种流控模式------直接、关联、链路。
  • controlBehavior,超过阈值之后怎么处理,是直接失败、预热还是排队等待。

如果用代码方式理解,一个最基础的流控规则大概长这样:

java 复制代码
FlowRule rule = new FlowRule();
rule.setResource("queryGoods");  # 规定资源
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); # 规定限流规则
rule.setCount(100); # QPS设置为100
FlowRuleManager.loadRules(List.of(rule)); 

这段代码规定资源名叫 queryGoods 的入口,QPS 超过 100 以后就开始限流。

4. 三种流控模式,直接、关联、链路

直接模式

直接模式最好理解,就是"谁超了就限谁"。比如 /goods/list 接口访问量过大,就直接对 /goods/list 做限流。

这种模式适合最常见的单接口保护场景。

关联模式

关联模式的是限制与重要接口相关联的资源

例如订单创建接口和商品查询接口都要访问数据库,秒杀时商品查询量暴增,可能会把数据库资源占满,影响到下单。这时就可以设置,当"商品查询"资源压力过大时,限制"商品查询",把资源留给"下单"这种更重要的业务。

链路模式

链路模式关注的是,同一个资源可能从不同调用入口进入,但这些入口的优先级不一样。

比如一个 queryUser() 方法,既会被普通查询页面调用,也会被下单流程调用。虽然最终访问的是同一个方法,但"下单链路里的 queryUser()"和"普通查询链路里的 queryUser()"业务价值不同。链路模式就能针对某一条调用路径单独限流。

这说明 Sentinel 的资源观念不只是"接口名",而是"接口在整条调用链里扮演什么角色"。

5. 流控效果:快速失败、warm up、排队等待

阈值一旦超了,系统并不一定只有"直接拒绝"这一种做法。 warm up 和排队等待,就是在讨论"限流之后的处理节奏"。

快速失败

快速失败是最直接的方式。超过阈值后,后续请求立刻被拒绝。这种方式实现简单,保护性最强,适合大多数接口。

warm up

warm up 适合服务冷启动的情况,如:资源正在初始化、数据库连接也刚建立,假设这个服务的 QPS 为 100,刚启动时请求就达到阈值,此时服务器的资源还未完全初始化,也有可能服务器的崩溃。

所以 warm up 的思路不是一开始就放开全部流量,而是先给一个较低的通过阈值,然后随着时间逐步升高,线性地升到设定的目标阈值。

排队等待

排队等待适合对"匀速处理"有要求的场景。比如某些写库操作,这时可以让请求先处于队列排队,按稳定节奏通过。

6. 热点参数限流

资源的接口的访问量是不一样的,有些接口访问的频繁,我们称之为热点接口

例如商品详情接口 /goods/{id} 平时很稳,但某个爆款商品 id=1001 突然被全网抢购。这时接口本身不一定超限,真正热点的是参数 1001。如果仍然按接口整体限流,就会误伤所有其他商品请求。

热点参数限流能做到:

  • 同一个接口,不同参数值分开统计。
  • 对高频热点参数单独限流。
  • 必要时还能给某些特定参数配置例外阈值。

也就是说,普通流控解决的是"这个门太多人进",热点参数限流解决的是"门本身没问题,但总有一小撮人疯狂挤同一个窗口"。

7. 限流算法的理解重点

常见限流算法通常有下面几类:

  • 固定窗口 / 滑动窗口

  • 漏桶 / 令牌桶

二、熔断降级

1. 熔断的三种触发条件

慢调用比例

当一个资源的响应时间持续很长,而且慢请求所占比例超过阈值时,就可以触发熔断。

这个规则适合处理接口请求过慢的场景。

异常比例

如果在一个统计窗口内,请求中的异常占比明显超过阈值,就说明这个资源已经处于高风险状态,可以暂时熔断。

这个规则强调的是接口请求失败的比例。

异常数

如果在统计窗口内,异常总数超过阈值时触发熔断。

2. 熔断状态机

状态机用于监控接口

  • CLOSED 表示正常放行,请求可以正常通过。
  • OPEN 表示熔断打开,这段时间内请求不会继续请求目标资源,而是直接走降级逻辑,可能会请求到另外的备用接口。
  • HALF_OPEN 表示半开,也就是给系统一次"试着恢复"的机会。它不会一次性把流量全放开,而是先用少量探测请求看看下游是否真的恢复了。如果恢复了,就回到 CLOSED;如果还是不行,就重新进入 OPEN

三、授权规则与自定义异常返回

1. 授权规则

授权规则关注的是"谁可以访问我",对请求来源进行白名单放行 / 黑名单拦截。

在微服务里,不同来源的请求优先级可能不同。比如某个接口只允许内部服务调用,不允许外部来源直接访问;或者同一个资源,对某些来源放行,对另一些来源拦截。

Sentinel 的授权规则一般会基于 origin 来做判断。你可以把 origin 理解成请求来源标识。规则的本质就是,对资源设置白名单或黑名单,让不同来源得到不同处理。

2. 自定义异常返回结果

当请求被 Sentinel 拦住时,如果直接把原始异常栈丢给前端,用户体验会很差,前端也很难统一处理。所以实际项目里,通常会把"被限流""被降级""被授权拦截"这些情况包装成统一的业务返回。

在 Spring MVC 项目中,常见做法是实现 BlockExceptionHandler

java 复制代码
@Component
public class CustomBlockExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, 
					String resourceName, BlockException e) throws Exception {
        response.setStatus(429);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("code":429,"msg":"当前请求被限流或降级,请稍后再试");
    }
}

四、Fallback 行为与封装接口 FallbackFactory

1. 为什么熔断后还需要 fallback 行为

熔断之后还需要降级逻辑,也就是 fallback。降级逻辑的目标不是把功能完整替代掉,而是在主流程不可用时,提供一个能接受的兜底结果。

2. FallbackFactory

Spring 为我们封装了 FallbackFactory 接口,此实例将在出现任何类型的错误时被调用,任何关于 fallback 的错误降级都可实现这个接口,捕获异常。它可以拿到触发降级的异常对象 Throwable,这样在写兜底逻辑时就有更多上下文。

![[Pasted image 20260521163743.png|713]]

实现栗子🌰

java 复制代码
@FeignClient(name = "user-service", fallbackFactory = UserClientFallbackFactory.class)  # 需声明fallbackFactory
public interface UserClient {
    @GetMapping("/users/{id}")
    String queryUserName(@PathVariable("id") Long id);
}
java 复制代码
@Component
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable cause) {
        return id -> "用户服务暂时不可用,执行了降级逻辑,原因:" + cause.getMessage();
    }
}

五、规则管理与持久化

1. 规则配置

当前的配置文件都是存放于内存中的,重启服务器后规则就没了,且微服务中多台示例部署,每个实例都规则可能都不同,管理配置会非常困难,我们需要平台将规则配置统一管理起来,方便修改同步。

2. pull / push 模式

pull 模式

应用会主动从某个外部规则源读取配置,比如 NacosApolloZooKeeper、文件或数据库。应用更像是规则的消费者,规则中心保存正式配置,应用自己去拉取。

push 模式

控制台或配置中心把规则配置主动推送到已经注册的实例中,实例(服务器)收到后会立刻更新

它的好处是实时性更好,规则修改后生效更快,也更接近真正的集中治理模式。生产环境里都会建议将 Sentinel 规则配置台注册到服务中心如 nacos 上,然后再由 nacos 推送,方便统一管理。

相关推荐
闪电悠米11 小时前
黑马点评短信登录01_session_sms_login
java·spring boot·redis·git·spring·面试
Advancer-11 小时前
黑马点评plus --异步秒杀重构升级
java·spring boot·重构·intellij-idea
Dicky-_-zhang11 小时前
服务网格实战:Istio与Linkerd对比选型与落地实践
java·jvm
云烟成雨TD11 小时前
Spring AI Alibaba 1.x 系列【56】SAA Admin 平台功能介绍
java·人工智能·spring
Gauss松鼠会11 小时前
GaussDB(DWS) 资源监控Topsql
java·网络·数据库·算法·oracle·性能优化·gaussdb
夏日听雨眠11 小时前
数据结构(快速排序)
java·数据结构·算法
字节高级特工11 小时前
C++11(一) 革新:右值引用与移动语义
java·开发语言·c++·人工智能·后端
郝学胜-神的一滴11 小时前
系统设计 012:从用户系统出发,吃透缓存、数据库与高并发设计
java·数据库·python·缓存·php·软件构建
人道领域11 小时前
【LeetCode刷题日记】654.最大二叉树:递归算法详解
java·算法·leetcode