土法炼钢 · 系统与基础设施

【HAProxy 数据面】Backend / server / LB:算法、队列与连接复用边界

文章导航

分类入口
networkproxy
标签入口
#haproxy#backend#load-balancing#roundrobin#leastconn#maxconn#http-reuse#3.4.3

目录

ACL / 规则引擎 给出 backend 名之后,数据面仍要回答三件事:选哪台 server、连不上或槽位满时排队还是失败、空闲上游连接能否被下一次请求复用。把这三层揉成「balance 配错了」会误导排障。本文钉 backend 内的机制边界,不写 server 行参数百科。

本文是「HAProxy / 数据面代理内核」系列第 7 篇(共 14 篇)。→ 系列目录

篇目 核心内容
第 6 篇 · ACL / 规则引擎 选路到 backend
第 7 篇 · Backend / LB 算法、队列、复用
第 8 篇 · Stick-table 粘滞与计数状态

上一篇ACL / 规则引擎 · 下一篇Stick-table

版本锚定:HAProxy 3.4.3 Configuration Manual balancemaxconn(server)、maxqueuetimeout queuehttp-reuseStarter Guide §3.3.5 Load balancing。源码 tag v3.4.3。无伪造 QPS。

本篇不展开:cookie 插入运维细节、健康检查探针语法(第 9 篇)、stick-table 容量(第 8 篇)。只回答「名字选中之后,主机与连接如何落到失败或成功」。


一、Backend 是什么

在 HAProxy 模型里,backend 是一组 server 加上:负载均衡算法、可选粘滞、队列与超时、健康检查与(HTTP 下)连接复用策略。frontend 负责接受与内容交换;backend 负责「向上游怎么走」。

选主不是在真空中跑算法。手册对 balance 写明:算法用于没有持久化信息可用,或连接被重新分派到另一 server 时。换言之,cookie / stick-table / 哈希粘滞会先收窄或钉死目标;算法是默认与回退路径。

flowchart TD
  name["backend name chosen"] --> persist{"persistence hit?"}
  persist -->|"yes"| srv["pinned server"]
  persist -->|"no"| algo["balance algorithm"]
  algo --> health["among usable servers"]
  health --> slot{"server maxconn room?"}
  slot -->|"no"| queue["queue / timeout queue"]
  slot -->|"yes"| conn["connect or reuse"]
  queue -->|"timeout / full"| fail503["503 / failure"]
  conn --> up["upstream I/O"]

健康集合由 check / agent / 管理状态(MAINT/DRAIN)塑造,细节见第 9 篇;本篇假定「当前可调度集合」已知。


二、算法作为机制(不是菜单)

Starter Guide §3.3.5 概括常见算法动机:短连接偏 round-robin;长会话偏 leastconn;SSL/终端农场常用 source;缓存农场常用 URI;first 用于尽量压到最少台数以便关电。Configuration Manual 的 balance 条目给出可核对约束:

算法 机制要点(3.4.3 文档) 典型误用
roundrobin 按权重轮转;动态(可慢启动调权);设计上限约 4095 活跃 server / backend 长连接农场仍用 RR → 连接数不均
static-rr 类似 RR 但静态权;server 恢复后立即回农场;无上述数量设计上限 指望 Runtime 改权立即进调度
leastconn 选当前连接数最低者;同负载组内再 RR;计入排队中的连接;动态权 短 HTTP 请求农场当默认 → 收益有限
first 按 id 从低到高填满 maxconn 再下一台;忽略权重;无 maxconn 则无义弱 未配 maxconn 却期望「自动缩容」
source / uri / hdr / url_param / hash 对样本哈希后按总权重取模(或一致哈希变体,见 hash-type);缺样本时常回退 RR 当绝对粘滞,却未处理 server 上下线导致的哈希重映射
random / random(N) 一致哈希意义上的随机键;N 次抽取后取最闲,默认 \(N=2\)(Power of Two Choices) 与 leastconn 混为一谈而不看文档假设

