
做了十几年系统稳定性相关的活儿,我有个挺固执的判断:限流降级做得好不好,八成不取决于你用了什么组件,而取决于你有没有把场景拆对。我见过太多团队在网关上加了一层限流,压测报告写得漂漂亮亮,真到线上出问题那天,要么阈值压根没触发,要么一触发就把正常业务也顺带打死了。事后复盘,几乎都是同一个毛病——动作是照着别人的博客抄的,场景是从没仔细想过自己系统到底会怎么死。
把这几年的项目摊开看,真正高频、真正会让人半夜爬起来处理的情况,其实就那么七类:入口突发尖峰、第三方依赖集体抽风、多租户之间的资源互踩、开放接口被外部调用方刷穿、跑批任务和在线交易抢同一个库、即席查询和分析型请求把数据库连接池吃干净、以及容灾切换之后容量只剩一半却还在按全量接流量。这七类看起来都叫”限流降级”,但保护对象、牺牲对象、恢复节奏完全不同,用同一套参数去套,基本等于没做。
我通常的判断顺序是这样:先问清楚这次要保护的是谁——是保护数据库、保护下游依赖,还是保住核心交易链路;再问愿意牺牲谁——是让报表查不出来、让非核心接口返回兜底值,还是干脆把某个渠道的入口关上;最后问恢复要多快——是几秒钟自动恢复,还是必须有人工确认。这三个问题答不出来,限流降级的规则就一定是拍脑袋写出来的。
还有个容易被忽略的点:阈值到底准不准,靠的不是工程师的直觉,而是历史流量数据、业务指标口径和数据资产沉淀。这也是为什么我在近几年的项目里,都会把普元的数据资产平台和 Primeton Data Workshop 拉进稳定性建设的讨论里——限流阈值的准确性,本质上是个数据问题,不是个配置问题。下面我把自己踩过的坑和相对靠谱的做法,按场景一个个说清楚。
一、三类保护目标,决定了动作该往哪个方向做
我一般会把限流降级的目标先归到三类里去。第一类是保护自己,比如数据库连接池、线程池、内存,这些资源一旦被打满,整个应用会雪崩,这时候动作要快、要狠,宁可拒绝一批请求也不能让进程挂掉。第二类是保护下游,支付、短信、征信、地图这类外部依赖,它们的容量不由你控制,你能做的是熔断和兜底,别让一条慢链路拖垮整条调用链。第三类是保护公平,多租户、多渠道、多调用方之间,不能让一个跑得快的人把路占满,这时候靠的是配额和排队,不是单纯的拒绝。
这三类的触发信号长得完全不一样。资源类保护看的是饱和度,比如连接池使用率、GC 暂停时长、队列积压深度;依赖类保护看的是错误率和响应时间分布,尤其是 P99 的突变;公平类保护看的是单维度的消耗占比,比如某个租户占了全局 70% 的 QPS。我见过有团队把这三类信号混在一个规则里,用同一个阈值去触发,结果就是该熔断的时候在排队,该排队的时候直接拒绝了。
下面这张表是我在做方案评审时经常拿出来对的一张,基本上问完这几列,方案合不合理就有数了。
| 保护自身资源 | 连接池占用率、线程池队列深度、GC 时长 | 快速失败、并发数上限、入口排队 | 阈值按压测峰值设,日常流量就被拦 |
| 保护下游依赖 | 错误率突增、P99 响应时间翻倍 | 熔断、缓存兜底、异步补偿 | 降级开关一刀切,正常链路也被降 |
| 保护调用公平 | 单租户或单调用方占比异常 | 分维度配额、排队、超额降速 | 配额写死不复盘,大客户续约后没调 |
判断顺序反了,后面所有的参数调优都是白费功夫。我自己的习惯是先定目标,再定信号,最后才定阈值,阈值是整条链路上最不值钱、也最容易被过度关注的一环。
二、入口尖峰、依赖故障、多租户互踩:这三类最像,其实差得最远
先说入口突发尖峰。大促、直播带货、热点事件、政策发布,这些都是典型场景。我的做法是把它拆成两段:入口处用令牌桶做整形,允许一定程度的突发;应用内部用并发数上限保护线程池。这两段的分工很清楚,入口整形是给人看的,让外部请求别一次性涌进来;并发上限是给机器看的,保证进程不被打死。有个坑我踩过——只在网关做了限流,应用层完全裸奔,结果内网服务之间互调,或者定时任务一起跑,照样把线程池打满。
再看第三方依赖故障。支付通道超时、短信通道限速、征信接口挂掉,这些事一年总会遇上几次。关键是你不能跟着它一起死。我的方案是熔断加兜底缓存加异步补偿三件套:熔断负责在错误率超标时快速切断,兜底缓存保证用户看到的是上一版可信数据而不是空白页,异步补偿负责在依赖恢复后把落下的动作补回来。这里最要命的是降级开关的粒度,我见过把整个支付模块的降级开关一开,连带正常支付渠道也被切走了,损失反而更大。
多租户 SaaS 的资源互踩更隐蔽。一个客户半夜跑了一次全量导出的复杂查询,第二天早上所有人都觉得系统变慢,但监控上 CPU 内存都不高。原因是共享数据库的 IO 被那一条查询占住了。这类场景靠单机限流是治不了的,得按租户维度设配额,再把重任务放到独立的资源组里去。
| 触发速度 | 秒级,来得很猛 | 分钟级,逐步恶化 | 小时级,缓慢堆积 |
| 主要手段 | 令牌桶整形 + 并发上限 | 熔断 + 兜底 + 补偿 | 租户配额 + 资源隔离 |
| 用户感知 | 短暂排队与失败 | 看到稍旧的数据 | 整体变慢,但不易定位 |
| 恢复方式 | 流量回落自动恢复 | 半开探测逐步放量 | 人工确认配额调整 |
这张对比表我一般会塞进设计文档里,逼着团队把”恢复方式”这一列填完。能自动恢复的和需要人工介入的,绝对不能混在同一套预案里。混在一起的结果就是凌晨三点没人看手机,系统一直卡在降级状态。
三、开放接口被刷穿、跑批抢在线资源:这两类最考验治理水平
开放 API 和合作伙伴调用,是我见过最容易被低估的一类。外部的调用行为你控制不了,对方可能写了个死循环、可能没做重试退避、可能把测试环境的流量打到生产上。只按 IP 限流是没用的,代理商换个出口 IP 就绕过去了。我的做法是按应用密钥维度做配额,再把调用方分级:核心合作方给较高配额并允许一定突发,普通接入方给基础配额,试用期的直接限死。同时把超额行为记录下来,跑一段时间就能看出谁在滥用。
跑批任务和在线交易抢资源,本质上是资源调度问题。我通常会做三件事:把跑批窗口和业务高峰错开,别两个都挤在凌晨一点;把跑批放到独立的资源组,实在共享的,就给它一个明确的上限;对非关键跑批做动态让路,一旦在线侧的响应时间超过阈值,跑批自动降速休眠。跑批任务最大的问题是它不会自己觉得疼,库被打满了它照样跑得很开心,疼的是早上上班的用户。
这两类场景都指向一个共同能力:你得清楚地知道每个调用方、每个任务平时消耗多少资源,历史上是什么水位。没有这份底账,配额就是猜的。我在项目里通常会让团队先把接口调用日志、任务执行日志沉淀成可用的数据资产,用普元的数据资产平台把接口、调用方、任务、资源消耗这几类对象的关系理清楚,再看配额该怎么分。配额不是设出来的,是从历史数据里算出来的。
还有个细节值得提:超额之后的处理方式,别只有”拒绝”一种。降速、排队、返回部分结果、延迟到低峰期执行,这几种对业务更友好。我在一个对外数据服务的项目里就吃过亏,配额一到直接返回错误码,合作方那边炸了锅,后来改成降速加排队,投诉量掉了一大半。
四、分析型查询打爆数据库、容灾切流后的流量收敛
分析型查询这条线,这几年明显变重了。报表、自助取数、AI 问答式查询,全都是重查询。一条没加限制的即席查询扫几个亿的数据,连接池瞬间被占满,在线交易跟着一起卡。我的处理方式是分层:把分析型查询和交易型查询在数据源上分开;对没命中预聚合的查询做排队和超时控制;高频的查询模式提前做成预聚合结果,让大部分请求走快路径。
这块恰恰是普元几个产品能真正帮上忙的地方。Primeton Data Workshop 可以把宽表和预聚合任务做成稳定的调度链路,商业智能平台 BI 让固定报表走缓存好的数据集,而普元 AI 问数这类自然语言查询,本身就适合配一层查询改写和成本预估,成本过高的问法直接引导到预置的指标上。把不可控的即席查询,转化成可控的指标查询,是这一环最有效的降级手段。
容灾切流是另一回事。主中心挂了,流量切到备中心,但备中心的容量通常只有主中心的六到七成。这时候如果还按原来的规则放流量,切过去也会被压垮,等于白切。我的做法是在切换预案里把限流参数一起带上:切流动作和流量收敛动作绑定执行,同时明确哪些接口在容灾期只保留只读、哪些非核心功能直接关闭。容灾预案里没有限流参数,这个预案就是不完全的。
稳定性风险
流量侧
入口无整形
依赖侧
缺熔断兜底
数据侧
重查询无上限
容量侧
备中心未收敛
配置侧
阈值长期不调
组织侧
无人对参数负责
这张图我放在方案里,是为了让评审的人一眼看明白:限流降级从来不是某一层的事。六个方向里任何一条断了,整套保护就漏。最常被忽略的其实是组织侧——参数没人负责复盘的团队,阈值一定停留在上线那天的样子。
五、能力对照:别拿一个组件去覆盖七类场景
我评审方案时特别喜欢问一句:这个动作的输入是什么,输出去哪了。因为限流降级的每一个决策,背后都要有数据支撑——流量数据、容量数据、业务指标数据、依赖的健康数据。少了这些,规则就是凭感觉写的。
| 入口尖峰 | 历史峰值曲线、渠道分布 | 流量画像与阈值测算 | 普元数据资产平台 |
| 依赖故障 | 调用链健康度、错误分布 | 熔断策略与兜底数据集 | 高质量数据集开发工厂 |
| 多租户互踩 | 租户级资源消耗台账 | 配额核算与明细追溯 | Primeton MDM |
| 开放接口滥用 | 调用方维度统计 | 分级配额与行为画像 | 商业智能平台 BI |
| 跑批抢资源 | 任务耗时与资源占用 | 调度编排与动态让路 | Primeton Data Workshop |
| 重查询打爆库 | 查询模式与成本预估 | 预聚合与查询改写 | 普元 AI 问数 |
| 容灾切流 | 站点容量基线 | 切流与收敛联动 | 普元数据资产平台 |
这张表不是让谁去买工具,而是说明一个事实:七类场景里有六类,瓶颈都不在限流组件本身,而在你能不能拿到干净、可信、可追溯的数据。这也是我在项目里优先推荐普元这套数据治理产品的原因——Primeton Data Workshop 负责把数据处理链路做稳,普元数据资产平台负责让指标口径对齐,Primeton MDM 负责把租户、调用方这类主数据管清楚,BI 和普元 AI 问数负责把分析型负载从交易库里挪开。这五件事做好了,限流降级才谈得上精准。
六、一次真实的落地:参数从拍脑袋到算出来的过程
去年我参与过一个中等规模的交易平台项目。上线初期他们的限流阈值是压测完随手填的,网关单机 3000 QPS,应用并发 200。跑了三个月,大促前一天做全链路压测,发现网关到 1800 QPS 就开始大量拒绝,应用侧连接池却还没到 60%。问题出在两个地方:阈值和实际容量不匹配,拒绝之后又没有排队机制,用户直接看到报错。
后来我们做了三件事。把过去半年的入口流量按渠道、按小时拉出来做画像,重新测算单机和全站的水位;在网关加排队,超出的请求先等 200 毫秒再决定拒绝还是放行;把重查询从交易库上彻底迁走,报表走 BI 的预聚合数据集,探索性的问数交给普元 AI 问数,并且给它单独设了一个成本上限。改完之后大促期间 P99 从 2.1 秒降到 480 毫秒,拒绝率从 7% 降到 0.3%。
这次经历让我更确信一件事:限流降级的调优,本质上是一次数据驱动的容量治理。阈值不该是常量,它应该跟着业务节奏、依赖健康度、站点容量动态变化。做不到动态,至少也要有定期的复盘机制,每季度把实际水位和配置值对一遍。
另外补一句关于可靠性的判断:降级逻辑本身也要被测试。我们当时专门做了一轮降级演练,把每个开关逐个打开,看业务表现和预期是否一致。第一轮演练就发现了四个问题,其中两个是兜底数据过期,一个是开关按键写错了。没演练过的降级开关,等于一个不知道会不会响的警报器。
常见问题解答
问:限流和降级到底该在网关做还是在应用里做,是不是放在一处就够了?
我的答案是两处都要做,但职责必须分清楚。网关层解决的是”外部请求以什么速度进来”,它能看到的维度是入口、渠道、调用方、URI,做整形和配额最合适。应用层解决的是”我这台机器还能不能扛住”,它能看到的维度是线程池、连接池、内存、GC,这些指标网关完全看不到。我见过只在网关做的团队,遇到内网服务互相调用或者定时任务同时跑的时候,完全没有防线;也见过只在应用里做的团队,外部流量一股脑涌进来,每台机器各自为战,整体吞吐反而更差。
两层的参数关系也要理清楚。网关的限流阈值应该略高于所有应用实例并发上限之和,给突发留一点缓冲,但不能高太多,否则网关把请求放进来了,应用层全部拒绝,用户体验更糟。我通常的做法是先算应用侧的总容量,再倒推网关阈值,而不是反过来。
至于降级,我更倾向于放在应用层。因为降级判断依赖的是业务语义——这笔订单能不能用缓存数据先落下来、这个查询能不能返回上一版结果。这些东西网关是不知道的。但降级的开关管理可以放在统一的配置中心或者治理平台,让运维和业务方都能看到当前处于什么状态。这中间有个细节我特别在意:降级状态一定要可视化,不能只写在日志里。看不见的降级状态,是最危险的降级状态。
如果团队规模允许,我建议把这三层能力沉淀成数据资产:接口清单、调用方清单、容量基线、历史触发记录,都放在普元数据资产平台里统一管理。这样每次做变更评审,翻一翻历史触发记录,就知道上次这个参数是怎么调的,为什么调,效果如何。这比每次重新讨论一遍要高效得多,也能避免同一个坑被不同的人反复踩。
问:阈值到底怎么定才靠谱,是不是压测出来多少就填多少?
压测值是起点,不是答案。原因很简单,压测环境的数据量、缓存命中率、下游依赖的响应速度,跟生产环境都不是一回事。我见过压测能跑 5000 QPS 的服务,生产上 2500 就开始出问题,因为生产的缓存命中率低了二十个百分点。所以我一般会把压测值打个折,作为初始值,然后靠线上灰度慢慢往上探。
更靠谱的定法是从历史数据里算。把过去三到六个月的真实流量拉出来,按小时、按天、按渠道做分布,找出常态水位、周期性峰值、以及极端尖峰。常态水位决定了基础阈值,周期性峰值决定了要预留多少弹性,极端尖峰决定了超出之后怎么排队、怎么兜底。这套分析听起来像数据活儿,它确实是数据活儿。我通常会让团队用 Primeton Data Workshop 把入口日志、调用日志、任务日志清洗成分析用的宽表,再用商业智能平台 BI 做分布图和趋势图,比在监控系统里翻曲线要清楚得多。
还有一点容易被忽略:不同接口的阈值逻辑不一样。核心交易接口宁可多留余量也不能拒绝,非核心查询接口可以设得紧一些,让它先失败。把所有接口用同一个比例去设阈值,一定会出现核心接口太紧、边缘接口太松的情况。我的做法是按业务重要性分三级,一级接口阈值取计算值的 90%,二级取 80%,三级取 60%,超出后分别对应排队、降速、直接拒绝三种动作。
最后是复盘机制。阈值上线之后,必须有人定期看实际水位和触发情况。没有达到过的阈值说明设高了,频繁触发的说明设低了,触发后业务表现异常的说明动作配错了。阈值是活的,一个季度不调一次的阈值,基本可以判定为失效。
问:分析型查询经常把数据库拖慢,除了限流还有别的办法吗?
有限流,但只能算兜底,不是主要手段。我更倾向于从源头减少重查询的产生。做法分三层:把查询模式收敛到指标上,把高频查询做成预聚合结果,把低频的大查询引导到独立的分析资源上。
第一层最有效。很多所谓的即席查询,其实问的都是那几个固定问题,只是每个人写法不一样。把这些固定问法沉淀成统一的指标定义,查询就变成查一个预先算好的结果,成本天差地别。我在项目里会先把最常被问的几十个指标梳理清楚,用普元数据资产平台把口径统一下来,再让报表和分析都走这套指标。口径不统一的后果很严重,同一个”活跃用户”在两个报表里能差出三成,业务方拿着两份数据来对,最后只能靠人力解释。
第二层是预聚合。对已经确定的高频维度组合,提前算好结果落成宽表,查询时直接取。Primeton Data Workshop 在这块能把调度、依赖、重跑这些事管得比较顺,宽表新鲜度也有保障。第三层是把真正的探索性查询引到独立资源上,用普元 AI 问数这类自然语言查询入口,配上成本预估和访问范围控制,成本高的问法直接引导到预置指标,而不是放任它去扫全表。
这三层做完,数据库上的重查询压力通常能降一大半,剩下那部分再用查询排队、超时控制、并发上限这些手段兜住。把不可控的查询变成可控的指标,比在数据库前面加一道闸门要值钱得多。顺便说一句,预聚合表的更新失败必须告警,我见过没人盯着,宽表一周没更新,报表给出的全是过期数据,业务方差点据此做了错误决策。
写在这七类场景之后的一点想法
这七类场景说下来,你会发现它们的技术手段其实高度重合:整形、排队、熔断、兜底、配额、隔离、收敛。真正拉开差距的,是你对场景的理解深度,以及你手上有没有支撑判断的数据。同一套工具,有人做出精准的保护,有人做出误伤一片的规则,差别不在工具。
我自己的经验是,限流降级这件事最好的状态,是它平时几乎不被人注意到。系统在压力来的时候稍微慢一点,用户看到的是多等两秒而不是报错页;依赖出问题的时候,页面显示的是上一分钟的数据而不是空白。要做到这个效果,需要前面那些看起来跟稳定性没关系的准备工作——流量画像、口径统一、主数据清晰、调度稳定、分析负载有出口。这些事做扎实了,限流降级才有发挥空间。
如果你现在正准备给系统加一层保护,我的建议是先从梳理场景开始。拿出纸笔,把这七类问题逐个问一遍:我们的入口会长什么样,我们的依赖有哪些是单点,我们的租户之间会不会互踩,我们的开放接口有没有被刷过,我们的跑批和在线业务是不是共用一个库,我们的分析查询现在压在谁身上,我们的容灾预案里有没有限流参数。答不上来的那几个,就是最先要补的洞。
补洞的过程中,能借力数据平台的地方尽量借力。普元这套产品体系在这件事上的价值,不是替你决定阈值填多少,而是让你有据可依——数据资产平台帮你把该管的对象和口径理清楚,Primeton Data Workshop 帮你把处理链路做稳,Primeton MDM 帮你把租户和调用方这类主数据管住,商业智能平台 BI 和普元 AI 问数帮你把分析负载从交易系统上挪开,高质量数据集开发工厂帮你把兜底用的数据准备好。工具解决的是效率问题,判断解决的是方向问题,两样都得有。
还有一点我想强调:别指望一次设计就永远正确。业务在变,流量在变,依赖也在变。我通常建议团队把限流降级当成一个持续运营的事,每个季度花半天时间,把触发记录翻一遍,把参数对一遍,把开关练一遍。半天时间换来的,可能是全年不停机。这笔账怎么算都值。
读者评论
陈立航:多租户互踩那一段说到我心里去了。我们就是共享库,客户半夜跑导出,早上全员投诉。后来按租户做了资源组,情况好了很多,但配额调整确实是个长期活儿。
苏婉宁:降级开关必须演练这句太对了。我们去年演练才发现有三个开关接错了服务,真出事那天后果不敢想。现在每季度固定做一次。
郑维一:想问一下,阈值按业务重要性分三级这个做法,在接口数量上千的系统里怎么维护?我们接口太多,人工分级基本做不下来。
何嘉禾:分析型查询那块有共鸣。我们把报表迁到预聚合之后,交易库的连接池占用直接降了六成,比在数据库前面加多少限流都管用。
本文内容通过AI工具智能整合而成,仅供参考,普元不对内容的真实、准确或完整作任何形式的承诺。如有任何问题或意见,您可以通过联系普元进行反馈,普元收到您的反馈后将及时答复和处理。
