作者: andylin02
学习章节:第21章 应对过载(Handling Overload)
关键词:QPS陷阱、CPU资源建模、优雅降级、客户端节流、自适应节流算法、重要性分类、重试风暴、级联故障
一、引言:当负载均衡“失效”之后
在前两章,我们系统地学习了Google如何在全局层面(第19章)和数据中心内部(第20章)实现负载均衡——GSLB负责将用户引导到最近的数据中心,Maglev负责将请求分发到具体的后端实例。然而,无论负载均衡策略设计得多精妙,随着压力不断上升,系统的某个部位总会过载。
就像一条高速公路,无论收费站设计得多合理,早晚高峰总会堵车。面对这种“必然的过载”,SRE不能只是被动接受,而是要主动设计一套系统化的过载处理机制。本章的核心命题正是:如何让系统在过载时“优雅”地降级,而非“灾难性”地崩溃?
核心观点:避免过载是负载均衡策略的一个重要目标。但无论你的负载均衡策略效率有多高,随着压力不断上升,系统的某个部位总会过载。运维一个可靠系统的一个根本要求,就是能够优雅地处理过载情况。
本章内容与第20章“数据中心内部的负载均衡”紧密衔接——负载均衡解决的是“流量怎么分”,过载处理解决的是“分不过来怎么办”。
二、核心观点速览
| 维度 | 核心要点 |
|---|---|
| QPS陷阱 | 仅凭QPS评估容量不可靠,因请求成本差异极大,必须以CPU等资源消耗作为容量衡量标准 |
| 容量建模信号 | 推荐以CPU消耗作为资源配给的主要信号,原因:GC语言中内存压力自然转化为CPU压力;非GC环境可合理配置其他资源避免成为瓶颈 |
| 优雅降级 | 在过载时返回“降级响应”——响应质量降低但消耗资源大幅减少的替代结果 |
| 每个客户的限额 | 全局过载时服务应只向行为异常的客户返回错误,确保其他客户不受影响 |
| 客户端自适应节流 | 客户端基于滑动窗口统计requests与accepts,动态计算本地拒绝概率,主动拦截超限请求 |
| 重要性分类 | 将请求分为四种等级,过载时按优先级顺序拒绝请求,核心请求优先保障 |
| 资源利用率信号 | 以CPU使用率、活跃线程数/CPU核心数作为过载检测指标 |
| 过载重试策略 | 区分少量后端过载(可重试)与全局性过载(停止重试,直接返回错误) |
三、详细内容拆解
3.1 QPS陷阱:为什么QPS不是好指标
本章开篇就指出一个Google经过“惨痛教训”学到的重要规律:将容量建模为“每秒查询数”(QPS),或者使用请求的静态特征作为其消耗资源的代理指标(如“请求读取了多少个键”),通常会导致一个糟糕的指标。即使这些指标在某个时间点表现良好,比率也可能发生变化——有时变化是渐进的,但有时变化是剧烈的。
为什么QPS不可靠?
不同查询的资源消耗可能相差巨大。例如:
一个搜索请求可能只需扫描100篇文档,另一个则需要扫描10万篇
读缓存与读数据库的成本差异可达数量级
请求的成本随一天中的时间、客户端类型、数据分布等因素动态变化
更好的解决方案:直接测量可用资源的容量。例如,为一个数据中心中的某个服务总共保留500个CPU核心和1TB内存。直接使用这些数字来模拟数据中心的容量,效果会更好。
3.2 使用CPU作为容量建模信号
在大多数场景下,以CPU消耗作为资源配给的主要信号通常能获得良好效果。Google推荐使用CPU数量作为资源配给的主要信号,原因如下:
在带有垃圾回收(GC)机制的平台中,内存压力会自然地转化为CPU消耗的增加——内存不足时GC活动增加
在其他平台中,其他资源(如网络带宽、磁盘I/O)通常可以通过合理配置,使得它们在CPU耗尽之前不太可能成为瓶颈
如果过度配置非CPU资源的成本过高,Google会在考虑资源消耗时单独考虑每个系统资源。
3.3 优雅降级:过载时的“退路”
处理过载的一种选择是提供降级响应:响应不如正常响应准确或包含的数据少于正常响应,但更容易计算。
典型例子:
无需搜索整个语料库来为搜索查询提供最佳可用结果,而是仅搜索候选集的一小部分
依赖结果的本地副本,该副本可能不是完全最新的,但使用起来比违反规范存储更便宜
在极端过载的情况下,服务甚至可能无法计算和提供降级响应。此时,它可能没有立即选择,只能处理错误。
💡实践建议:要保证这个优雅降级的系统能正常工作,你可以经常让一小部分服务过载来测试这个系统。通过主动制造过载来验证降级机制是否生效,是DiRT测试思路的延续。
3.4 每个客户的限额:隔离“异常”流量
在一个完美的世界中,团队与后端依赖项的所有者仔细协调其启动,全局过载永远不会发生。但现实是:全局过载非常频繁地发生,特别是对于往往有许多团队运行许多客户端的内部服务。
当全局过载确实发生时,至关重要的是该服务仅向行为不当的客户提供错误响应,而其他客户不受影响。
实现方式:
服务所有者根据与客户协商的使用情况来配置容量,并根据这些协议定义每个客户的配额
当某个用户超过资源配额时,后端任务应迅速拒绝该请求,返回一个“用户配额不足”类型的错误,且该回复消耗的资源应远少于真正处理该请求
这种“按客户隔离”的策略确保单个“坏邻居”不会拖垮整个服务
3.5 客户端侧的自适应节流机制
这是本章最核心的技术实践。Google SRE通过一种称为“自适应节流”的客户端限流技术,从源头控制请求压力。
3.5.1 为什么需要客户端节流?
即使后端可以快速拒绝超过配额的请求,发送这些拒绝回复本身也会消耗一定数量的资源。如果拒绝回复的数量也很多,这些资源消耗可能十分可观。在这种情况下,后端可能在忙着不停地发送拒绝回复时一样会进入过载状态。
解决方案:客户端自行限制请求速度,限制生成请求的数量,超过这个数量的请求直接在本地回复失败,而不会真正发送到服务端。
3.5.2 自适应节流算法的工作原理
每个客户端记录过去两分钟内的两类关键指标(一般以滑动窗口实现):
| 指标 | 含义 |
|---|---|
| requests | 应用层代码发出的所有请求的总数 |
| accepts | 后端任务实际接受的请求数量 |
在正常情况下,这两个值基本相等。当后端开始拒绝请求时,accepts会开始小于requests。
核心机制:客户端允许继续发送请求,直到requests = K × accepts。一旦超过这个阈值,客户端开始自行节流——新产生的请求在本地以概率p直接被丢弃,不会真正发往后端。
3.5.3 算法公式
拒绝概率p的计算公式为:
p = (requests - K × accepts) / (requests + 1)
或等价地,当requests ≥ K × accepts时开始节流。
核心思想:随着客户端发送请求的速度加快(相对后端接受请求的速度来说),我们希望提高本地丢弃请求的概率。
3.5.4 K值的调优
| K值选择 | 效果 |
|---|---|
| K = 2(推荐初始值) | 允许后端接收约双倍于客户端估计的请求,更快将后端承载能力传递回客户端;代价是消耗额外后端资源,但能加速稳定、减少振荡 |
| 减小K | 自适应节流更激进,更早开始丢弃请求 |
| 增大K | 更宽松,允许更多超额发送 |
3.6 重要性分类:请求的“优先保障”
“重要性”是在全局配额和限制机制中非常有用的信息。Google归纳了四种类型,发现这四种分类可以描述大部分服务。
| 优先级 | 类型 | 处理策略 |
|---|---|---|
| 高 | 核心业务请求 | 过载时优先保障 |
| 中 | 常规业务请求 | 过载时逐步限制 |
| 低 | 后台批处理任务 | 过载时优先被拒绝 |
| 最低 | 非关键探测请求 | 过载时最先被拒绝 |
在实际处理中的应用:
当某个客户的全局配额不足时,后端任务按请求优先级顺序分级拒绝请求
当某个任务开始进入过载状态时,低优先级的请求会先被拒绝
自适应节流系统也会根据每个优先级分别计数
这一机制确保在高负载下,最重要的请求得到保障,而非核心功能被“战略性放弃”。
3.7 资源利用率信号:如何判断“过载”
Google的任务过载保护以资源利用率为核心指标,通常以当前CPU使用率(当前CPU消耗 ÷ 分配的CPU数量)为主;在需要时也会将内存利用率纳入判断。
Google使用的过载检测指标:
| 指标 | 计算公式 | 用途 |
|---|---|---|
| CPU使用率 | 当前CPU消耗 / 分配的CPU数量 | 判断系统是否接近容量极限 |
| 负载L | 活跃线程数 / 分配的CPU数量 | 更敏感的早期预警信号 |
当负载或资源利用率超过预设阈值时,系统会开始拒绝或降级请求,以防止过载并保证整体可用性。
为什么选择CPU作为核心信号?
在有GC的语言中,内存压力会转化为CPU压力
CPU消耗可以直接反映请求的“真实成本”
相比请求数,CPU消耗是更稳定的容量度量单位
3.8 过载时的错误处理与重试策略
3.8.1 区分两种过载场景
| 场景 | 特征 | 处理策略 |
|---|---|---|
| 少量后端过载 | 由单个耗资源请求或负载均衡短期不完美导致,数据中心整体仍有可用容量 | 立即重试(重试延迟通常仅为几个RTT,可忽略) |
| 大规模过载 | 大部分后端都过载,整个数据中心容量不足 | 应停止重试,直接向上层返回错误,避免浪费更多资源 |
3.8.2 重试策略的核心原则
重试请求与新请求等同对待,不额外保证命中不同的后端
在后端数量足够多时,概率上能实现自然分散,无需增加路由复杂度
限制单个请求的重试次数上限(Google推荐每个请求最多重试3次)
3.8.3 关于连接造成的负载
除了请求处理之外,连接本身也会消耗资源。即使后端在过载时快速拒绝请求,维护大量TCP连接、定期健康检查、SSL握手等操作仍会产生可观的资源消耗。因此,客户端节流不仅保护了请求处理路径,也保护了连接管理路径。
3.9 本章方法论总结
四、第21章知识点脑图总结
五、总结:一句话记住本章
应对过载 = 放弃QPS陷阱,以CPU为核心建模容量,通过客户端自适应节流主动限流,按优先级分级处理请求,在过载时优雅降级而非灾难性崩溃。
| 关键点 | 一句话概括 |
|---|---|
| 核心前提 | 无论负载均衡多有效,系统终将过载——优雅处理过载是可靠系统的根本要求 |
| QPS陷阱 | 仅凭QPS评估容量不可靠,必须以CPU等资源消耗作为容量衡量标准 |
| CPU建模信号 | 在GC语言中内存压力→CPU压力,使CPU成为资源配给的“一站式”信号 |
| 优雅降级 | 过载时返回质量降低但成本大幅减少的响应,而非直接崩溃 |
| 客户限额 | 全局过载时只向异常客户返回错误,保障大多数用户体验 |
| 自适应节流 | 客户端基于requests与accepts动态计算本地拒绝概率,主动拦截超限请求 |
| K=2初始值 | 推荐K=2,让后端接受约双倍请求,加速稳定且减少振荡 |
| 重要性分类 | 将请求分为四种优先级,过载时低优先级先被拒绝,保障核心业务 |
| 重试策略 | 区分局部过载(可重试)与全局过载(停止重试),避免重试风暴 |
| 过载测试 | 定期主动让一小部分服务过载,验证降级机制是否生效 |
行动建议:
本周内完成:审视服务的容量建模方式——是否还依赖QPS?是否已过渡到以CPU为核心的建模?统计客户端与后端之间的重试次数,识别是否存在“重试风暴”的风险
一个月内完成:为核心服务建立“重要性”分级机制,明确哪些请求在过载时需要优先保障;配置客户配额机制,确保单个异常客户不会影响其他客户;引入客户端自适应节流(参考Google算法,K=2起始)
一个季度内完成:定期主动制造过载(如通过压力测试模拟),验证降级机制是否生效;建立资源利用率监控,基于CPU使用率设置过载保护阈值;评估现有重试策略,确保在大规模过载时能自动停止重试
长期坚持:将持续优化容量建模纳入SRE的工程工作范畴;定期审查客户配额配置,确保与业务发展同步;在系统设计阶段就将降级方案作为必选项
六、高频考点自测
问题1:为什么Google认为QPS不是衡量服务容量的好指标?
参考答案:因为不同的查询可能具有截然不同的资源要求。请求的成本会因客户端类型、数据分布、一天中的时间等多种因素动态变化。如果仅以QPS建模容量,当请求的平均成本发生变化时(如新功能上线、数据分布改变),实际资源消耗会偏离预期,导致容量预估失效。Google通过惨痛教训认识到,将容量建模为“每秒查询数”或使用请求的静态特征(如“读取了多少个键”)通常会导致一个糟糕的指标。
问题2:Google为什么推荐以CPU作为资源配给的主要信号?
参考答案:在大多数场景下,以CPU消耗作为资源配给的主要信号能获得良好效果,原因包括:①在带有垃圾回收(GC)机制的平台中,内存压力会自然地转化为CPU消耗的增加——内存不足时GC活动增加;②在其他平台中,其他资源(如网络带宽、磁盘I/O)通常可以通过合理配置,使得它们在CPU耗尽之前不太可能成为瓶颈。
问题3:Google SRE的自适应节流算法是如何工作的?
参考答案:客户端记录过去两分钟内的两个关键指标:requests(应用层发出的请求总数)和accepts(后端实际接受的请求数量)。正常情况下两者相等;当后端开始拒绝请求时,accepts小于requests。客户端允许继续发送请求,直到requests = K × accepts(K推荐初始值为2)。一旦超过该阈值,客户端以概率p在本地拒绝新请求,不发送到服务端。随着客户端发送请求的速度加快,本地丢弃概率也随之提高,从而主动将发送速率拉回到可接受范围。
问题4:过载时如何区分“少量后端过载”和“大规模过载”?各自应该怎么处理?
参考答案:若跨数据中心负载均衡正常,理论上不应出现大量后端同时过载。少量后端过载通常由单个耗资源请求或负载均衡短期不完美导致,此时数据中心整体仍有可用容量,建议立即重试(重试延迟通常仅为几个RTT,可忽略)。若大部分后端都过载,说明整个数据中心容量不足,此时应停止重试,直接向上层返回错误,避免浪费更多资源。
问题5:为什么需要客户端侧的节流机制?仅靠后端限流有什么问题?
参考答案:即使后端可以快速拒绝超过配额的请求,发送拒绝回复本身也会消耗资源。如果拒绝回复的数量也很多,这些资源消耗可能十分可观,后端可能在忙着不停发送拒绝回复时一样会进入过载状态。此外,维护大量TCP连接、定期健康检查、SSL握手等操作也会消耗资源。客户端节流通过在源头主动拦截超限请求,解决了“后端被迫消耗资源来拒绝请求”的困境。
七、延伸阅读推荐
《Google SRE工作手册》第24章“处理过载”:本章内容的工作手册版扩展
《Google SRE 工作手册》第21章“客户端节流”:自适应节流算法的官方详细说明
《构建安全可靠的系统》:书中第13章详细讨论了“限流”(即客户端节流)的更多实现细节
《Maglev论文》:Google软件负载均衡器,其连接跟踪能力与本章过载保护机制存在密切关联
Google SRE官方书籍网站:https://sre.google
《SRE中文社区》:https://www.srenow.cn
学习下一章预告:第22章“应对连锁故障”——当过载问题进一步恶化,引发系统内部的“多米诺骨牌”效应时,如何设计防御机制,防止故障从局部扩散到全局。
本文为个人学习笔记,仅用于知识分享。如有错误,欢迎指正。
👍🏻 点赞 + 收藏 + 分享,让更多开发者看到这篇深度解析!❤️ 如果觉得有用,请给个赞支持一下作者!