random 文档显式回指 Mitzenmacher 等关于 Power of Two Random Choices 的分析,并说明提高 \(N\) 会逼近 leastconn 但更慢;低负载大农场下平局时还会比较近一秒请求率。这是本篇需要的「谱系钉」,不是算法广告。

动态 vs 静态:roundrobin / leastconn / random 等支持动态权(慢启动、agent 改权有意义);多数纯哈希类默认静态,除非配置 hash-type 允许动态行为。Runtime 改权「不生效」时,先看算法是否静态——这是机制问题,不是 API 坏了。


三、maxconn、队列与失败模式

3.1 server maxconn

server 参数 maxconn:并发连接(HTTP 模式下是并发请求)超过该值时,新请求进入队列等待槽位。默认 0 表示不限制。手册强调:这是保护脆弱上游的关键旋钮;HTTP 多路复用下「50 的 maxconn」可能对应 1–50 条实际 TCP,但飞行中请求不超过 50。

frontend / global 的 maxconn 限制的是接受侧并发,与 server 槽位不是同一层——一端听队列在内核 listen backlog,一端在 HAProxy 的 server/backend 队列。

3.2 maxqueuetimeout queue

失败模式对照:

现象 机制含义
队列等到超时 → 503 有 server,但槽位长期不足,或上游释放太慢
maxqueue 触发改派 宁愿破粘滞,也不在坏死 server 上无限等
无可用 server 健康集合为空 / 全 MAINT;算法无候选 → 失败(常见仍是 503 语义,具体日志码依版本与模式)
frontend maxconn 打满 新连接停在系统 listen 队列;尚未进入 backend 算法

排障时应先分清:没进 backend进了 backend 但在排队已连上上游却应用错误。三者日志与 stats 计数不同轴。


