【读书活动感悟分享】《SRE Google运维解密》第二十一章-应对过载_文章

【读书活动感悟分享】《SRE Google运维解密》第二十一章-应对过载

冯辉
发表于 2025-10-31 17:23:16

本章节目录:

  • QPS 陷阱
  • 给每个用户设置限制
  • 客户端侧的节流(限流)机制
  • 重要性
  • 资源利用率信号
  • 处理过载错误
    • 决定何时重试
  • 连接造成的负载
  • 小结


本章核心,主要通过规避过载出发,避免过载,是负载均衡策略的一个重要目标,也是运维中可靠系统的一个根本要求,就是能够优雅地处理过载情况。

QPS 陷阱

Google 在多年的经验积累中得出:按照 QPS 来规划服务容量,或者是按照某种静态属性(认为其能指代处理所消耗的资源:例如某个请求所需要读取的键值数量)一般是错误的选择。

更好的解决方案是以可用资源来衡量可用容量。

在大多数场景下,以 CPU 核心数作为资源配额的主要依据通常能获得良好效果。

原因包括:

  • 对带垃圾回收(GC)的语言,内存压力通常会转化为 CPU 压力(内存不足时 GC 活动增加);
  • 在非 GC 环境中,其他资源通常可以按固定比例配置,使得这些资源成为瓶颈的情况很少发生。

给每个用户设置限制

在发生全局过载时,服务应仅对少数被标记为“异常”的客户返回错误,确保大多数用户不受影响;为此,运维团队与客户团队需协商并制定使用约定,用作配额与资源配置的依据。

客户端侧的节流(限流)机制

本节介绍一种称为“自适应节流”的客户端限流技术。每个客户端在过去两分钟内统计两类指标:requests(应用层发出的请求总数)和 accepts(后端实际接受的请求数)。正常情况下两者相等;当后端开始拒绝请求时,accepts 会小于 requests。客户端允许发送请求直到 requests = K * accepts;一旦超过该阈值,客户端以概率 p 在本地拒绝新请求,从而把发送速率拉回到可接受范围。拒绝概率可定义为:

通过调整倍值 K 值,可以控制客户端的本地拒绝概率:减小 K 会让自适应节流更激进(更早开始丢弃请求),增大 K 则更宽松(允许更多超额发送)。一般推荐以 K = 2 作为初始值:该设置允许后端接收约双倍于客户端估计的请求,从而更快把后端实际承载能力传递回客户端。代价是会消耗额外的后端资源,但能加速稳定并减少振荡。

重要性

重要性(criticality)是另外一个在全局配额和限制机制中比较有用的信息。文章归纳了四种类型,并发现这四种分类可以描述大部分服务:

  • 最重要 CRITICAL_PLUS: 为最重要的请求预留的类型,拒绝这些请求会造成非常严重的用户可见的问题。
  • 重要 CRITICAL: 生产任务发出的默认请求类型。拒绝这些请求也会造成用户可见的问题,但是可能没有 CRITICAL_PLUS 那么严重。我们要求服务必须为所有的 CRITICAL 和 CRITICAL_PLUS 流量配置相应的资源。
  • 可丢弃的 SHEDDABLE_PLUS:这些流量可以容忍某种程度的不可用性。这是批量任务发出的请求的默认值。这些请求通常可以过几分钟,或者几个小时之后重试。
  • 可丢弃的 SHEDDABLE: 这些流量可能会经常遇到部分不可用的情况,偶尔会完全不可能用。
  • 通过重要性分类,在处理过载情况下可以使用该信息:

    • 当某个客户全局配额不够时,后端任务将会按请求优先级顺序分级拒绝请求(实际上,全局配额系统是可以按重要性分别设置的)。
    • 当某个任务开始进入过载状态时,低优先级的请求会先被拒绝。
    • 自适应节流系统也会根据每个优先级分别计数。

    资源利用率信号

    Google 的任务过载保护以资源利用率(utilization)为核心指标,通常以当前 CPU 使用率(当前 CPU 消耗 / 分配的 CPU 数量)为主;在需要时也会将内存利用率纳入判断。文中还引入了一个基于活跃线程数与分配 CPU 数量之比的负载度量:负载 L = 活跃线程数 / 分配 CPU 数量。若该负载或资源利用率超过预设阈值,系统会开始拒绝或降级请求以防止过载并保证整体可用性。

    处理过载错误

    若跨数据中心负载均衡正常并能实时调度流量,理论上不应出现大量后端同时过载。

    • 少量后端过载:常由单个耗资源请求或 LB 短期不完美导致,通常数据中心仍有可用容量。此类情况建议立即重试(重试延迟通常为几个 RTT,可忽略)。
    • 大规模过载:若大部分后端都过载,应停止重试并直接向上层返回错误(避免浪费更多资源)。
    • 重试策略:重试请求与新请求等同对待(不额外保证命中不同后端),在后端数量多时概率上能实现自然分散,避免增加路由复杂度。
    • 快速失败的价值:快速拒绝后立即重试能把多余负载快速转移到有空闲的后端,形成天然的负载再分配机制。
    • 实践要点:监控过载比例并根据比例切换策略(大比例时禁用重试、小比例时允许短期重试);优先使用简单策略以降低系统复杂度。


    一句话总结:用“快速失败 + 把重试当作普通请求” 的简单策略能在大多数场景下以最低复杂度把负载自然分散;只有在广泛过载时才停止重试并上报错误。

    决定何时重试

    • 全局重试上限:每个请求最多重试 3 次(含首次尝试),超过则不再自动重试并将错误返回给调用方。
    • 客户端侧限流:每个客户端维护重试比率(基于节流/令牌桶等算法),限制该客户端的重试频率以避免单点放大效应。
    • 重试元数据与后端协作:客户端在请求元数据中携带重试计数(retry-count);后端根据该计数与自身过载判定返回明确信号(例如 429 + Retry-After 或自定义字段),告知客户端“当前过载,无需继续重试”。

    连接造成的负载

    维护大型连接池或频繁建立/断开连接会带来显著的 CPU/内存开销,连接快速波动亦会触发额外负载。为缓解,可采用两种策略:

  • 跨数据中心按资源利用率调度:将负载均衡决策从“仅按请求数”升级为按资源利用率(CPU、内存)、活跃线程数或连接数的加权得分来调度流量。高负载实例的请求应优先路由至利用率较低的数据中心,避免单点资源耗尽。
  • 批处理代理隔离:将批处理流量统一引导到轻量级批处理代理,由代理复用连接、聚合请求并转发到后端,响应再由代理回传。请求路径变为“客户端→批处理代理→后端”,从而把批处理对后端连接与资源的冲击隔离开。
  • 104 0

    评论
    

    意见反馈