接口一上量就慢、就 429、就超时,很多时候不是机器不够,而是没分清瓶颈在网络、连接数、下游还是排队策略。这篇按「先量基线再定位再改架构」的顺序走一遍,给你一张排查清单和几种兜底做法,并说明哪些做法在什么情况下不适用。
接口一上量就慢、就 429、就超时,很多人第一反应是加机器,结果加完还是慢。问题往往不在机器数量,而在没分清瓶颈到底卡在哪一层:是网络链路、连接数、下游接口,还是自家排队和重试策略在互相打架。这篇按「先量基线、再定位、再改结构」的顺序走一遍。
先把顺序记住:没有基线就不要谈优化,没有分段计时就不要猜瓶颈。下面每一节都给你具体动作和判断标准,也标出哪些做法在什么场景下不该用。想先核实接口本身的延迟底数,可以到 /tools/speed-test 跑一遍再往下看。
第一步:先量基线,再谈优化
把单实例的吞吐上限、P95 延迟、错误率先压出来。没有这三个数,你分不清是代码慢还是资源少,也分不清该扩机器还是该改逻辑。压测时不要只盯平均值,平均值会把少数极慢请求藏起来,真正拖垮体验的是尾部延迟。
- 压测取基线用固定并发梯度往上加,记录每个梯度的吞吐和 P95。找到吞吐不再涨、延迟开始陡增的那个拐点,那就是单实例的实际上限。
- 按链路分段计时网关、应用逻辑、下游接口调用、数据库读写各记一段耗时。哪一段占比突然变大,瓶颈就在那儿,别凭感觉猜。
- 区分两种慢「并发上不去」看连接池和排队策略;「并发上去后单请求变慢」看资源争用和下游压力。两种病用药不一样。
一个常见误区是把「接口慢」和「服务撑不住并发」混为一谈。前者是单次调用耗时问题,后者是同时能处理多少路请求的问题。压测报告里这两个数字要分开看,否则优化方向会跑偏。
第二步:把并发收进可控范围
并发不是越大越好。无限堆请求的结果是下游被打崩,然后全链路雪崩。正确做法是先设并发上限,超出的部分进队列或快速失败,让系统在一个稳定的压力区间里工作。
- 并发上限要设,而不是让请求无限进入;超出部分要么排队要么立刻返回失败,别硬扛
- 队列要有最大等待长度和超时,否则请求堆在队列里,用户最终拿到的全是超时
- 限额要分维度:按用户、按 Key、按接口各设一套,别用一个全局阈值一刀切
- 突发流量场景下固定阈值要留余量,或者用能动态调整的策略,否则正常抖动也会被误限
- 排队和限流的目标是保住已进入请求的成功率,不是让所有请求都进来试试看
排队策略还要看业务类型。面向用户的在线接口,超出容量就该快速失败并告知重试,不能让用户干等;内部批处理任务则适合排队慢跑,牺牲时效换成功率。
第三步:超时、重试与降级的取舍
超时和重试是两把双刃剑。设得太松,请求积压拖垮连接池;设得太激进,正常波动也会触发失败。重试更危险,配错了会让流量成倍放大,本来是下游抖动,结果被自家重试打穿。
| 配置项 | 怎么设 | 什么情况不适用 |
|---|---|---|
| 连接超时 | 短一些,只覆盖建立连接阶段 | 跨地域链路本身握手慢时,设太短会误杀正常请求 |
| 读取超时 | 按接口实际耗时分布定,流式和非流式分开 | 流式接口不能用同一口径,否则长连接会被提前掐断 |
| 整体超时 | 覆盖全链路,作为最后兜底 | 设得比读取超时还短就没意义,等于没兜底 |
| 重试次数 | 只对幂等且可恢复的失败重试,配退避 | 写操作和非幂等调用不要自动重试,会重复下单或重复计费 |
降级要有明确的触发条件,比如下游连续失败到一定比例就切备用通道或返回精简结果。触发条件要事先定好并写进代码,而不是等全线挂掉才临时手工切。
第四步:留够可观测与扩容余地
性能问题最怕事后无据可查。日志至少记下请求标识、耗时、状态码、命中的通道和用量,出问题时才能顺着链路还原慢在哪、贵在哪。没有这些字段,复盘只能靠猜。
- 对延迟、错误率、队列长度、并发占用做监控告警,出问题前先看到趋势
- 扩容能解决一部分问题,但如果是下游额度或单点瓶颈限制,加机器没用
- 单点瓶颈常见于共享连接池、集中式缓存、单一上游通道,要提前识别
- 定期复盘高峰期数据,比出事后再查省力得多
扩容和限流不是二选一。合理顺序是先限流保住稳定,再看监控确认是资源不足还是结构问题,资源不足才扩,结构问题则要从路由和并发控制侧改。上游额度相关口径可以到 /ai-nav/category/ai-api 核对,别凭印象判断。
哪些情况下这些做法不适用
上面这套流程是针对有真实并发压力的接口服务。如果你服务的流量很低、几乎没有并发,上来就做复杂排队和降级属于过度设计,代码复杂度换不来任何收益,反而增加故障点。
- 下游本身有硬性配额时,本地优化突破不了上游天花板,先去核对额度口径而不是拼命调本地参数
- 内部批处理和面向用户的在线接口策略不同,前者适合排队慢跑,后者要优先保住响应时间
- 单机低流量服务不需要复杂限流和降级,简单超时加日志就够了
- 如果瓶颈已经被确认在数据库慢查询或第三方接口,优化排队策略是治标不治本
常见问题
并发一上去就报 429,是不是服务器配置太低?
多数情况不是配置问题,而是超过了上游或本地的并发额度。先确认是哪一层在拒绝:如果是下游返回的限流,加机器也没用,要靠排队、分批和退避来削峰;如果是本地连接数或线程池打满,再看资源水位。两层的排查路径不一样,别一上来就升配。
排队和限流能不能只做一个?
两者解决的是不同问题。限流决定「放进来多少」,排队决定「放不下的怎么等」。只限流会让突发请求直接被拒,只排队会在下游变慢时把请求全积压。稳妥做法是先限流卡住入口,再给队列设最大长度和等待超时,超出的快速失败并返回可重试提示。
加了缓存和重试之后还是慢,往哪看?
优先看下游调用占比和超时设置。很多接口慢是卡在等一个慢下游上,而不是本地算得慢。把每次请求的分段耗时打出来,确认是连接建立慢、首字慢还是整体慢,再决定是调超时、换通道还是拆成异步。没有分段数据就优化,基本等于蒙。