四、连接复用边界(http-reuse

HTTP 下 HAProxy 会把用过的空闲上游连接放进按 server 分组的池,用一组键属性判断能否复用:源/目的地址、PROXY protocol、TOS/mark、以及连接名(pool-conn-name 或默认由 SNI/Host 推导)。pool-max-conn / pool-purge-delay 限制池大小与清理。

http-reuse 策略(手册):

模式 行为要点
never 会话间不共享空闲连接;排障或兼容「误把同连接多请求当成同一客户端」的旧应用
safe(默认) 会话的首个请求总走自己的连接;后续请求才可复用他连。对易 HoL 的协议(如后端 h2)还有「同会话占用」语义
aggressive 允许更多首请求走「已被证明可复用」的连接;偏 webservice、上游集合不完全已知的场景
always 最大程度复用;文档对其风险更谨慎,需结合上游是否真安全共享

复用边界与线程相关:维护者对多线程模型的说明是——可复用的 backend 连接等实体有线程亲和,不会在任意线程间无锁横传。因此「池里明明有空闲连接」仍可能在本线程看不到兼容项,而新建连接。这与 Envoy 每 Worker 分池 同构:全局计数与本地池实例不是同一把锁。

TCP mode(mode tcp)没有这套 HTTP 复用语义;TLS 透传与终结见 第 10 篇


五、动态槽位、redispatch 与 backup

当 server 同时配置 maxconnminconn 时,手册用 fullconn 描述「backend 负载爬坡」:server 实际接受上限在 minconnmaxconn 之间随 backend 并发连接数变化;fullconn 是达到 maxconn 的参考负载点。未显式配置时,HAProxy 会按可能汇入该 backend 的 frontend maxconn 之和的一定比例自动估算。机制目的是:平常压低单机并发,高峰再放开,而不是一上来打满 maxconn

option redispatch(与重试配合):当目标 server 倒下或不可用时,允许把请求改派到其它 server。它与粘滞、队列改派(maxqueue)同属「打破原定目标」家族——排障时要问:是健康检查触发的再分派,还是队列策略触发的再分派,或是显式 redispatch。

backup server:Starter Guide 强调 backup 在活跃 server 全不可用时接替,并可构造多路径。option allbackups 打开时,在普通 server 全挂后对所有 backup 做负载均衡,而不是只打第一台 backup。这改变失败模式:从「单台接力」变成「backup 池接盘」。balance first 与 backup/关电运维假设不同轴,不要混用叙事。

哈希类算法还受 hash-type(map-based / consistent 等)约束:server 增减时扰动大小不同;hash-balance-factor 等用于 consistent 场景下的平衡修正。本篇只需记住:哈希粘滞的「稳定性」是哈希函数与农场成员集的函数,不是 stick-table 复制语义。


六、轻对照 Envoy Cluster / 连接池

维度 HAProxy backend Envoy cluster(本站系列)
名字来源 use_backend / 默认 Router / RDS 选 cluster
选主层次 粘滞 → balance → 健康集合 priority → locality → subset → LB
并发限额 server maxconn + 队列 circuit breaker(跨 Worker 共享限额)
http-reuse + per-server 池;线程亲和 每 Worker 连接池;协议抽象池
被动摘除 主要靠健康检查 / 重试 / 自定义 ACL;非 outlier 同构物 outlier detection 一等公民

对照目的不是选型打分(见系列第 14 篇与 Envoy 选型),而是避免把 Envoy 的 503 overloaded 叙事硬套到 HAProxy 的 timeout queue 上。二者都可能在「路由名字正确」时对外失败,但计数器、日志字段与缓解旋钮不在同一张表里:HAProxy 侧先查 server 队列与健康集合,Envoy 侧先查 circuit breaker 与 outlier 集合。

慢启动(slow start)在动态权重算法上把恢复中的 server 权重从低拉高,避免冷缓存或刚编译的应用被瞬时打满——Starter Guide §3.3.5 将其与动态权绑在一起叙述。它改变的是权重时间函数,不是健康状态位;与 check 变 UP 的瞬间叠加时,会出现「已 UP 但仍几乎无流量」的窗口,这是机制预期而非故障。


七、谱系、争论与开放问题

谱系:进程内软件 LB 的算法菜单长期在 RR、最少连接与哈希粘滞之间权衡;Power of Two Choices(Mitzenmacher 等)进入 HAProxy random(N),与 Envoy least-request 的 P2C 叙述同宗。HAProxy 额外用 first + maxconn 表达「装箱以利关电」,这是面向运维的调度假设,不是理论最优负载。

争论:短 HTTP 是否该默认 leastconn。文档明确 leastconn 更适合长会话;短请求上 RR / random 往往足够。把 leastconn 当「更智能」而无视请求时长分布,是配置品味问题,不是文档未写。

开放问题:多路复用(H2/H3)下「server maxconn 计请求」与池复用、线程亲和叠加后,容量规划是否还能用「连接数 ≈ 负载」的旧经验,需要结合观测而非口号。QUIC/H3 路径的队列语义演进留给选型/开放问题篇。


八、参考资料

规范 / 官方文档(A)

论文(A)

站内

实验台账


九、小结

  1. balance 只在无持久化或再分派时决定选主;先分清粘滞命中与算法路径。
  2. maxconn + 队列 + timeout queue / maxqueue 定义容量失败模式;503 不一定是「上游进程挂了」。
  3. http-reuse 划定池复用边界;默认 safe 保护首请求;线程亲和限制「看见」空闲连接的范围。
  4. fullconn/minconnredispatch、backup 进一步塑造高峰与故障时的目标迁移;与哈希扰动、stick-table 粘滞不是同一机制。
  5. 与 Envoy 对照时,对齐的是名字 → 选主 → 限额 → 池,不是产品功能清单。

系列目录 · 上一篇:ACL / 规则引擎 · 下一篇:Stick-table

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。


By .