资讯动态

微服务高可用利器:Sentinel限流熔断实战指南

发布时间:2026/9/25 1:26:28 来源:尧图企业网站定制
1. 先想明白Sentinel到底替我们挡什么这几年只要做微服务尤其是Spring Cloud Alibaba这套体系的基本都绕不开Sentinel。它是阿里巴巴开源出来的一个轻量级高可用流量控制组件主打两件事限流和熔断降级。很多第一次接触的人容易把它当成一个配置规则的工具其实它背后解决的是分布式系统里最经典的两个事故场景。先说第一个场景秒杀或者热点活动。你的服务平时每秒撑个几百请求没问题结果活动一开流量直接翻几十倍数据库连接池先被打满然后接口超时超时又占用更多线程最后整台机器卡死。这种情况靠加机器能缓解但加机器要时间而且流量过大时上游负载均衡本身也可能被拖垮。Sentinel做的就是在流量还没打到核心资源之前先把多余的请求挡掉让系统始终运行在它能够承受的范围内。注意限流不是让系统变慢而是主动放弃一部分请求保住整体可用性。第二个场景依赖下游出问题。微服务里A调用BB调用C如果C突然变慢或者报错B的线程会被大量占用然后A调用B也超时整个调用链跟着雪崩。Sentinel的熔断降级就是干这个的它监控下游调用的耗时和异常比例一旦超过阈值就快速失败不再继续傻傻地等待下游同时给你机会返回降级结果比如缓存兜底或者提示文案而不是让用户看到超时错误。如果你之前用过Hystrix会发现Sentinel在功能覆盖上更全面配置也更灵活。Hystrix默认基于线程池隔离每个依赖一个线程池代价是线程开销大Sentinel默认基于并发线程数和QPS做实时统计性能开销低得多还能做到细粒度的热点参数限流、系统自适应保护。做Java后端、Spring Cloud微服务体系尤其是已经上了Nacos、Spring Cloud Alibaba的话Sentinel几乎是必装的一环。下面我按一个入门者的视角把从落地到跑通再到避坑的完整路径捋一遍。2. 五分钟跑起来控制台加客户端是最短的落地路径2.1 控制台启动一条Java命令的事Sentinel最直观的使用方式是配合控制台Dashboard来做可视化规则配置和监控。控制台本质上是一个Spring Boot应用官方直接提供了可执行Jar包。去GitHub的Sentinel Release页面下载sentinel-dashboard-xxx.jar然后执行java -Dserver.port8080 -Dcsp.sentinel.dashboard.serverlocalhost:8080 -Dproject.namesentinel-dashboard -jar sentinel-dashboard-1.8.6.jar启动完成之后浏览器访问http://localhost:8080默认用户名和密码都是sentinel。这里有个小细节-Dcsp.sentinel.dashboard.server这个参数本身是指定控制台地址的启动控制台时也填自己是为了让控制台自己也能被客户端发现。实际生产部署时控制台地址写的是你的服务器IP端口按需调整。2.2 客户端接入配置两行就够如果你的项目用的是Spring Cloud Alibaba接入成本低得惊人。在pom.xml里加上依赖dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-sentinel/artifactId /dependency然后在application.yml里做最短配置spring: application: name: order-service cloud: sentinel: transport: dashboard: localhost:8080 port: 8719transport.dashboard就是控制台地址port是客户端暴露给控制台拉取数据的端口默认8719如果被占用会自动向后探测找可用端口。这时候启动你的Spring Boot项目正常情况下控制台首页的机器列表里会出现这台应用。对就这么点配置Sentinel的启动依赖和自动配置全部帮你处理完了。2.3 一个必须留意的懒加载细节很多新手在这一步就卡住了应用启动后控制台机器列表里啥也没有怀疑自己配置错了。其实大概率没配错只是因为Sentinel的默认行为是懒加载——也就是只有第一次请求访问某个接口时这个资源才会被注册应用才会出现在控制台里。所以接完之后别干等着随便请求几个接口再刷新控制台就能看到。如果你希望应用一启动就主动向控制台注册可以加一行配置spring: cloud: sentinel: eager: true这行配置建议在联调和生产环境都开着。否则你部署了一个新节点半天控制台里看不到排查起来容易自我怀疑。3. 资源和规则Sentinel整套设计的两个支点3.1 资源到底是什么Sentinel里面有个核心概念叫资源Resource它可以是任意一段代码、一个接口、一个方法甚至是一个字符串标识。你用SentinelResource注解标记的方法是一个资源你通过SphU代码埋点包裹的调用链是一个资源Spring Cloud Alibaba还会自动把你所有的Controller接口都注册成资源资源名默认就是接口的URL。资源相当于你想保护的对象规则则是作用在资源上的策略。资源注册好之后Sentinel会对它的实时调用情况做统计比如每秒通过多少请求、最大RT、异常数。这些统计数据的精度非常高因为它用的是滑动窗口来做时间桶计数而不是简单的AtomicLong累加。你可以把它理解成把一分钟切成很多个小时间片每个时间片独立计数窗口每秒滑动一次既能兼顾高并发写入性能又能准确反映实时流量。3.2 规则是打在资源上的开关规则分很多种流控规则、熔断降级规则、热点参数规则、系统保护规则、网关流控规则、授权规则。每种规则的生效逻辑不同但设计思路一致针对某个资源设置条件条件满足就触发保护动作。我在带团队的时候发现很多新人一上来就急着配规则连资源链路都没搞清楚。其实Sentinel是先有资源再谈规则的。资源没注册规则配得再漂亮也是白搭。3.3 规则生效链路请求进来怎么被拦一个请求进来后的大致路径是这样的先到达Sentinel的入口找到对应的资源接着读取该资源的规则列表逐条判断当前请求是否命中规则然后根据命中的规则类型执行对应动作——比如直接抛BlockException、进入排队等待、触发熔断降级逻辑。这里要特别区分两个异常BlockException和业务异常。被Sentinel拦截时抛出的是BlockException它表示的是被限流/被熔断不是代码本身报错而业务异常是RuntimeException之类的。两者在SentinelResource注解里处理方式完全不同后面我详细说。4. 流控规则最常用的流量闸门4.1 阈值类型怎么选QPS还是并发线程数流控规则是Sentinel里干活最多的规则也是新手误解最多的一块。阈值类型有两种QPS和并发线程数。QPS指每秒请求数适合对接口的访问频率做控制比如一个查询接口最多每秒放行50个请求。并发线程数指当前同时占用该资源的线程数量适合处理那些单个请求耗时较长的接口。举个例子你的接口平均耗时200ms一台机器单线程最多每秒处理5个请求如果QPS太高线程就会排队。此时你与其限制QPS不如限制并发线程数让超出的请求快速失败避免线程堆积。实操经验大部分对外接口优先按QPS限流因为QPS直观、容易配合压测数据做估算。耗时波动大的接口比如调用外部第三方服务建议考虑并发线程数否则可能出现QPS不高但线程全被占用的诡异现象。4.2 流控模式直接、关联和链路阈值类型决定你有没有超标的量流控模式决定谁触发限流时管到谁头上。直接模式最直白A接口的QPS超过阈值就限流A接口自己。关联模式有意思假如B接口的QPS超过阈值反过来对A接口限流。这非常适合读写场景。比如订单查询接口A和订单写入接口B写操作压力大时数据库资源紧张你希望优先保障查询接口那就对查询接口配置关联流控关联资源指向写接口。当写接口QPS超标查询接口自动启动限流保护数据库不被写爆。链路模式稍微复杂它按调用来源做限流。最常见的例子是同一个资源被多个上游调用用户端调用和内部定时任务都触达同一个Service方法。你希望限制用户端入口的流量但不想限制定时任务。此时用链路模式入口资源设为Controller层的两个不同方法目标资源设为Service方法针对用户端入口那条链路单独限流。链路模式在配置时需要额外开启spring.cloud.sentinel.web-context-unify: false否则默认会把所有链路入口合并效果就变成全局限流了。这是老手都可能踩的坑新手建议先用直接模式跑通。4.3 流控效果快速失败、预热和排队等待限流条件命中之后接下来是处理策略。快速失败超出阈值的请求直接抛BlockException。这是默认策略也最常用。适合大部分同步接口因为拒绝请求的成本最低。Warm Up预热阈值不是一步到位的而是从初始值逐步增长到设定值过程默认是10秒。这个效果特别适合那些冷启动时需要时间升温的系统比如数据库连接池刚建立、JVM缓存还没热起来一上来就放满量反而容易把系统打垮。我个人强烈建议对刚重启过的核心服务配上Warm Up给系统留出热身时间。排队等待这是最优雅但最少人用的模式。它不拒绝请求而是让请求以固定速率通过超出部分排队等待。默认排队超时时间为500ms超过就不等了。在秒杀这类有大量瞬时流量、且可接受的削峰填谷场景里用排队等待可以防止流量瞬间压垮下游。我做过一个报表导出接口峰值QPS上千但下游数据库只能抗200用排队等待把速率设为200 QPS之后用户体验从请求失败变成最多等几百毫秒效果立竿见影。流控规则的参数配置如下配置项含义推荐场景阈值类型QPS / 并发线程数对外接口用QPS耗时波动大用并发线程流控模式直接 / 关联 / 链路默认直接读写场景用关联多调用方用链路流控效果快速失败 / Warm Up / 排队等待同步接口用快速失败系统冷启动用Warm Up削峰填谷用排队阈值怎么定我建议不要拍脑袋。先跑压测找到系统性能拐点然后留出20%-30%的余量。比如压测发现某接口在QPS 300时RT开始明显上涨那阈值就定200-250再配合Warm Up让系统平滑到达极限。5. 熔断降级规则依赖崩了以后怎么做5.1 三种熔断策略详解熔断降级是Sentinel保护系统周全身的另一个轮子。它的思路是不阻止请求进入而是当你发现这个资源已经出故障时直接跳过它或快速失败。Sentinel 1.8之后提供三种熔断策略慢调用比例。设置一个最大RT比如500ms。滑动窗口内请求数达到最小请求数默认5且慢调用比例超过阈值比如0.6就触发熔断。这个策略对接口变慢但不报错的场景非常有用。我曾经处理过一个下游支付状态查询接口平时RT平均80ms调用方代码有问题后突然变成2s但没有抛异常。用慢调用比例熔断最大RT设500ms比例阈值0.5它就能精准识别这种钝刀子割肉式的恶化。异常比例。窗口内请求数达到最小请求数后异常数占总请求数的比例超过阈值就熔断。适合接口开始大量报错的场景。比如一个接口突然因为某个数据源变化导致大量空指针异常比例飙升到80%熔断就可以立即启动。异常数。窗口内异常数量超过阈值直接熔断。注意这里的最小请求数不会作用于异常数策略也就是说即使请求量很低只要异常数攒够也会熔断。适合高可用要求极高的核心链路宁可错杀不可放过。5.2 熔断之后发生了什么触发熔断后资源会进入打开Open状态此时所有请求都会被拦截快速失败。经过设定的熔断时长默认1000ms后进入半开Half-Open状态Sentinel会放行少量请求探测资源是否恢复。如果探测请求都成功了熔断关闭资源恢复正常如果还是失败重新打开熔断。这里有个细节容易被忽略熔断状态是针对资源而不是针对某个实例或某次调用的。所以在分布式架构下每个实例的熔断状态是独立的A实例熔断了不代表B实例也熔断。判断是否恢复靠的是每个实例自己的半开探测这也就意味着如果下游故障持续你可能会看到各实例熔断时段不一致这是正常现象。5.3 一套比较稳妥的降级参数经验值熔断降级最大的坑就是阈值定得太激进。我有一次把异常比例熔断阈值设成0.1结果一次全链路压测里一个非核心接口抖动触发熔断后大量请求走了降级方法把降级方法依赖的缓存又打满了反而扩大了故障面。给一个相对稳妥的参数参考策略参数参考值慢调用比例最大RT接口压测P99 RT的2-3倍慢调用比例比例阈值0.4-0.6慢调用比例熔断时长5000-10000ms异常比例比例阈值0.2-0.5异常比例最小请求数10-20异常数阈值20-50核心思路是熔断阈值要比你自己的人工报警阈值宽松因为它主要负责兜底而不是第一时间报警。发现的问题交给监控告警熔断负责的是阻止问题继续蔓延。6. 注解接入与异步问题SentinelResource 的正确打开方式6.1 blockHandler 和 fallback以及两者别搞混Spring Cloud Alibaba的自动配置虽然把Controller接口都注册成了资源但更灵活、更精细的控制还是要靠SentinelResource注解来做代码埋点。这个注解有两个核心属性blockHandler和fallback。fallback负责处理业务异常也就是方法本身抛出的RuntimeException。blockHandler负责处理Sentinel拦截产生的BlockException也就是被限流/熔断时触发的逻辑。我见过很多新手的坑在于只配了fallback以为限流之后会自动走降级逻辑结果发现被限流的请求直接抛了BlockException前端报错。原因是两者互不兜底。想要既处理业务异常又处理限流必须同时配置SentinelResource( value order.create, blockHandler createOrderBlockHandler, fallback createOrderFallback ) public Order createOrder(Long userId, Long skuId) { // 业务逻辑 return orderService.create(userId, skuId); } // 注意blockHandler 和 fallback 的方法签名入参要和原方法一致最后可以加一个 BlockException / Throwable 参数 public Order createOrderBlockHandler(Long userId, Long skuId, BlockException ex) { return new Order(); } public Order createOrderFallback(Long userId, Long skuId, Throwable throwable) { return new Order(); }还有一点blockHandler处理的优先级高于fallback。如果同时触发业务异常和限流只会走blockHandler。6.2 异步场景下注解失效问题如果你在CompletableFuture.supplyAsync(() - doSomething())这类异步会签里调用被SentinelResource注解的方法你会发现限流规则完全不生效。这不是你配置错了而是Sentinel原生的注解适配器默认基于ThreadLocal传递上下文异步线程拿不到主线程的调用链入口信息于是资源统计就断掉了。解决方式有两种第一别在异步线程里直接调用注解方法而是在主线程先获取SphU.entry或者AsyncEntry把资源入口上下传到异步线程里去。第二如果你的团队里异步场景特别多建议好好研究一下Sentinel的entry和asyncEntry两个API。asyncEntry是专门为异步场景设计的它把资源统计和调用链解耦统计的是真实的资源调用情况而不是依赖当前线程的上下文。我自己的经验是注解方式适合90%的同步场景价格最便宜但一旦代码里出现线程池、MQ消费、GateWay配异步过滤器就要主动排查一下资源埋点是不是还在生效。系统上线前我一定会拿两三个核心异步链路做一次限流触发验证确认确实拦得住再收工。6.3 热点参数限流的小补充SentinelResource还有一个特别实用的场景热点参数限流。比如同一个商品详情接口普通商品的QPS阈值是100但某个爆款商品的QPS到了1000你想单独对爆款商品的请求参数做限制。用热点参数规则可以做到针对资源goods.detail的第一个参数商品ID单独设置更高或者更低的阈值和参数例外项。热点参数限流需要额外引入sentinel-parameter-flow-control依赖并且这个规则是在专业控制台的热点参数规则里配置不是在普通流控规则里。它非常适用于秒杀场景下的单商品限流单用户限流很多系统能做出来的精准限流都靠它。7. 网关接入Spring Cloud Gateway 用 Sentinel 限流的实践7.1 为什么网关也要限流如果是单机应用只在服务端做流控就够了。但在微服务架构里所有外部流量都要经过网关网关是第一道防线。在网关层限流的好处是过滤掉的请求根本不会到达后端服务节省的是整条链路的资源而不只是某一个被限流接口的线程。Spring Cloud Gateway接入Sentinel也很顺依赖换一下dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-sentinel-gateway/artifactId /dependency这里要注意网关的自动配置和普通Spring MVC应用的自动配置是互斥的。如果你在网关项目里直接引spring-cloud-starter-alibaba-sentinel它不会自动对路由生效因为网关用的不是Servlet模型而是WebFlux模型。7.2 网关维度配置网关接入后你会看到控制台多出两个维度一个叫Route ID维度按路由ID限流一个叫自定义API分组维度按你自定义的API组合限流。Route ID维度最简单在控制台的网关流控规则里选择一条路由直接设置QPS阈值就行。比如/order/**这个Route的QPS阈值设为500超过的请求直接返回默认的429 Too Many Requests。API分组维度的能力更强。比如你希望/order/**和/user/**共享同一个总阈值或者更常见的是你希望把一组内部测试接口统一限流掉可以用API分组把它们归到同一个分组然后对这个分组配置流控。这块我觉得是网关层限流最精髓的地方它不是按URL机械限流而是按业务语义组合限流。7.3 网关流控与业务流控的区别网关限流主要针对入口流量粒度通常较粗一般按路由或API分组来限制好处是统一入口、统一管控。业务流控主要在服务内部粒度更细可以精确到方法和参数比如热点参数规则、关联流控都只能在服务内生效。两层限流没有谁替代谁的关系。最佳实践是两层都上网关层挡住突发洪峰服务层保护性能瓶颈所在的资源。比如秒杀场景网关限流把整体流量降到1w QPS订单服务内部再把订单创建接口的QPS限到3000数据库层的连接池才安全。这就是典型的层层设防。8. 规则不生效与控制台不显示的排错名场面8.1 控制台没出现应用这个现象在接入网关或WebFlux项目时尤其多但我按普通Spring Boot项目讲。按照如下顺序排查看spring.cloud.sentinel.transport.dashboard配置是否有效确认路径走的是/favicon.ico或某个不存在的路径第一次访问触发了注册。检查应用启动日志是否有Sentinel started相关日志。如果看到Sentinel reporter初始化失败多半是8719端口被占用。打开http://localhost:8719/registry?transport.dashboardlocalhost:8080这个地址会返回注册信息。如果注册成功客户端会返回一个JSON格式数据。如果以上都没问题注意一点新版控制台和应用之间的通信是走HTTP的如果你的应用在容器里部署需要确保transport.port8719端口能被控制台所在的机器访问。8.2 规则设置成功却不拦截这是最打击人的一个情况控制台规则配好了资源名也显示在线压测时却发现规则根本没生效。我踩过的坑主要是版本不匹配。服务端Sentinel Core版本和控制台版本不一致会导致控制台推送的规则序列化失败。官方推荐版本尽量保持一致跨大版本比如1.8和2.0一定会有兼容问题。规则没真正下发到客户端。控制台配的规则默认只保存在控制台内存里如果应用重启或者控制台重启规则就丢了。那自然会出现规则配了但过一段又失效的情况。这个问题的根治方案是规则持久化下一小节说。资源配置写错。在注解为资源但URL本身也被自动注册时容易出现你配置的是URL资源但代码里触发的是注解资源两边名字差一点规则就空了。8.3 规则重启就丢持久化方案这是所有用Sentinel的人都绕不开的痛点默认情况下你在控制台里配的规则只存在控制台进程中应用重启、控制台重启规则全部归零。生产环境绝对不能用这种方式管理规则。常见做法有以下几种方案一使用Nacos做规则数据源推模式。在客户端引入数据源扩展dependency groupIdcom.alibaba.csp/groupId artifactIdsentinel-datasource-nacos/artifactId /dependency配置文件里声明spring: cloud: sentinel: datasource: flow: nacos: server-addr: localhost:8848 dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP rule-type: flow这样客户端会启动时从Nacos拉取规则并且监听配置变更规则一变立即生效。这是目前最推荐的持久化方案因为规则可以统一在Nacos管理变更方便。方案二本地文件持久化拉模式。把规则写到本地文件里客户端启动时读取定期检查文件变更。适合不引入配置中心的场景。缺点是多个实例之间规则同步麻烦改一个文件要逐步发布。我自己在实际项目中的体会是如果团队还没有配置中心那就一次性把Nacos上马因为Sentinel规则这种需要全局管理的东西指望本地文件做多实例同步迟早出事故。用Nacos管理之后每次规则调整都有变更记录回滚也方便新接手的同事查规则看Nacos配一下就懂了。最后再分享一个小经验刚开始用Sentinel别贪多先挑两个核心链路配上流控和熔断跑一两周看看统计面板上的指标再慢慢拓展规则。我见过不少人第一天就把所有接口的流控规则全配了结果规则互相打架排查了一整天。Sentinel这东西先跑通你读得懂配置的场景比什么都重要。等你真正遇到一次流量洪峰看着控制台上的拦截曲线稳稳把系统扛住就会理解前面这些配置的价值了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