首页 / 资讯中心 / 文章详情

微服务治理实战:Sentinel限流熔断与Nacos持久化全攻略

微服务治理实战:Sentinel限流熔断与Nacos持久化全攻略 ★ FEATURED ARTICLE
微服务跑起来之后第一个让人睡不着觉的问题往往是某个接口突然被刷爆了线程全部卡在数据库查询上紧接着依赖它的上游、下游跟着一起超时整个系统像多米诺骨牌一样开始崩。我之前在团队里负责过一个电商下单链路大促前一天压测的时候一个原本只需要 50ms 的订单接口因为下游库存服务抖动RT 涨到了 3 秒结果不到两分钟就把 Tomcat 线程池打满了紧接着所有接口全部雪崩连健康检查都挂了。那次之后我才真正意识到微服务里不能只有可用性设计还得有流量管控和故障隔离的手段。Sentinel 就是在这个场景里被我用起来的而且越用越觉得它是微服务治理里少有的能把限流、熔断、系统保护三件事一起做好的组件。这篇东西不打算讲源码也不打算堆概念就围绕实际使用场景把 Sentinel 的核心用法、配置方式、Nacos 持久化、控制台运维、常见坑位完整过一遍适合那些已经跑了微服务但还没好好做保护、或者刚刚把 Sentinel 接进 Spring Cloud 项目里的同学参考。1. 微服务为什么必须有 Sentinel 这层保护先说一个我自己的判断微服务架构里服务的数量越多故障的传播半径就越大。单体应用挂了就是挂了最多影响一个功能模块但微服务里一个底层服务抖动可能让上游十几个服务跟着连带超时最后把整个调用链路拖死。这不是危言耸听我之前团队里就出现过一次缓存 Redis 节点故障结果所有依赖缓存的接口全部超时重试把数据库连接池直接压爆整体宕机两个小时。真正经历过这种事故之后你会对保护这个词有完全不一样的理解。1.1 雪崩效应是怎么一步步发生的很多初学者觉得雪崩就是服务 B 挂掉服务 A 也跟着挂。实际上链路是这样的服务 A 调用服务 BB 响应变慢A 的线程就一直在等 B 的响应等不到的线程越积越多A 的线程池被耗尽新请求进入 A 时没有线程可用于是排队甚至直接拒绝下游如果还有 C、D、E 在调用 A他们也会跟着一起等整个调用链路的线程资源被集体占住。这个过程中其实没有任何一台机器宕机但系统就是整体不可用了。Sentinel 在这里能做的事情就是在流量到达某个服务之前先做拦截要么挡掉一部分超出能力的请求要么赶在服务被拖垮之前主动把调用熔断掉避免无效等待。1.2 Sentinel 到底解决了哪些问题抛开官方文档的术语我是从这三个实际痛点来理解的流量不可控接口平时 QPS 几百大促或者被刷的时候可能瞬间冲到几千上万后端的数据库和缓存根本扛不住需要限流保护。依赖不稳定下游服务不是 100% 可靠的缓存会抖动数据库会慢查询外部接口会超时需要用熔断降级来兜底。系统整体的水位不可见单看每个接口都能扛但如果 CPU、负载、内存快满了整个机器上所有接口其实都在危险边缘需要一个系统级别的保护开关。这三个痛点正好对应 Sentinel 的三大能力流量控制、熔断降级、系统自适应保护。这也是我为什么在 Hystrix 和 Sentinel 之间选了后者的核心原因。Hystrix 本身已经停止维护而且它偏重的是熔断和线程隔离对限流这种灵活多变的场景支持很弱Sentinel 的限流模型更丰富有 QPS 限流、并发线程数限流、热点参数限流还有系统自适应保护一条规则就能覆盖很多边缘场景。1.3 Sentinel 的核心概念要先弄清楚用 Sentinel 之前我最想提醒你的一件事是先搞清楚资源和规则这两个词在 Sentinel 里的含义。资源是你要保护的东西可以是一个方法、一个接口、一段代码块。在代码里我们通常用SphU.entry(resourceName)或者SentinelResource(resourceName)把它圈出来。规则是作用于资源的具体保护策略包括限流规则FlowRule、熔断降级规则DegradeRule、系统保护规则SystemRule、热点参数规则ParamFlowRule等。理解这两者关系之后再去配置任何规则都顺了你想保护哪个接口就给哪个资源绑定规则资源不存在规则就没有意义。很多新手配置了半天规则发现不生效八成就是资源名和服务接口路径对不上。2. 项目接入 Sentinel 的三种正确姿势Sentinel 的接入方式不算复杂但对刚上手的人来说还是容易乱。我见过有人直接在项目里引了sentinel-core然后自己包了一套 API也见过有人为了用注解把所有类都切了一遍结果切面顺序跟事务切面打架。实际上结合 Spring Boot / Spring Cloud 的项目接入路径就那么几条选对了非常省事。2.1 最基础的接入加依赖和配置如果是 Spring Boot 项目最低成本的接法是引入sentinel-annotation-aspectj和sentinel-transport-simple-httpdependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-sentinel/artifactId /dependency如果没用到 Spring Cloud Alibaba也可以用裸的 Sentinel 依赖dependency groupIdcom.alibaba.csp/groupId artifactIdsentinel-core/artifactId version1.8.6/version /dependency dependency groupIdcom.alibaba.csp/groupId artifactIdsentinel-annotation-aspectj/artifactId version1.8.6/version /dependency dependency groupIdcom.alibaba.csp/groupId artifactIdsentinel-transport-simple-http/artifactId version1.8.6/version /dependencysentinel-transport-simple-http的作用是让应用能把监控数据上报给 Sentinel 控制台同时也能接收控制台推送的规则。如果不加这个依赖限流规则只能写在代码里控制台那块基本是废的。我建议无论多小的项目一开始就把 transport 带上后面接控制台会省很多事。2.2 用 SentinelResource 注解定义资源在实际业务代码里最优的做法是用注解把资源明确圈出来而不是在方法里手动写entry/exit。原因很简单注解的方式声明式更清晰而且blockHandler和fallback分开处理被限流和业务异常两种场景代码可读性好很多。SentinelResource( value createOrder, blockHandler createOrderBlockHandler, fallback createOrderFallback ) public Order createOrder(OrderRequest request) { // 业务逻辑 return orderService.create(request); } public Order createOrderBlockHandler(OrderRequest request, BlockException ex) { // 这里是被限流或降级之后走的方法 log.warn(createOrder blocked: {}, ex.getRule()); return Order.fail(429, 系统繁忙请稍后重试); } public Order createOrderFallback(OrderRequest request, Throwable t) { // 这里是业务异常兜底 return Order.fail(500, 下单失败); }这里有一个非常容易踩的坑blockHandler和fallback方法的参数签名必须和原方法保持一致并且blockHandler方法要额外加一个BlockException参数而且是最后一个参数同时这些方法必须是public如果写在别的类里还要配blockHandlerClass。我遇到过一个团队把降级方法写成了private结果运行时报BlockException直接抛到上层整个接口 500排查了半天才发现是方法修饰符的问题。2.3 接入 Spring Cloud Gateway 的注意点如果你的微服务架构里用了 Spring Cloud Gateway 作为统一入口那限流更适合放在网关这一层而不是在每个业务服务里各做一套。Sentinel 有专门的sentinel-spring-cloud-gateway-adapter可以针对路由 ID 或者自定义 API 分组做流控。网关层限流的思路是挡在最前面把流量先过滤一遍业务服务里的规则作为第二层精细防护。两个层次可以并存但不要把同样的规则重复配在每一层否则流量会被双重拦截阈值叠加之后容易误伤正常用户。3. 限流规则配置QPS、线程数、热点和系统保护限流是整个 Sentinel 使用频率最高的功能但很多人配置限流规则的时候就是随手填一个 QPS100完全没想过这个数字怎么来的更没想过不同的限流模式对系统保护有什么不同。我在生产环境里把限流规则分成了四类来用效果比一刀切的 QPS 限制要稳定得多。3.1 QPS 限流模式和它的三种流量控制效果最常用的就是按照 QPS每秒请求数来限流规则配置大概长这样FlowRule rule new FlowRule(); rule.setResource(createOrder); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setCount(100); rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); FlowRuleManager.loadRules(Collections.singletonList(rule));但同样是把阈值设为 100controlBehavior不同实际效果完全不一样。默认的CONTROL_BEHAVIOR_DEFAULT是直接拒绝超过 100 的请求立刻返回BlockException。这种模式适合对实时性要求高、宁可拒绝也不愿意等的场景比如秒杀下单。另一种常用的CONTROL_BEHAVIOR_WARM_UP是冷启动模式系统刚启动的时候限流阈值是保守的默认是 1/3然后逐步提升到设置的最大值适合应对突发流量防止缓存没预热就把系统打垮。还有一种CONTROL_BEHAVIOR_RATE_LIMITER是匀速排队模式超出的请求会排队等待每隔固定的时间窗口放行一个适合削峰填谷比如定时任务、消息推送这种可以接受延迟的场景。我举一个实际配置劣例我做抢券系统时秒杀接口的 QPS 峰值能到 5000后端真正扛得住的其实是 800 QPS直接把 count 设成 800 会误杀很多正常请求因为用户在前端会反复点击真正的有效请求占比并不高。所以我对网关限流设置了WARM_UP 阈值 1200业务服务里再用RATE_LIMITER 阈值 800让流量到达业务层之前先平滑一波。效果是整场活动下来系统没有一次雪崩也没有一个用户因为接口直接 429 而彻底退出。3.2 并发线程数限流保护线程池不被拖垮线程数限流比 QPS 限流更贴近系统真实负载。QPS 限流管的是每秒处理多少请求但如果每个请求耗时很长QPS 很高也算正常可如果线程池里堆积的请求太多就算 QPS 不高系统也一样会挂。Sentinel 的线程数限流限制的是资源同时被调用的并发线程数超过阈值后新的请求会直接被拒绝而不是进入线程池排队。举个例子一个接口的 RT响应时间在正常情况是 50ms如果 QPS 是 500并发线程数只有 25但下游一旦变慢RT 变成 2 秒同样的 QPS 500 就会导致瞬间有 1000 个线程被占住线程池直接爆。在这种情况下限定并发线程数 100 就非常有效超过 100 个并发请求直接失败降级把等待下游的时间限制在一个可控范围。这种模式特别适合第三方接口调用、数据库慢查询这种RT 不可控的场景。3.3 热点参数限流精确到某个参数的防护热点参数限流是 Sentinel 比较独特的功能。普通限流规则是针对整个资源的但热点规则可以精确到某一个参数的值。比如一个商品详情接口大多数商品每天访问量只有几百但某一个爆款商品的访问量可能突然冲到几万。按照资源粒度限流要么阈值定低了误伤正常商品要么定高了保护不住爆款。热点参数规则在控制台里配置起来也很直观见后面控制台章节代码方式是这样ParamFlowRule rule new ParamFlowRule(getProductDetail) .setParamIdx(0) .setCount(50); // 参数值为 9527 时单独限制为 5 QPS ParamFlowItem item new ParamFlowItem(9527, 5, Integer.class); rule.setParamFlowItemList(Collections.singletonList(item)); ParamFlowRuleManager.loadRules(Collections.singletonList(rule));这里setParamIdx(0)的意思是拦截第一个参数也就是商品 ID。如果商品 ID9527 是爆款就单独给它一个很低的阈值其他商品还是走默认的 50 QPS。这个功能在接口防刷和秒杀场景里可以用到极致。3.4 系统自适应保护最后一层安全网系统保护规则不是针对某一个接口而是针对整个应用实例的全局规则。它支持按 LoadCPU 负载、RT、线程数、入口 QPS 等维度来触发保护。我之前在一个高负载实例上配置过当系统 Load 超过 10CPU 核数的 2 倍且 RT 超过 50ms 时所有入口流量都会被限制一部分。这种自适应的机制背后是 TCP BBR 的拥塞控制思想核心逻辑是系统在快扛不住的时候主动限制入口流量让系统有时间恢复。配置系统规则代码大致如下SystemRule rule new SystemRule(); rule.setHighestSystemLoad(10.0); rule.setAvgRt(50); rule.setQps(2000); SystemRuleManager.loadRules(Collections.singletonList(rule));个人体会是系统保护规则适合默认开启阈值可以设得宽松一点它解决的是全局限流问题而针对具体接口的规则解决的是重点保护问题。两者配合起来才是完整的。4. 熔断降级实战慢调用、异常比例与异常数限流解决的是流量太大的问题熔断降级解决的是依赖不可靠的问题。我见过有的团队把熔断和限流搞混了实际上这两个东西的触发条件完全不同限流是主动挡流量熔断是被动发现故障后切断链路。Sentinel 的熔断降级规则有 3 种触发模式平时最常用的是前两种。4.1 慢调用比例熔断给接口的 RT 上了一条红线慢调用比例熔断的意思是在统计窗口内如果请求的平均响应时间超过了某个阈值比如 500ms并且这部分慢请求的比例达到了设定的比例比如 60%那么接下来一段时间内这个资源的所有请求都会被熔断直接走降级逻辑。它的状态机是 CLOSED - OPEN - HALF_OPEN - CLOSED。一开始是关闭的触发后打开等熔断时间过去后进入半开状态放少量请求探测如果探测请求成功了就关闭熔断否则继续打开。在代码里配置慢调用比例熔断是这样DegradeRule rule new DegradeRule(getProductDetail) .setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO) .setCount(500) // RT 超过 500ms 算慢调用 .setTimeWindow(20) // 熔断持续 20 秒 .setStatIntervalMs(10000) // 统计窗口 10 秒 .setMinRequestAmount(10) // 最小请求数 10避免样本太少误判 .setSlowRatioThreshold(0.6); // 慢调用比例阈值 60% DegradeRuleManager.loadRules(Collections.singletonList(rule));这里最重要的参数其实是setMinRequestAmount。我见过有人把最小请求数设成 1结果某一次单个请求慢就立刻熔断导致接口在低峰期频繁抖动。正确做法是统计窗口内至少要积累一定样本量比如 10 个或者 20 个再下结论。这个数字可以从你们接口的正常 QPS 推算出来如果平时 QPS 是 5那 10 秒统计窗口也就 50 个请求最小请求数设为 10 比较合理。4.2 异常比例熔断下游报错多了直接切掉异常比例熔断的逻辑跟慢调用很接近只是触发条件从响应慢换成了异常比例高。比如某个第三方支付接口如果 10 秒内调用 100 次失败 30 次异常比例超过 30%就熔断 30 秒这 30 秒里所有请求直接返回降级结果不再真正调用支付接口。这样做的价值很明显如果第三方接口已经挂了你在这 30 秒内每重试一次都是在浪费资源还可能因为重试风暴把对方彻底压垮。配置如下DegradeRule rule new DegradeRule(payService) .setGrade(CircuitBreakerStrategy.EXCEPTION_RATIO) .setCount(0.3) // 异常比例阈值 30% .setTimeWindow(30) // 熔断持续 30 秒 .setStatIntervalMs(10000) // 统计窗口 10 秒 .setMinRequestAmount(20); DegradeRuleManager.loadRules(Collections.singletonList(rule));使用异常比例熔断时要特别注意的是 Sentinel 默认只会统计BlockException以外的异常。也就是说你业务里自己抛的业务异常是计入统计的但如果是BlockException即被限流造成的拒绝不会被算进异常比例里这个设计是合理的否则系统一变忙限流触发了异常率也被推高会造成双重的误判。4.3 异常数熔断适合低流量但故障集中的场景异常数模式比较简单统计窗口内累计异常次数超过某个阈值就熔断。它跟异常比例的区别是不看比例只看绝对数量。适合那些平时调用量不大比如 QPS 只有 1~2但一旦故障就会连续报错的场景。因为 QPS 低的时候用比例模式很容易因为样本太少而误判用绝对次数反而更准。我个人一般优先用慢调用比例和异常比例这两个模式的数据指标更平滑异常数模式适合做辅助。不管用哪种模式熔断时间窗口timeWindow都不要设得太短。短于 10 秒的话系统刚缓过来一点就开放流量很容易马上再次被打垮形成熔断-恢复-再熔断的抖动循环。我之前在排障的时候就把熔断时间设过 5 秒结果下游故障持续期间系统每 5 秒就震荡一次非常难受。后来统一改成 20~30 秒配合半开状态探测稳定性好了很多。5. 让规则持久化接入 Nacos 的正确打开方式用 Sentinel 控制台直接配置规则确实很爽点几下鼠标规则就生效了。但如果你只在控制台上配置一重启应用规则就丢了。这是因为默认情况下 Sentinel 的规则是保存在应用内存里的控制台修改后虽然能实时推给客户端但没有一个地方做持久化存储。生产环境里微服务一扩容新启动的实例就是白板没规则保护这是不能接受的。所以把规则放到 Nacos 这类配置中心里就成了 Sentinel 落地过程中必须做的一件事。5.1 为什么选择 Nacos 作为规则存储微服务项目里Nacos 本身就是配置中心和注册中心的标准选择把 Sentinel 规则也放进去可以复用现有的配置管理流程、权限控制、环境隔离dev/test/prod 不同命名空间不用额外引入存储系统。Nacos 支持配置的版本管理和回滚规则出问题了可以秒级恢复。对于大多数团队来说不用为了 Sentinel 再去引入 Redis 或者数据库来存规则学习成本和运维成本都最低。Sentinel 整合 Nacos 有拉模式和推模式两种主流方式。拉模式是客户端定期从 Nacos 读取配置本地解析之后更新规则推模式则是通过 Nacos 配置变更监听把最新配置实时推给客户端。社区版本的 Sentinel 控制台默认不支持推模式需要自己改造才行所以对于绝大多数使用开源版本的项目更省事的方案是用拉模式来实现规则的持久化。5.2 拉模式读写 Nacos 配置的完整样例先看依赖需要引入sentinel-datasource-nacosdependency groupIdcom.alibaba.csp/groupId artifactIdsentinel-datasource-nacos/artifactId version1.8.6/version /dependency然后写一个配置类把 Nacos 数据源注册给 Sentinel 的规则管理器。以限流规则为例核心代码是Configuration public class SentinelNacosConfig { Bean public FlowRuleDataSource flowRuleDataSource() { String serverAddr 127.0.0.1:8848; String dataId ${spring.application.name}-sentinel-flow-rules; String groupId SENTINEL_GROUP; ReadableDataSourceString, ListFlowRule flowRuleDataSource new NacosDataSource(serverAddr, groupId, dataId, source - JSON.parseArray(source, FlowRule.class)); FlowRuleManager.register2Property(flowRuleDataSource.getProperty()); return new FlowRuleDataSource(flowRuleDataSource); } }注意这里我用了source - JSON.parseArray(source, FlowRule.class)意思是从 Nacos 读到的 JSON 配置转换成ListFlowRule。Nacos 里的配置文件内容大致长这样[ { resource: createOrder, limitApp: default, grade: 1, count: 100, strategy: 0, controlBehavior: 0, clusterMode: false }, { resource: getProductDetail, limitApp: default, grade: 1, count: 50, strategy: 1, controlBehavior: 0, clusterMode: false } ]关于 JSON 字段对应的含义需要确定一下避免配置的时候看不懂字段含义示例resource资源名对应 SentinelResource 的 valuecreateOrdergrade限流维度0 表示线程数1 表示 QPS1count限流阈值100strategy流控策略0 直接、1 关联、2 链路0controlBehavior流量控制效果0 快速失败、1 Warm Up、2 匀速排队0clusterMode是否集群限流单机模式为 falsefalse熔断规则降级的 JSON 内容也类似放在另一个 dataId 里[ { resource: payService, grade: 1, count: 0.3, timeWindow: 30, minRequestAmount: 20, statIntervalMs: 10000 } ]然后还需要给降级规则也注册数据源Bean public DegradeRuleDataSource degradeRuleDataSource() { String serverAddr 127.0.0.1:8848; String dataId ${spring.application.name}-sentinel-degrade-rules; String groupId SENTINEL_GROUP; ReadableDataSourceString, ListDegradeRule degradeRuleDataSource new NacosDataSource(serverAddr, groupId, dataId, source - JSON.parseArray(source, DegradeRule.class)); DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty()); return new DegradeRuleDataSource(degradeRuleDataSource); }5.3 控制台、Nacos、客户端三者如何配合把规则持久化到 Nacos 之后整个工作流会变成这样运维或开发在 Nacos 控制台上修改规则 JSON保存发布。客户端应用通过 Nacos 数据源感知到配置变更实时更新本地规则。Sentinel 控制台仍然显示应用的实时监控数据但规则修改建议直接去 Nacos 改而不是在控制台改。这里有个体验上的落差控制台上改的规则如果没配持久化重启就没有了但控制台上显示规则依然是生效的因为控制台和客户端之间通过 transport 通信规则存在客户端内存里。所以我自己在团队里立的规矩是生产环境的规则一律以 Nacos 为准控制台只用来做可视化监控和规则查看不直接改规则。如果确实需要改也是先在 Nacos 里改完然后等客户端推下去再在控制台确认效果。6. 控制台部署与监控从选型到排障Sentinel 控制台Dashboard是一个独立的 Spring Boot 应用负责显示每个接入客户端的实时监控数据、配置规则、查看链路调用情况。部署控制台本身不难但接入的过程中有几个细节不处理好的话很容易出现明明接入了但控制台啥也看不到的情况。6.1 控制台启动与客户端接入参数先去 GitHub 下载sentinel-dashboard的 jar 包然后启动java -Dserver.port8080 \ -Dcsp.sentinel.dashboard.serverlocalhost:8080 \ -Dproject.namesentinel-dashboard \ -jar sentinel-dashboard.jar初始用户名密码都是sentinel登录之后就是主界面。客户端的 application.yml 需要加上spring: cloud: sentinel: transport: dashboard: localhost:8080 port: 8719这里dashboard是控制台地址port是客户端和 control 台通信的心跳端口。要注意的是如果你的应用服务器有多个实例每个实例的 8719 端口必须保证可用如果 8719 被占了Sentinel 会尝试依次用 8720、8721 递增。生产环境最好在安全组里放行 8719因为控制台机器需要通过这个端口才能拿到客户端的监控数据。还有个容易忽略的点控制台默认只能展示最近 5 分钟的实时监控曲线因为客户端在本地只保留了最近 1 分钟的秒级窗口数据聚合之后上报给控制台。并不是监控不准而是 Sentinel 的定位是实时监控 规则管理不是长期的 metrics 存储。要做长期趋势分析你得把监控数据接到 Prometheus 或者其他时序库里。6.2 控制台配置规则的优势和局限控制台上配置规则最大的优势是可视化尤其是对不熟悉代码的同学比如运维或者 QA非常友好。你可以在簇点链路里看到所有被 Sentinel 收集到的资源逐个给它们配置限流、熔断、热点规则点点鼠标就完成。但它也有两个让我头疼的局限。第一个就是前面说过的规则不持久化重启即失必须接 Nacos 才能解决第二个是规则的推送机制开源版控制台是通过 HTTP 接口把规则推给客户端的客户端本地会更新规则但如果客户端这时候网络抖动推送可能失败控制台上却没有明显的失败提示。所以在生产环境里我更推荐把控制台定位成监控 规则预览把 Nacos 当成规则真源。6.3 监控指标怎么读在控制台的实时监控页面你关心的指标就三个通过 QPS、拒绝 QPS、RT。通过 QPS 是系统实际放行的流量拒绝 QPS 是被规则拦截的流量RT 是平均响应时间。如果某个接口的拒绝 QPS 持续大于 0说明它正在被限流规则保护这时候要去确认规则的阈值设置是否合理是主动保护的预期行为还是阈值过低导致误伤。如果通过 QPS 不高但 RT 持续上涨说明系统可能在等待下游资源这时候要关注的不是限流规则而是熔断规则有没有及时触发。链路页的调用树也很有用它能展示一个资源被哪些入口调用、每个调用链路的 QPS 和 RT。排查问题的时候顺着链路树看谁在拖慢整体性能比一上来就看日志要高效得多。7. 常见问题与排查技巧实录Sentinel 用久了之后你会发现大部分问题其实都集中在几个固定的点上。这里把我在实战中遇到过的、以及帮别人排查过的典型问题整理成一份速查表每条都是真实场景下反复踩过的坑。7.1 限流规则完全不生效这是出现频率最高的一个问题。限流不生效90% 是资源名对不上。你想保护的接口路径如果是/api/order/create但你的SentinelResource注解 value 写的是createOrder那控制台上配置针对createOrder的规则和实际请求其实是两个资源。解决办法是在簇点链路里看 Sentinel 到底把请求统计到哪里了以控制台展示的资源名为准再来配规则。还有一种可能是规则加载失败。用 Nacos 数据源的时候如果 JSON 里有未知字段JSON.parseArray可能会直接转换失败规则一条都没加载进去。这种情况控制台看规则列表是空的需要先看客户端日志里有没有 Nacos 数据源的报错。7.2 控制台看不到监控数据控制台看不到数据先检查客户端有没有成功上报心跳。你去客户端的日志里搜sentinel相关关键词看有没有输出 sentinel transport 之类的启动信息。最常见的三个原因没引入sentinel-transport-simple-http依赖client 的 transport 端口 8719 被防火墙挡了或者spring.cloud.sentinel.transport.dashboard地址配错了。还有一个隐蔽问题是如果应用本身没流量控制台也看不到资源数据需要先真实调用一下接口才会注册资源。7.3 热点参数限流不生效热点参数规则比普通规则多几个容易出错的点。paramIdx是从 0 开始计算的0 表示第一个参数不是从 1 开始参数类型如果是复杂对象Sentinel 默认用的是参数的hashCode不是 JSON 里的某个字段所以你要防护的目标得是基本类型或者字符串。还有热点参数规则只对SphU.entry(name, EntryType.IN, 1, paramA)这样的带参数调用生效如果你在方法里没把参数传给 Sentinel规则也会静默失效。7.4 规则在控制台上删除后客户端还在执行这个场景我也遇到过在控制台上删掉了一条限流规则但测试发现接口还是被限流。原因在于如果规则是持久化在 Nacos 里的客户端本地缓存的规则由 Nacos 数据源维护控制台删除操作并不会同步到 Nacos。你删掉的只是控制台的内存视图客户端仍然从 Nacos 拉取规则并加载。所以要改或删规则请记得去 Nacos 里面操作而不是控制台。7.5 阈值不知道设多少合适阈值设置不是拍脑袋拍出来的而是压测压出来的。我的经验是先不给应用限流用压测工具jMeter 或者 wrk分别测出接口的安全水位和极限水位。安全水位指的是 RT 保持稳定的最大 QPS极限水位是系统能抗住但不保证质量的最大 QPS。限流阈值建议设在安全水位的 80%~90%留出余量给突发流量。如果是大促这种可以允许少量失败的场景可以放宽到极限水位的 80% 左右但一定要配合熔断规则兜底。7.6 系统自适应规则和业务限流规则打架系统保护规则是全局的业务限流规则是局部的两者同时生效时优先触发哪个是不确定的。如果系统保护规则设得太紧比如 Load 阈值设成 2但机器是 8 核系统一繁忙所有接口都会被系统规则挡住业务侧精心配置的限流规则反而形同虚设。所以系统自适应规则的阈值不能照抄网上的要结合你机器的核数和实际负载来调。一般来说Load 阈值可以先设成 CPU 核数的 70%~80%跑一段时间观察再逐步收紧。8. 从稳定到精细化Sentinel 在这些场景下的进阶玩法如果基础限流和熔断已经跑通了下面这几个方向值得继续深入它们能让 Sentinel 发挥更大的价值。我不打算展开每个细节只说说哪些场景值得关注以及它解决的问题是什么。8.1 隔离不同来源的流量同一个接口可能面向多种来源比如 APP 端、PC 端、开放平台第三方。不同来源的流量特征差异很大第三方平台的调用往往对稳定性要求更高。Sentinel 支持通过origin参数区分来源再配合授权规则来控制谁能访问、谁不能访问或者说给不同来源分配不同的限流阈值。实现起来就是在调用SphU.entry的时候传入来源标识规则里用limitApp字段来匹配。这个玩法在多租户系统里尤其实用。8.2 网关层统一限流前面提过网关层限流是很多微服务架构必须做的一层。Sentinel 对 Spring Cloud Gateway 和 Zuul 都有成熟的适配方案可以按照路由 ID、API 分组、客户端 IP 来做流控。我的建议是全局的初级过滤放在网关层业务级的精细规则放在服务层。网关层的阈值应该比服务层宽松一些否则两层叠加会把流量卡得太死。8.3 集群限流单机限流在水平扩容之后有一个问题每个实例的阈值都一样假如 10 个实例每台限流 1000总容量就是 10000但如果流量不均匀某台机器先被打满其他机器还很空闲单机限流就会提前拦截。集群限流的意思是把一组实例的总流量控制在同一个阈值内由专门的 Token Server 统一分配。这个配置相对复杂适合流量波动大、对总量控制要求高的场景。如果只是普通的微服务项目建议先从单机限流起步不用直接上集群。8.4 规则加白名单和降级兜底规则本身也可能出问题理论上存在规则配错导致所有流量都被拦截的情况。所以我在生产项目里会在 Sentinel 的入口包一层兜底逻辑如果发现拒绝率异常飙升或者降级处理也超时了可以做一个熔断降级开关由监控告警触发直接把 Sentinel 的规则临时清空或者调整成放行模式。这个开关听起来有点违反直觉但经历过一次误配规则导致的事故之后你就会明白这个兜底有多重要。9. 最后再分享一点我自己的使用体会Sentinel 真正用得出价值和用不出价值差别往往不在功能掌握多少而在规则是否贴合实际业务场景。我见过一些团队把几十条限流规则配在代码里但问起来每个阈值怎么来的没人说得清也见过一些团队就两三条规则但每一条都经过了压测验证、都清楚它的触发条件和影响面。做微服务保护这件事少即是多你不需要一开始就追求把所有接口都保护起来先从最核心的两三个链路开始把限流阈值压测出来把熔断降级的边界跑通再逐步铺开。还有一个小技巧是Sentinel 的规则变更一定要留审计记录。无论你是用 Nacos 改规则还是在控制台上手动调整都建议把谁在什么时间把哪个资源的阈值从多少改成了多少记到日志里。因为限流规则一变线上流量表现立刻就会变如果没有审计出了问题你根本不知道是哪条规则导致的。我们的团队就是在踩过无记录线上改规则的坑之后才定下了这个规矩。另外别忽视客户端日志里那些看起来不起眼的 WARN 日志。Sentinel 在规则的加载失败了、数据源注册出问题了、transport 连接不上控制台了都会打出 WARN 级别的日志但很多同学从来看都不看。这些日志其实是最早暴露问题的信号。线上排查 Sentinel 相关问题第一件事就是去翻客户端日志很多问题一眼就能定位。如果你正在做微服务改造或者已经上线了 Spring Cloud 架构但还裸奔着我建议你把 Sentinel 优先放到核心链路上而不是所有接口一把抓。先让少数关键链路具备限流熔断能力在这个基础上逐步完善规则形成一套适合自己业务的保护体系这才是 Sentinel 的正确打开方式。
阅读完成 · 觉得有帮助?
咨询建站