CPU 和系统负载上涨,是否意味着算力不足?发布后接口变慢,是旧实例容量减少,还是新实例尚未预热?业务流量突然增长,又该先限流还是先扩容?
本文从资源指标、发布过程和流量来源三个角度展开,说明如何定位瓶颈,以及如何在容量不足时保护应用与下游。
本文讨论以下 4 个问题:
- CPU、负载和磁盘:如何判断性能瓶颈?
- 发布后指标飙升,是容量不足还是预热未完成?
- 流量突然上涨,如何保护应用与下游?
- 有了扩容,为什么还要限流?
CPU、负载和磁盘:如何判断性能瓶颈?
判断瓶颈时,要把资源指标和业务表现放在一起看。CPU 利用率、系统负载或磁盘水位越过某个数字,通常意味着需要排查,不代表已经找到了原因。
CPU 利用率:看是否还有容量余量。按照经验主义,可以先把70%作为高负载时的规划水位,但它是经验起点,应结合接口延迟、错误率和流量变化调整。
系统负载:先分清任务在等什么。Linux的load average统计的是一段时间内以下两类任务数量的移动平均:
R:Runnable(可运行状态),正在运行或等待CPU的任务。D:Uninterruptible Sleep(不可中断睡眠),处于不可中断睡眠的任务,常见于等待 IO。
所以,load average不是 CPU 利用率,它更多反应的是一段时间内系统活跃的进程比例。负载升高时,需要先看主要增加的是R状态任务还是D状态任务,再结合 CPU 和 IO 指标判断。
内核大约每五秒更新一次负载统计。以一分钟负载为例,可以用下面的近似权重理解平滑过程:
假设旧 load 为 0.7,本次采样 R 与 D 状态任务合计为 2: 新 load ≈ 旧 load × 0.92 + 当前任务数 × 0.08 ≈ 0.7 × 0.92 + 2 × 0.08 ≈ 0.80这里的0.80是平滑后的平均值,不是本次任务数量,因此可以是小数。对于系统负载,笔者推荐的判断标准如下:
- 当负载主要由
R状态任务贡献,且 CPU 利用率接近饱和时,才更有依据怀疑 CPU 争用。 - 若主要由
D状态任务贡献,则应优先检查 IO 等待,不能按 CPU 核数直接下结论。 - 采用“核数 × 0.7”作为提前关注的经验水位,八核机器对应
8 × 0.7 = 5.6。这个值可以作为观察信号,但不是统一的性能瓶颈阈值;是否影响业务,仍要看延迟和错误率。
磁盘容量:看剩余空间和增长速度。可以用df -h查看容量,并将 70% 作为提前治理的经验水位。持续增长时,应评估何时耗尽空间,再按数据保留规则归档、清理或扩容。容量水位也不代表 IO 性能,磁盘延迟和吞吐需要另外检查。
发布后指标飙升,是容量不足还是预热未完成?
如果指标只在发布后几分钟内上涨,可以先检查两个方向:旧实例是否承担了额外流量,新实例是否尚未完成预热。
- 滚动发布导致剩余实例负载增加。假设一百台机器刚好承载业务流量,发布时分批下线几个实例,剩余实例仍要处理原来的请求量,RT、CPU 等指标就可能上涨。
- 新实例仍在初始化和预热。连接池、线程池、缓存以及 Java 热点代码编译,都可能让启动阶段的请求开销高于稳定运行阶段。
确认原因后,再选择对应措施。
如果使用的 JDK 发行版支持JWarmUp,可以记录代表性运行中的热点方法信息,在下次启动时读取记录并提前触发JIT 编译执行代码预热,确保流量走编译后的机器码:
另一种方式是让新实例先承接少量真实流量,通过请求逐步预热核心路径。观察 RT、P99 和错误率,确认耗时稳定后再增加流量。这种方式不依赖特定的 JWarmUp 支持,但需要控制预热期间对真实用户的影响。
两种方式都要与发布期间的容量安排配合:预热解决新实例尚未进入稳定状态的问题,容量预留解决旧实例暂时减少的问题。
流量突然上涨,如何保护应用与下游?
先区分流量来源,再决定怎么处理。热点事件或大促带来的正常请求,需要容量与应用保护;攻击流量则需要在入口处识别和过滤。
云上业务可以通过高防服务清洗大流量攻击,再结合 WAF 和入口限流规则识别、限制恶意请求。源站应限制回源来源,避免攻击者绕过入口防护直接访问。
正常业务流量突增时,要先知道集群和下游能承载多少。可以通过压测确定稳定容量,再使用 Alibaba Sentinel 按业务资源设置集群流控阈值。这里指的是 Alibaba Sentinel,区别于 Redis Sentinel。
例如,集群压测得到的稳定容量为 10000 QPS,可以先采用以下保护方案:
- 按 70% 的安全水位,将集群流控阈值设为
7000 QPS。 - 流量越过阈值时快速拒绝或降级:查询接口返回业务允许的缓存或降级数据,写入接口返回
429,客户端在保证幂等的前提下按重试策略处理。 - 执行扩容,等新实例预热完成、下游容量验证通过后,再提高流控阈值。
7000 QPS是本例采用的保护水位,不是通用配置。是否合理,要看业务允许的降级方式、扩容耗时和下游余量。
有了扩容,为什么还要限流?
扩容需要时间,请求却可能瞬间涌入。限流的作用,是在新增容量就绪前,把进入系统的请求控制在可承载范围内,减少超时和故障扩散。
判断是否扩容,还要考虑两个条件:
- 流量是否来自真实业务增长。如果是攻击或异常重试,增加机器可能只是让更多无效请求进入系统。
- 瓶颈是否在应用实例。如果数据库或下游已经饱和,只增加应用机器可能进一步放大压力。
例如,系统稳定容量为1000 QPS,突发请求远超这个数值。应先按既定规则限流,保护仍在处理的请求;再检查流量来源和瓶颈位置,决定是否扩容以及扩哪里。
因此,限流控制当前进入的请求量,扩容增加后续可用容量。两者需要配合,才能在流量上涨时维持服务。
小结
资源指标上涨是排查的入口,还需要结合业务延迟、任务状态和流量来源结合多项指标综合判断原因。发布时学会利用主动加热或者缓慢被动加热的方式平稳发布服务,结合系统阈值设定合理阈值进行限流熔断,而不是一口气承载所有流量,盲目扩容。
SharkChili· 禅与计算机程序设计的艺术
开源贡献
- mini-redis:教学级 Redis 精简实现 ·
https://github.com/shark-ctrl/mini-redis
关注公众号,回复【加群】获得笔者联系方式加入技术交流群