Sentinel授权规则与系统规则:从限流量到限来源与全局保护

发布时间:2026/10/15 12:45:31
Sentinel授权规则与系统规则:从限流量到限来源与全局保护
做服务容错做得久了你会发现一个有意思的现象流量控制、熔断降级这些规则管的是“某一条路能放多少车过去”可真正把系统搞垮的往往不是哪一条路太堵而是你压根不知道是谁在一窝蜂地挤进来或者整台机器的CPU、负载已经亮红灯了你还在继续放新流量进来。这个系列前面几篇把流控规则、熔断降级、热点参数规则都过了一遍今天这篇接着聊Sentinel规则家族里偏“全局视角”的两类规则授权规则和系统规则。标题里我标了“简要说明”是因为对多数项目来说这两类规则的使用频率没有流控和降级高但它们解决的都是流控解决不了的硬问题接口被不该调的来源反复请求、高峰期整机资源耗尽导致的全链路抖动。这篇以理解为主不需要你记住太多API细节关键是搞清楚它们各自管什么、什么时候该配、配完怎么验证。我按自己的习惯来先讲它们在整个保护体系里处在什么位置再逐个拆开说原理最后给一个能直接跑通的演示工程。1. 规则体系里最容易被忽视的两类规则授权规则与系统规则1.1 前几篇已经解决的问题这个系列前面四篇围绕Sentinel的核心规则做了逐一拆解流控规则在QPS或者线程数维度上限制某个资源接口、方法的访问量降级规则在接口异常比例、慢调用比例超标时自动熔断并走兜底热点规则则是对携带特定参数值的请求做精细化限流。你可以发现这三类规则有一个共同特征——它们都锚定在某个具体资源上。每个规则的配置里都有一个资源名保护对象是类似/order/info、com.demo.OrderService.getOrder这样被Sentinel切出来的点。这种保护叫“资源维度”的保护擅长解决的是“某个接口突然被打爆”这类问题。但实际故障里还有两类请求是资源维度规则管不了的。1.2 授权规则和系统规则的本质区别授权规则管的是“谁在访问”。它不关心一次请求占了多少QPS也不关心接口的RT是不是飙到了2秒它只做一件事判断这个请求的来源origin是否在白名单或黑名单里然后决定放行还是拒绝。系统规则管的是“这台机器还顶不顶得住”。它会看整个应用实例的系统负载、CPU使用率、总体入口QPS这些全局指标。一旦某个全局指标超过阈值它就直接对入口流量做整体拦截而不是去细分到底哪个资源最热门。用一个比喻你马上就能记住前三类规则管的是“每条路各能放多少车”授权规则是“哪类车不允许上这条路”系统规则则是“整个路网已经堵死了所有进市区的车先停一停”。1.3 什么时候你会意识到需要它们先说授权规则。最常见的场景某公司的订单服务里有一个给内部仓储系统调用的接口结果因为没有做来源限制被外部客户端用技术手段挖了出来直接绕过网关去刷下单接口。这个时候你用流控规则去限制QPS只是把正常的仓储调用一起限了根本问题没解决——正确的做法是配置授权规则把该接口的调用来源限制成只允许仓储系统那一个来源。再说系统规则。大促高峰期网关做了限流理论上打到下游服务的流量是可控的但某个下游服务所在的机器本身CPU已经飙到90%多GC频繁新进来的请求基本都在排队超时。此时如果这个服务自身配置了系统规则把CPU使用率或系统Load的阈值卡住它就能在资源耗尽前主动拦截入口流量给自己留出喘息空间。这两类规则流控规则很难优雅实现。因为它们本质上是来源不合法或者全局状态恶化而不是单纯的流量过大。理解了这一点后面配置起来思路就清晰了。2. 授权规则从“限流量大小”到“限流量来源”2.1 一句话理解授权规则授权规则AuthorityRule本质上就是黑白名单控制。你给某个资源设定一组“被允许的调用来源”或“被拒绝的调用来源”当请求到达时Sentinel根据请求解析出的调用来源和名单做比对按策略决定放行还是拒绝。这里要特别强调一下授权规则里的“来源”不是IP地址不是用户ID而是Sentinel通过RequestOriginParser接口从请求中解析出来的一个字符串。这个字符串的内容完全由你决定可以是从Header里取的调用方应用名可以是从Token里解出来的客户端类型甚至可以是从参数里拿到的某个业务标识。2.2 核心参数解析授权规则在控制台上配置时需要关注三个参数参数含义说明resource资源名要保护的接口或方法对应的资源标识和流控规则的资源名是同一套体系limitApp调用来源集合逗号分隔的origin字符串列表比如app1,app2strategy策略0表示白名单1表示黑名单以resource/order/info、limitAppconsole-app、strategy0为例这条规则表达的意思就是只允许请求来源为console-app的调用访问/order/info接口其他来源一律拦截。配置授权规则时最常见的困惑是“limitApp里到底填什么”。它不是随便写的而是要和你的RequestOriginParser实现对应上。你在代码里解析出什么字符串控制台里就要填什么字符串两边不一致规则就不会生效。2.3 RequestOriginParser让Sentinel认出“调用者是谁”Sentinel默认不知道你的请求里哪个字段代表来源所以需要实现一个RequestOriginParser接口来告诉它。这是授权规则里唯一需要写代码的地方。先看一个最简单的实现从请求Header中取出来源Component public class HeaderRequestOriginParser implements RequestOriginParser { Override public String parseOrigin(HttpServletRequest request) { String origin request.getHeader(X-Request-Origin); return StringUtils.hasText(origin) ? origin : unknown; } }这段代码逻辑很简单每次请求进来时取Header中X-Request-Origin的值作为调用来源如果请求方没有带这个Header就统一记为unknown。这里有三个要点需要提醒第一这个类必须交给Spring容器管理。Component注解不能少否则Sentinel在Web环境中通过SPI或者容器查找RequestOriginParser实现时找不到授权规则就会形同虚设。第二整个应用只需要一个RequestOriginParser实现类不需要为每个接口单独写一个。第三解析逻辑可以非常灵活。我曾经在一个项目里见过比较巧妙的做法从用户的JWT Token里解析出客户端类型是App端、小程序端还是运营后台然后针对只允许运营后台访问的管理接口配置白名单。这样用户在哪个端发起请求就会被自动映射到对应的来源标识上完全不需要调用方额外传Header。2.4 白名单和黑名单的选择白名单和黑名单用哪个不只是一个参数的差别背后是安全模型的选择。白名单是“默认拒绝只放行明确允许的”。它的安全程度最高误伤风险也高。如果某个合法来源没有提前加进名单它的请求就会被拦截属于宁可错杀不可放过。黑名单是“默认放行只拦截明确拒绝的”。它的兼容性最好但安全性依赖名单的完整性。漏配一个恶意来源等于没防住。我的建议是可枚举合法调用方的场景优先用白名单。比如内部服务间调用调用方就那么几个系统全部枚举出来剩下的一律拒绝。如果合法调用方太多或者无法完整枚举但你能明确识别出恶意来源的特征时再退而求其次用黑名单。还有一点容易忽略来源值必须足够稳定。如果调用方这次请求带console-app、下次带console白名单就会间歇性误伤。所以在设计来源字段的取值规范时一定要和调用方约定好“这个值是一个固定常量”而不是随便填一个动态拼接的字符串。2.5 典型的授权规则应用场景我在实际项目里见过比较多的是下面三类一是内部接口防外部调用。公司的开放平台、运维平台、管理后台这些内部系统接口只允许特定的内部系统访问外部网络环境一律拦截。这种场景通常配合网关层白名单使用Sentinel的授权规则是第二道防线防止有人绕过网关直接打到服务端口。二是回调接口防刷。支付回调、Webhook这类接口理论上只有第三方平台会主动调用但一旦第三方平台的密钥泄露或者逻辑异常可能会被刷。给这类接口配置黑名单把异常的调用来源封掉比单纯限流更精准。三是多端业务限制。比如某个活动接口只允许App端参与H5端和小程序端不能访问后端数据接口。通过请求端信息解析出来源后配置白名单即可。这种需求用授权规则比在业务代码里写if判断要清爽得多规则调整也不用发版。3. 系统规则全局视角的负载保护3.1 为什么需要系统规则单条资源的流控保护能精准治理热点但解决不了“整台机器已经不行了”的问题。举一个我实际遇到的例子某个服务的A接口流量并不大但B接口有一个计算密集型的逻辑单次请求就会把CPU打高。此时A接口的流控规则统计显示QPS很低、RT正常不会触发拦截但整台机器的CPU已经接近100%所有接口的响应都在变慢。这种场景下你需要的不是“哪条资源超了限哪条”而是“机器整体快不行了所有入口流量都先收一收”。这就是系统规则存在的意义。它不关心具体资源只看应用实例全局的运行状态。3.2 系统规则的五个维度Sentinel系统规则支持五个维度的阈值设置维度含义触发条件注意事项Load系统负载操作系统1分钟平均负载load1超过阈值时拦截入口流量仅Linux/Unix环境生效Windows下忽略CPU使用率系统CPU占用百分比超过设定值时触发取值是0到1之间的小数0.9表示90%平均RT所有入口流量的平均响应时间超过阈值时拦截单位毫秒入口QPS所有入口流量每秒请求数之和超过阈值时拦截全局总吞吐控制并发线程数入口流量的并发线程数超过阈值时拦截反映当前正在处理的请求总量逐个解释一下每个维度的正确打开方式。Load维度看的是操作系统的1分钟平均负载。这里有个基本概念要清楚负载不等于CPU使用率它表示的是“处于可运行状态或不可中断状态的进程/线程数量均值”。判断一个系统的负载是否过高不能只看这个数值还要结合CPU核数。比如一个4核机器load值到4说明4个核都满负荷在跑这个时候新请求再进来就要排队了。而一个64核机器load值到4其实还很轻松。所以Load阈值通常按照“CPU核数 × 0.7”左右来估算留出一定缓冲。CPU使用率维度最直观也最好理解。生产环境我一般建议设置在0.7到0.85之间。设得太低比如0.5系统稍微忙一点就开始拦截入口流量影响正常业务设得太高比如0.95等触发拦截时系统可能已经在“假死”边缘了拦截动作本身都未必来得及执行。平均RT维度是入口请求平均响应时间。这个指标本身是结果指标系统慢的时候RT自然会上涨。用它做保护阈值相当于说“当整体平均RT超过某个值说明系统已经处理不过来了拦截新请求”。RT阈值一般结合压测数据来定取正常峰值RT的1.5倍左右比较稳妥。入口QPS维度最粗暴直接限制所有入口请求的总吞吐。但设置阈值时一定要小心它一拦就是全局拦。假设服务正常峰值入口QPS是200你设成150那流量稍微一冲就触发拦截并且全部接口一起拦业务损失可能比资源耗尽更大。并发线程数维度和流控里的线程数模式思路类似只不过作用范围是所有入口请求。3.3 “入口流量”到底指什么上面反复提到“入口流量”这个词是理解系统规则的关键也是新手最容易踩坑的地方。在Spring Web项目中Sentinel统计的入口流量是指从DispatcherServlet进入应用的外部HTTP请求。也就是说你在控制台看到那个应用的所有Controller接口加在一起的请求量。应用内部方法之间的调用、Async异步线程里发起的请求、MQ消费者里调用业务方法的流量这些都不算入口流量。配了系统规则后很多人的第一反应是“我已经配了入口QPS100为什么一个内部定时任务调了几百次接口都没被拦”。原因就在这里——那个定时任务是在应用内部直接调用业务方法的根本没有经过入口过滤器自然不落在入口流量的统计范围内。还有一个常见场景如果你把服务A作为一个纯RPC服务没有加Web层接口那么入口QPS指标可能一直是0系统规则的入口QPS维度永远触发不了。这种情况就要检查自己的架构是不是适合用系统规则的入口维度来做保护。3.4 系统规则与流控规则的区别从对比的角度看系统规则和流控规则至少有三层差别一是作用层次不同。流控规则作用在单个资源上系统规则作用在整个应用实例的入口上。假设系统里有10个接口流控规则可以只保护其中2个系统规则一配就是“看住全部10个接口的总量”。二是阈值逻辑不同。流控规则的阈值是你写死的一个数比如QPS1000。系统规则里Load、CPU这些系统的阈值是硬指标而入口QPS虽然是硬指标但Sentinel在系统负载高时会基于SystemStatusListener采集的实时状态做自适应判断不是简单到了阈值就一刀切。三是定位不同。流控规则是常态化的流量治理手段日常就在跑系统规则更像是系统的“最后一道防线”平时不指望它频繁触发但一旦触发一定是全局都在承压。我在生产环境里的习惯是接口级别的流控规则精细化配置系统规则只保留CPU和入口QPS两条作为兜底并且阈值留得相对宽裕。因为系统规则的触发代价是全量拦截宁可少拦一点也不要在系统还能撑的时候误伤业务。3.5 阈值怎么定阈值设置是一个见仁见智的问题没有标准答案但有可复用的方法。第一步先压测得到业务容量的基线。向服务持续加压观察CPU、RT、QPS三个指标出现拐点的位置。所谓拐点就是继续加大压力但QPS涨不动、RT开始明显上涨的那个点这个点的QPS就是系统的实际吞吐上限。第二步设置入口QPS阈值为实际吞吐上限的70%左右。留出的30%余量用来应对流量抖动和GC等短暂干扰。第三步CPU阈值设在0.7到0.85之间。如果你的业务对延迟敏感选0.7如果是离线型业务能容忍排队选0.85也可以。第四步RT阈值取压测中正常流量下平均RT的1.5倍。这个维度是用来兜底的不需要精确到个位数。最后提醒一句系统规则的顺序应当放在最后。接口级流控先拦热点参数再拦如果都不生效流量继续冲击系统规则作为兜底再出手。如果一开始就把系统规则设得很严真正出现问题的时候接口级流控反而没有机会发挥作用了。4. 动手实操完整演示授权规则和系统规则的配置与验证4.1 工程准备先创建一个Spring Boot工程引入Spring Cloud Alibaba的Sentinel依赖dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-sentinel/artifactId /dependency在application.yml中配置控制台地址和应用名spring: application: name: sentinel-rules-demo cloud: sentinel: transport: dashboard: localhost:8080 eager: true这里多说一句eager: true的作用。Sentinel默认是懒加载的应用启动后不会主动注册到控制台只有第一次有接口被调用时才会初始化并上报。配了这个参数后应用启动就会立即注册到控制台方便我们观察资源列表。需要先启动Sentinel控制台控制台本身是一个独立的Java进程启动后默认监听8080端口。为了避免端口冲突把业务服务端口改一下比如用8081server: port: 80814.2 写一个被保护的接口创建一个简单的订单查询接口用来演示两类规则的效果RestController RequestMapping(/order) public class OrderController { GetMapping(/info) public String info(RequestParam String userId) { return order info for user: userId; } }启动服务后先手动访问一次接口curl http://localhost:8081/order/info?userId1001然后打开Sentinel控制台在“实时监控”和“簇点链路”页面应该能看到/order/info这个资源。如果没看到等一下再刷新资源上报有一点点延迟。4.3 授权规则演示只允许特定来源访问按照前面写的先实现RequestOriginParser从Header中读取来源Component public class HeaderRequestOriginParser implements RequestOriginParser { Override public String parseOrigin(HttpServletRequest request) { String origin request.getHeader(X-Request-Origin); return StringUtils.hasText(origin) ? origin : unknown; } }重启服务让这个类生效。接着在控制台左侧菜单点“授权规则”再点“新增授权规则”按下面的参数配置资源名/order/info流控应用console-app类型白名单配置保存后用三种不同情况分别验证第一种不带X-Request-Origin头的请求curl http://localhost:8081/order/info?userId1001这时来源被解析为unknown不在白名单里请求会被拦截。返回结果里能看到Sentinel的拦截标记通常是Blocked by Sentinel: 参数不合法之类的提示。第二种带X-Request-Origin: console-app头curl -H X-Request-Origin: console-app http://localhost:8081/order/info?userId1001来源匹配白名单请求正常返回。第三种带X-Request-Origin: other-app头curl -H X-Request-Origin: other-app http://localhost:8081/order/info?userId1001来源不在白名单同样被拦截。验证完成后可以切到控制台的“授权规则”页面能看到该资源的通过请求数和拦截请求数的统计。4.4 在控制台配一条系统规则并验证接下来演示系统规则的配置。在控制台左侧菜单点“系统规则”点“新增系统规则”选择“入口QPS”阈值填30。保存后我们制造并发请求来触发拦截。用ab压测工具最方便没有的话循环也可以但速度会慢很多。for i in $(seq 1 200); do curl http://localhost:8081/order/info?userId$i /dev/null; done这种串行循环很难让QPS超过30更推荐用abab -n 200 -c 20 http://localhost:8081/order/info?userId100120个并发、200个总请求入口QPS很快会超过30系统规则触发拦截。从ab的输出能看到有一部分请求是非200状态在Sentinel控制台的“系统规则”页面也能看到Blocked计数在上涨。这里要提醒入口QPS30这个阈值只是演示用生产环境千万别这么设。真实系统单机入口QPS几百上千都很正常设成30等于把所有流量全部拦在外面。4.5 观察控制台实时监控规则验证完之后别忘了看实时监控曲线。控制台右侧的“实时监控”页面会展示每个资源的通过QPS和拦截QPS被拦截的请求流量在图表上会有明显标记。很多时候用户在控制台配完规则发现“好像没生效”其实不是没生效而是流量根本没到触发条件。所以养成配完规则就看监控的习惯比反复改规则本身更有用。Blocked计数开始上涨才说明规则真正在起作用。5. 实战中避不开的坑与一些体会5.1 RequestOriginParser不生效的几类原因授权规则配完不生效十有八九不是规则本身的问题而是来源没解析对。我复盘几个容易踩的坑第一RequestOriginParser实现类没有放进Spring容器。有人写了一个普通类也实现了接口但就是忘了加Component。结果Sentinel找不到实现所有请求的来源都被当作默认值授权规则永远匹配不上预期来源。第二解析来源时返回的值不稳定。比如有的请求带了Header有的没带有的带的是下划线有的带的是中划线最后解析出来一堆不同的来源值。白名单里只配了一个导致部分合法请求被当成非法来源拦截。第三来源解析时抛异常。如果parseOrigin方法里取Header、取Token时没做判空处理请求异常时抛出了NullPointerExceptionSentinel对异常的处理是直接将该请求视为来源未知同样会影响规则命中。第四配置的规则资源名和实际资源名不一致。控制台里资源名写的是/order/info但代码里因为用了不同路径前缀实际注册的资源名变成/order/info带了后缀或者参数。两边对不上规则自然不生效。排查思路也很简单在parseOrigin方法里打日志看每个请求解析出的origin到底是什么再看控制台里授权的资源名和簇点链路里的资源名是否完全一致。5.2 系统规则的几个隐藏限制系统规则不生效的情况比授权规则更隐蔽。首先Load维度只对Linux/Unix生效。如果你在Windows机器上调试配置Load阈值永远不会触发。这不是BUG是官方明确的平台支持限制。正确的验证方式是在Linux服务器上配置或者在本地改用CPU使用率、入口QPS这类跨平台指标来验证。其次系统规则统计入口流量这在Spring Web环境没问题但如果你用的是其他Web框架或者纯RPC服务入口流量的定义可能和预期完全不同。我见过有人给一个只做RPC的消费者服务配了系统规则结果发现很长时间里入口QPS一直是0因为流量根本没从Web入口进来。还有一个容易出现误解的地方系统规则触发后控制台返回的是全局拦截信息但你是不是只能看到资源级统计对系统规则不像授权规则那样有单独的列表页你要在“实时监控”里看有没有大量Blocked同时配合系统监控的CPU、Load曲线判断是不是系统规则触发。5.3 常见误用场景授权规则不适合用来做用户权限校验。授权规则只识别“来源”这个来源可以是应用名、端类型但一般不会精确到个人用户。想实现“只有VIP用户能访问这个接口”那是业务权限体系的范畴不要在Sentinel授权规则里硬做。系统规则也不要当成常规限流手段来用。它的触发代价是全量拦截属于“丢车保帅”的策略。正常流量治理还是靠资源维度的流控、热点规则来做系统规则只作为最后一道防线。我见过一个设计得比较糟糕的配置把系统规则的CPU阈值设成了0.4结果服务CPU稍微一波动所有接口全部拦截线上直接告警炸锅。后来把阈值放宽到0.8同时配合接口级流控系统才稳定下来。5.4 我实际使用中的一些体会最后分享一点我自己的使用习惯。授权规则和系统规则在我的监控体系里属于“平时不怎么动但必须提前配好”的规则。原因很简单等真出事的时候再临时去控制台配规则反应速度大概率赶不上故障扩散的速度。提前配好平时它不干预业务关键时刻它能挡住灾难这就够了。我通常会把授权规则和系统规则的验证纳入上线检查清单里。每次服务发布前至少手动触发一次授权规则确认来源解析正常再用压测工具做一次小流量验证确认系统规则阈值没有因为代码改动而失去意义。这套流程看起来多花几分钟但能在早春阶段发现配置失效的问题。如果你在生产环境使用了Nacos做规则持久化还需要注意控制台配置和Nacos配置源之间的优先级问题避免出现“控制台改了规则但线上没生效”的情况。这些规则都是工具关键看你用得合不合适。授权规则该配在哪里、来源值怎么定义、系统规则阈值留多少冗余没有放之四海而皆准的标准但理解了它们各自的原理和限制你就能在自己的系统里做出合理的取舍。