ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

性能最优类负载均衡详解:响应时间是怎么采集的?分配给谁?

性能最优类负载均衡详解:响应时间是怎么采集的?分配给谁? 性能最优类负载均衡详解响应时间是怎么采集的分配给谁“负载均衡系统根据服务器的响应时间来进行任务分配优先将新任务分配给响应最快的服务器” —— 这句话听着直观但落地时立刻冒出三个问题响应时间是谁采的、采的哪个指标、怎么据此分配本文把这三个问题彻底拆开。一、先厘清性能最优到底指哪个算法在分配算法家族里按响应时间分配这一支通常有两个层次算法别名/常见叫法决策依据代表实现最少响应时间Least Response Time性能最优、最快响应历史平均 RT 最小Nginx 第三方upstream_fair、LVSSED短期等价加权响应时间Weighted Response TimeResponse Time WeightedRT 最小且兼顾加权连接数RibbonWeightedResponseTimeRule业内口语里说的性能最优类绝大多数时候指的就是基于响应时间RT做权重动态调整的那一类。它不是无脑转给最快的那台而是用 RT 反推出一台机器的综合权重再按权重分配。理解这一点后面的采集机制才说得通。二、核心问题一响应时间是怎么采集到的关键认知负载均衡器自己就是 RT 的天然采集者。它不需要后端额外上报因为请求是它转出去的、响应是它收回来的一去一回中间的时间它本就知道。1. 代理型负载均衡七层如 Nginx负载均衡器以反向代理身份转发请求完整参与 TCP/HTTP 生命周期Client ──①请求──▶ Nginx ──②转发──▶ Backend │ Client ◀──④响应── Nginx ◀──③响应──┘采集点Nginx 在②转发记一个起始时间戳在③收到后端响应记一个结束时间戳。采集的量这两者之差即后端处理这段请求花了多久。这本质上是 Nginx 自带的upstream_response_time指标每条请求都会记。Nginx 原生默认策略轮询/最少连接不用这个 RT要用 RT 分配得装第三方模块nginx-upstream-fair按 RT 选最快或upstream-fair。也就是说采集能力 Nginx 一直有用不用它来决策是另一回事。2. 客户端型负载均衡Sidecar/SDK如 Ribbon、Spring Cloud LoadBalancer客户端进程内集成了负载均衡逻辑如 Feign Ribbon请求直接从消费方进程发往后端Consumer JVM (含 Ribbon) ──请求──▶ Provider A / B / C ▲ │ └──────响应──────────┘采集点Ribbon 在每次 HTTP 调用前后用LoadBalancerCommand记录耗时。存哪维护在每个 Server 对应的ServerStats对象里做滑动窗口累计默认最近一段时间内的平均 RT。关键设计RT 数据只存在消费者内存里不持久化、不跨进程上报。多个消费者各自维护各自的 RT 视图。3. 主动探测型心跳附带如 LVS/F5 硬件、部分四层 LB四层负载均衡器不一定能感知应用层 RT它只看到 TCP 报文于是用主动探测补足均衡器周期性向后端发一个健康检查探测包HTTP/health或 TCP 握手。记这个探测包的往返时间作为该后端的响应能力参考。缺点探测路径 ≠ 真实业务路径探测包 RT 只能近似代表这台机器当前快不快。4. 三种采集方式对比方式采集者数据来源准确度代表代理被动采集LB 自己转发时记录真实业务请求高最真实Nginx upstream_fair客户端被动采集消费方进程内记录真实业务调用高Ribbon WeightedResponseTime主动探测采集LB 周期性探测探测包非真实业务中近似部分 LVS/硬件 LB一句话总结采集要么我转发的我自然知道耗时被动要么我主动去戳一下看多久回来主动。大多数应用层性能最优用的是被动采集。三、核心问题二Java 系统那么多接口服务器响应时间到底指哪个这是最容易困惑的点。一个 Java 系统几百个接口有快有慢LB 采的是哪个答案分三层1. 指标层面采的是每台服务器的聚合 RT不是每个接口的 RT负载均衡器的决策粒度是节点服务器实例不是接口。它维护的是Server A → 最近 N 个请求的平均 RT 50ms Server B → 最近 N 个请求的平均 RT 120ms Server C → 最近 N 个请求的平均 RT 80ms这是一个跨所有接口的混合平均值。LB 不关心你调的是/order/create还是/user/query它只关心发往 A 的请求平均多久回来。2. 那接口差异这么大混合平均合理吗不合理但工程上能接受原因有二同一集群内的节点跑同一份代码对外暴露的接口集合相同流量分布也大致相同。所以 A、B、C 三台混合平均 RT的对比等价于在相同流量结构下比机器本身的速度差异——这正是我们想要的。真实业务里快慢接口的比例在各节点间基本一致都按相同比例混合混合均值相减后接口差异被对消剩下的就是机器性能差异。反例如果某台机器被特意多分了慢接口流量比如用了会话保持 慢用户集中混合 RT 就会失真。所以响应时间算法通常关掉会话保持让流量结构在节点间均匀。3. 想按接口级 RT分配那是另一套机制如果确实要针对/order/create这个慢接口单独挑快机器LB 本身一般不干这事而是路由层面按接口/path 做分流每个接口集合内部再用 RT 算法。服务网格/注册中心让 Sidecar如 Istio按维度上报 RT由控制面聚合后下发权重。APM 动态权重接 Skywalking/Pinpoint 采接口级 RT写回注册中心或 Nginx upstream weight。所以服务器响应时间在 LB 语境下 发往该服务器实例的所有请求的加权/滑动平均响应时间是个节点级聚合指标不是某个接口的 RT。4. 还有个坑RT 包含什么被动采集的 RT 里可能混入非纯处理时间排队时间连接池等不到网络往返LB 自身到后端的连接建立时间因此 RT 偏大未必是后端算得慢可能是它在排队。这恰恰说明RT 小的机器往往是当前不太忙、连接不挤的机器——这跟最少连接算法的结论高度一致也是两者常被合并讨论的原因。四、核心问题三如何根据响应时间来进行任务分配分配给最快的那台是最朴素的直觉但直接这么干有两个致命问题抖动A 当前最快所有新请求都涌向 AA 瞬间被打满RT 反弹又全涌向下一台——在节点间反复横跳。饿死一旦某台偶然慢了一次可能长期被排挤。所以工程实现不是选最小 RT 的那一台而是用 RT 算出每台的权重按权重概率分配。下面以 RibbonWeightedResponseTimeRule为例拆解。1. 权重计算公式Ribbon 的核心思想RT 越小权重越大且权重和总 RT 成反比关系。设有 3 台机器采集到的平均 RTServeravg RTA50msB100msC150ms总和300msRibbon 用totalCapacity - avgResponseTime作为该 Server 的权重totalCapacity取所有 RT 之和或一个常数使非负weight(A) 300 - 50 250 weight(B) 300 - 100 200 weight(C) 300 - 150 150再归一化成概率P(A) 250 / (250200150) ≈ 41.7% P(B) 200 / 600 ≈ 33.3% P(C) 150 / 600 ≈ 25.0%注意不是100% 给 A而是41.7% 给 A。这样最快的 A 拿大头但 B、C 仍分到流量避免饿死和抖动。2. 分配动作加权随机拿到权重后每次新请求来按上述概率做一次加权随机抽样Ribbon 用的是WeightedRandom。落到哪台就转给哪台。[0, 41.7%) → A [41.7, 75%) → B [75, 100%) → C 随机数 r Math.random() * totalWeight落在哪个区间选哪台。3. 权重刷新时机权重不是每条请求都重算太贵而是定时刷新Ribbon 默认每 30sserverWeightTaskTimerInterval重新读一次各 Server 的滑动平均 RT重算权重表。在两次刷新之间用旧权重表做加权随机。这带来一个权衡刷新太勤 → 跟着瞬时抖动跑不稳定刷新太慢 → 反应迟钝。30s 是经验值。4. 容错与冷启动新加入的机器没有历史 RT给一个默认中等权重避免一上来被流量冲垮或完全拿不到流量。某台 RT 采不到/超时标记不可用剔除出候选池而非按RT∞参与计算。RT 突刺滑动平均本身就是为了削平单次突刺有的实现还会丢弃 P99 之外的异常值。5. Nginx upstream_fair 的不同做法nginx-upstream-fair偏向选完成时间最早的那台它看每台后端当前未完成请求里最晚能结束的时间优先把请求发给能最快腾出手的机器。这更接近最少连接 响应时间的混合而非纯加权随机。两种流派流派代表风格加权随机派Ribbon WeightedResponseTimeRT→权重→概率分配平滑最快空闲派Nginx upstream_fair看谁先空闲就给谁更激进五、整体流程串起来以 Ribbon WeightedResponseTime 为例一次完整的采集→决策→分配┌─────────────────────────────────────────────────────────────┐ │ 后台定时线程每30s │ │ 1. 遍历所有 Server读 ServerStats 里的滑动平均 RT │ │ 2. weight totalRT - avgRT (RT越小权重越大) │ │ 3. 重算加权随机区间表替换旧表 │ └─────────────────────────────────────────────────────────────┘ │ ▼ (新表就绪) ┌─────────────────────────────────────────────────────────────┐ │ 请求线程每次调用 │ │ 1. 从候选池排除不可用 Server │ │ 2. r random() * totalWeight │ │ 3. 命中区间 → 选定 Server │ │ 4. 发起 HTTP 调用计时 │ │ 5. 回来后把本次 RT 累加进该 Server 的 ServerStats 滑动窗口 │ └─────────────────────────────────────────────────────────────┘采集步骤5→ 决策后台步骤1-3→ 分配请求步骤2-3形成闭环这次的 RT 喂养下一轮的权重。六、选型与陷阱何时该用性能最优算法✅ 集群内机器异构CPU/内存/网络不一轮询会拖垮弱机。✅ 流量本身耗时不均希望自适应。✅ 单次请求 RT 在几十 ms 以上采集误差占比小、值得用。何时不该用❌ 集群完全同构 请求耗时均匀轮询/最少连接更简单、更稳。❌ 请求极快亚毫秒级RT 采集中网络抖动占比过大权重算出来基本是噪声。❌ 强依赖会话保持会话保持会让流量结构不均混合 RT 失真。常见陷阱把响应时间等同于某个接口的 RTLB 采的是节点级聚合 RT不是接口级。以为每次都选绝对最快那台实际是按 RT 反推的权重做加权随机避免抖动。忽略采集口径差异被动采集的 RT 含排队/网络时间“RT 高未必是算得慢”。刷新间隔设太短权重跟着瞬时抖动剧烈波动反而加剧不均。冷启动没兜底新机器无历史 RT要么权重为 0 饿死要么默认权重过大被冲垮——必须给默认中等值。七、一句话回答三个问题响应时间怎么采的大多数情况是负载均衡器/消费方在转发真实请求时被动记录一去一回的耗时四层 LB 不便感知应用层时改用周期性主动探测近似。指哪个接口的 RT不是某个接口而是发往该服务器实例所有请求的滑动平均 RT节点级聚合指标因为同集群各节点流量结构相近混合均值相减能对消接口差异。怎么据此分配不是无脑给最快那台而是用 RT 反推权重RT 越小权重越大→ 按权重做加权随机 → 定时刷新权重表兼顾优先快机器与避免抖动饿死。
返回列表