ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Sentinel授权规则与系统规则实战:白名单、黑名单与整机兜底

Sentinel授权规则与系统规则实战:白名单、黑名单与整机兜底 Sentinel系列写到第五篇前几篇我们把流控规则、降级规则、热点规则都过了一遍到这篇剩下的就是授权规则和系统规则两个模块。标题上虽然写了“简要说明”但以我实际排查问题的经验来看这两个模块看着简单用起来翻车的概率比流控规则还高。很多人配了授权规则不生效配了系统规则发现接口全被拦了问题往往出在没搞懂这两类规则在Sentinel整个拦截链里到底处于什么位置以及它们背后依赖了哪些前置条件。这篇就用实战的方式把这两块拆开讲清楚适合已经跑通Sentinel基础流程、准备在生产环境细化管控的同学参考。1. 授权规则与系统规则流控之外的“横向兜底”从Sentinel的规则体系来看流控、降级、热点规则针对的是单个资源解决的是“某个接口能不能扛住这个量”的问题而授权规则和系统规则解决的是另一类问题一个请求到底有没有资格进来以及这个应用整体还能不能撑住。这两类规则是横向的作用在整个调用链上不单纯挂在某一个资源名下。1.1 授权规则到底在管什么授权规则的核心是“我不能让谁进来”区分白名单和黑名单两种模式。举个例子线上有个下单接口原本只应该由订单服务内部调用结果被外部某个脚本盯上了每天定时刷你几千次。流量不大触发不了流控规则但接口逻辑确实在被白嫖业务上也说不清这些请求到底是哪来的。这时候授权规则就能派上用场给请求来源打上标记在Sentinel入口处直接拒绝黑名单来源或者反过来只允许白名单来源访问。它的设计思路是“来源识别 黑白名单判断”所以有一个关键前提请求里必须能被解析出“来源应用”。这个来源可以是一个Header、一个参数、甚至一段自定义逻辑。如果应用里没做来源解析授权规则就是一堆永远不生效的配置。1.2 系统规则是给“整机”设的保险丝系统规则的价值不在于保护某个接口而在于保护整个应用进程。它的阈值维度包括系统Load、CPU使用率、入口QPS、平均RT、线程数五个维度任何一项超标都会触发全局拦截。典型的场景是业务大促期间某个接口流量暴涨流控规则还没来得及在对应的资源上生效整个应用就快被拖垮了。这时系统规则像保险丝一样先跳闸保住进程不被打挂。这套机制的思路是“机器级别的兜底”不分接口、不分调用方一视同仁地限制入口流量。但它也有偏科的地方比如你设置了入口QPS为1000结果所有Web接口的请求都会算进这1000如果某个接口本身会调用外部服务导致RT很高也可能把全局平均RT拉高触发拦截。所以系统规则的阈值设置比流控规则更依赖对整机负载的理解不能拍脑袋填数字。2. 授权规则从配置到落地请求来源解析是关键授权规则看起来只有两个选项白名单、黑名单再加一个来源应用名称。但实际上最容易出问题的环节是“来源应用名称从哪来”。Sentinel不会自动知道调用方是谁它需要你告诉它一个来源标识。2.1 授权规则的判定逻辑授权规则在Sentinel拦截链中位于统计完成之后、流控规则之前核心类是AuthoritySlot。当一个请求进入时Sentinel会调用RequestOriginParser解析出origin然后拿着这个origin和当前资源的授权规则做匹配。白名单模式下limitApp里列出的来源允许通过未列出的来源直接抛AuthorityException黑名单模式正好反过来列出的来源被拒绝未列出的放行。这里有个容易被忽略的细节如果请求解析出来的origin为空或者为null在白名单模式下请求会直接拒绝。原因很简单白名单的语义是“只有列表里的才放行”一个连来源都标识不出来的请求自然不在信任范围内。所以实现RequestOriginParser时至少要给一个兜底值比如default避免误伤正常请求。2.2 来源解析RequestOriginParser的实现细节在Spring Boot的Web MVC场景下spring-cloud-starter-alibaba-sentinel自动装配了SentinelWebInterceptor它会从Spring容器中查找RequestOriginParser的实现类来解析来源。实现这个接口很简单Component public class HeaderRequestOriginParser implements RequestOriginParser { Override public String parseOrigin(HttpServletRequest request) { // 优先取自定义Header很多内部系统约定用X-Origin标识调用来源 String origin request.getHeader(X-Origin); if (origin ! null origin.trim().length() 0) { return origin; } // 兜底返回一个固定值避免白名单模式下误伤没有来源标识的请求 return default; } }这个类必须是Spring管理的Bean否则SentinelWebInterceptor拿不到它授权规则会静默失效。还有一个容易踩的坑如果在项目里自定义了WebMvcConfigurer的addInterceptors方法要注意别覆盖掉Sentinel的拦截器注册否则整个Sentinel链路都不会生效。另外来源解析和资源名解析是两回事。资源名解析走的是UrlCleaner用来把/order/create/123清洗成/order/create/*来源解析走的是RequestOriginParser只负责回答“这个请求是谁发来的”。这两个逻辑不要混在一起。2.3 控制台配置步骤与白名单实战假设现在有一个下单接口/order/create我们希望只允许来源为gateway的请求访问其他来源一律拒绝。操作很简单在控制台左侧菜单进入“授权规则”点“新增授权规则”资源名填/order/create授权类型选“白名单”来源应用填gateway保存后这条规则就生效了。规则底层逻辑等价于AuthorityRule rule new AuthorityRule(); rule.setResource(/order/create); rule.setLimitApp(gateway); rule.setStrategy(RuleConstant.AUTHORITY_WHITE); AuthorityRuleManager.loadRules(Collections.singletonList(rule));保存后可以启动一个请求不带X-Origin头去访问这个接口会看到类似SentinelBlockException: AuthorityException的异常带上X-Origin: gateway就能正常通过。实践中我建议同时配置一套黑名单规则来封杀恶意调用者比如来源标识为spider的请求AuthorityRule blackRule new AuthorityRule(); blackRule.setResource(/order/create); blackRule.setLimitApp(spider); blackRule.setStrategy(RuleConstant.AUTHORITY_BLACK); AuthorityRuleManager.loadRules(Collections.singletonList(blackRule));这里有一个细节授权规则的资源名必须和Sentinel埋点的资源名完全一致。Spring MVC适配器默认用请求URI作为资源名所以/order/create这个写法没问题如果项目里使用了自定义埋点SphU.entry(createOrder)那授权规则的资源名就要填createOrder而不是URL。3. 系统规则拆解五个维度的阈值怎么定、怎么生效系统规则在控制台里看上去更简单一行配置五个可选项。但它的内部机制比授权规则复杂不少因为涉及机器级指标的采集和入口流量的统计。3.1 五个维度背后的含义系统规则的五个维度分别是维度参数名含义典型设置参考LoadhighestSystemLoad系统当前Load1分钟平均仅Linux等类Unix系统有效核数的1.5倍到2倍比如4核机器设6.0CPUhighestCpuUsageCPU使用率0.0到1.0之间0.6到0.8留出缓冲RTavgRt所有入口流量的平均响应时间单位毫秒业务P99耗时的1.5倍左右线程数maxThreads入口流量的并发线程数参考压测得出的最大并发数入口QPSqps所有入口流量的总QPS峰值QPS的70%左右注意这里的RT和线程数都是“所有入口流量”的聚合指标不是单个接口的指标。设置RT300意味着所有Web请求的平均RT超过300ms就会触发全局拦截这在某些长接口业务里会显得很激进。比如有一个接口本身要跑5秒但它的调用量很低平均RT只有200ms看起来不会触发如果有一天这个慢接口调用量突然上来平均RT被拉高到300ms以上那所有接口都会被拦这其实是合理的——因为整机已经被慢调用拖住了。Load维度的判断逻辑是只有当系统Load超过阈值且当前并发线程数超过系统容量时才会触发单纯Load高但线程数不高不触发。这个设计是防止机器负载瞬间尖峰导致误杀。在Windows上测试时Load指标拿不到数据所以源码里直接跳过这个维度的判断也就是说你在Windows上调Load规则它永远不会生效。3.2 入口流量的统计机制系统规则里反复提到“入口流量”这个词很多人没细想。Sentinel把流量分为IN和OUT两种类型Web请求默认是IN微服务内部调用通常也是IN而OUT代表出口调用。系统规则只统计入口流量底层通过SystemMetricStatistics做滑动窗口聚合默认统计窗口是1秒每5秒检查一次阈值。在默认的Spring MVC适配器场景下所有被SentinelWebInterceptor拦截的请求都会自动标记为IN并累加到入口统计里。所以如果只配置了入口QPS500那应用上所有Web请求的总QPS超过500就会全部被拦下来。这个行为对单体应用来说很直观但在微服务架构下要格外小心你开了多个实例每个实例的入口QPS是独立的控制台上配置的500是单机值不是集群值。还有一个容易走弯路的地方系统规则在控制台里只有“系统规则”一个入口配置的规则是挂在默认入口资源Constants.ENTRY_RESOURCE上的。这个默认入口资源可以理解为“应用的总入口”所有自动埋点的请求都会归到这里。但它也可以被替换Sentinel提供了一个扩展点SystemRulesManager.registerSystemRulesProvider大部分场景用不到只需要知道有这么一个机制就好。3.3 扩展入口规则与压测验证我用一个实际案例来演示系统规则的完整落地过程。假设有一个4核8G的服务器预期峰值入口QPS在800左右线上要求P99 RT不高于300msCPU不能打满。先通过一次简单的压测拿到数据压测工具设置200并发跑5分钟得到平均RT180ms、入口QPS峰值1050、CPU最高81%。这些数据就是设置阈值的依据。控制台新增系统规则配置一组合理阈值SystemRule rule new SystemRule(); rule.setHighestSystemLoad(6.0); rule.setHighestCpuUsage(0.8); rule.setAvgRt(300); rule.setMaxThreads(200); rule.setQps(800); SystemRuleManager.loadRules(Collections.singletonList(rule));保存后再次压测当入口QPS超过800时新请求开始被拒绝控制台能看到SystemBlockException的拦截记录CPU稳定在80%以下服务不再响应超时。这里要提醒一下系统规则的阈值不是越快越好。如果设置得过低比如CPU0.5业务上稍微有点波动就触发全局拦截反而会影响正常流量。设置的原则是“在业务可接受的延迟范围内尽量多抗流量”具体数值要基于压测数据迭代调整。关于代码方式配置规则生产环境有争议。用控制台配置的好处是改动即时生效、方便观察用代码配置的好处是随应用启动一起加载不依赖控制台连接。我的建议是测试环境用控制台快速调参确定阈值后固化到配置文件里用Sentinel的DataSource机制加载避免生产环境控制台不稳定导致规则丢失。4. 避坑指南这两类规则最容易踩的坑这两类规则看着简单实际用起来问题不少。我整理了在多个项目里真实遇到的五类问题基本可以覆盖大部分排查场景。4.1 授权规则配了不生效这是排在第一的高频问题。控制台里规则明明保存了但请求进不来也出不去心里没底。查这个问题的顺序一般是第一确认有没有实现RequestOriginParser并且类上标了Component。没有实现请求来源解析控制台填的来源应用名称就永远匹配不上白名单模式下所有请求都会被拒绝黑名单模式下规则形同虚设。第二确认请求来源解析返回值和控制台填写的值完全一致。解析逻辑里做了大小写转换或去空格控制台填的是Gateway解析返回的是gateway匹配不上。建议解析逻辑只做trim不做其他转换避免自己给自己挖坑。第三确认Sentinel链路真的生效了。检查过滤器或拦截器有没有被自定义配置覆盖最直接的办法是看请求日志里有没有Sentinel相关输出或者故意配一个流控规则验证一下基础链路是否正常。4.2 系统规则在Windows上不生效很多人开发机是Windows配了Load规则后发现压测怎么都触发不了不是规则写错了而是Windows没有Load这个概念代码里检测到不支持就直接跳过了这个维度的判断。如果要在开发阶段验证系统规则用CPU、RT、线程数、QPS这四个维度Load维度放到Linux测试环境再验。另外还要注意CPU使用率的获取在不同JDK版本下表现有差异遇到CPU阈值始终不触发的情况先看机器监控里CPU是不是真的超过了阈值有时候虚拟机抢占导致监控工具看到的CPU很高但Java层面拿到的数据有延迟。4.3 网关场景的来源解析是另一套APISpring Cloud Gateway场景下Sentinel的接入方式不是SentinelWebInterceptor而是SentinelGatewayFilter请求来源解析的注册方式也完全不同。需要通过GatewayCallbackManager.setRequestOriginParser来注册Configuration public class GatewayConfiguration { PostConstruct public void init() { GatewayCallbackManager.setRequestOriginParser(exchange - { String origin exchange.getRequest().getHeaders().getFirst(X-Origin); return origin ! null ? origin : default; }); } }很多人在网关场景下依然按Web MVC的方式写Component实现RequestOriginParser结果授权规则完全不生效就是因为这套适配器根本不会从Spring容器里去找那个接口。网关场景的资源名默认是路由ID不是URL路径配置授权规则时要用路由ID否则也匹配不上。4.4 阈值设置不能只靠感觉系统规则的五个维度不是所有都要配更建议只配置当前需要的那一两个维度避免相互干扰。比如只配入口QPS和CPU两个维度其他维度保持未配置状态Sentinel会跳过未配置的判断。如果五个维度全部配满可能出现某个维度先触发导致其他规则来不及验证的情况给排查增加难度。阈值方面常见的错误有两种一种是把入口QPS设成单接口压测的吞吐量但入口QPS是所有接口的总和二者差好几倍另一种是把RT设成单个接口的P99但系统规则统计的是全局平均RT和单接口的延迟不是一个概念。这两种错都会导致线上误触发压测时需要特别区分。4.5 授权规则和系统规则的配合思路最后聊聊这两类规则的配合。授权规则、系统规则、流控规则的触发顺序是授权规则最先判断系统规则次之流控规则最后。也就是说一个被授权规则拒绝的请求不会计入系统规则的入口统计也不会进入流控判断一个被系统规则拦截的请求不会再继续往下走流控逻辑。基于这个顺序我通常会这样设计最外层用授权规则挡住明确不允许的调用方这是第一道闸第二道用系统规则保护整机资源这是保命闸再往内才是流控、降级、热点这些精细化规则管控单个接口的流量形态。我在实际项目里第一次用系统规则时把入口QPS设置成了2000结果白天流量稍微一冲就直接全局拦截业务方半夜打电话来找我。后来把阈值改到压测峰值的50%再逐步上调用了一周才找到安全值。这个经验是任何规则上线前都先在压测环境压一轮拿到真实数据再填阈值宁可先收紧再放宽也不要一开始就给一个想当然的大数字。生产环境里还有个小技巧系统规则触发时会拒绝入口流量但返回给调用方的异常是BlockException如果你统一封装了全局异常处理器记得把SystemBlockException也处理掉否则调用方拿到的可能是500而不是预期中的提示信息。授权规则抛出的AuthorityException同理也应该在异常处理里做统一兜底给前端一个明确的提示而不是裸抛异常。这一篇把授权规则和系统规则讲完Sentinel的规则体系就补得差不多了。下一篇准备聊规则持久化和动态数据源这应该是生产环境里最后一块拼图了。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表