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
balance、maxconn(server)、maxqueue、timeout queue、http-reuse;Starter 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 maxqueue
与 timeout queue
maxqueue:该 server 队列中最多等待多少连接;达到后新请求改派到其他 server(可能打断粘滞)。默认0表示队列不设此上限。leastconn 在maxqueue显式大于 0 时,可以把请求排进队列以平滑单机maxconn很小的场景。timeout queue:在队列中等待槽位的最长时间;超时则丢弃并给客户端 503。未配置时回退为与timeout connect相同(兼容旧行为)。
失败模式对照:
| 现象 | 机制含义 |
|---|---|
| 队列等到超时 → 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 同时配置 maxconn 与
minconn 时,手册用
fullconn 描述「backend
负载爬坡」:server 实际接受上限在 minconn 与
maxconn 之间随 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)
- HAProxy 3.4.3 Configuration
Manual:
balance、http-reuse、servermaxconn/maxqueue、timeout queue。 - HAProxy 3.4.3 Starter Guide §3.3.5 Load balancing。
论文(A)
- Mitzenmacher 等,Power of Two Choices
负载均衡分析(HAProxy
random文档回指 Harvard 笔记链接)。
站内
实验台账
- 本篇无压测数字;不声称某算法在未声明 workload 下「更快」。
九、小结
balance只在无持久化或再分派时决定选主;先分清粘滞命中与算法路径。maxconn+ 队列 +timeout queue/maxqueue定义容量失败模式;503 不一定是「上游进程挂了」。http-reuse划定池复用边界;默认safe保护首请求;线程亲和限制「看见」空闲连接的范围。fullconn/minconn、redispatch、backup 进一步塑造高峰与故障时的目标迁移;与哈希扰动、stick-table 粘滞不是同一机制。- 与 Envoy 对照时,对齐的是名字 → 选主 → 限额 → 池,不是产品功能清单。
→ 系列目录 · 上一篇:ACL / 规则引擎 · 下一篇:Stick-table
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【HAProxy 数据面】ACL / 规则引擎:求值顺序、副作用与 stick-table 耦合
把 ACL 与 http-request / use_backend 当作数据面机制:说明连接期到 L7 的求值顺序、动作副作用如何改写后续条件,以及与 stick-table 限流/标记的耦合点;不写 ACL 关键字百科。
【HAProxy 数据面】Stick-table:键类型、容量、跨线程可见性与 peers/reload
说明 stick-table 的键类型、size/expire/store、nbthread 共享内存与 nbproc 不共享的边界,以及 peers 复制与 reload 继承;覆盖表满等容量失败模式。
【HAProxy 数据面】Health-check 引擎:探活调度、httpchk/tcp-check 与 agent-check 边界
区分健康检查引擎与数据面请求调度:说明默认 TCP 探活、httpchk/tcp-check 规则集、agent-check 的独立控制面语义,以及与 soft-stop/排空的交互提示;不写伪造检查日志。
【HAProxy 数据面】SSL/TLS 路径:终结与透传、握手落点与会话缓存
区分 TLS 终结与 mode tcp 透传:说明握手相对线程/FD 的位置、会话缓存对握手成本的高层含义,以及与 HTTP 路径的交界;不是证书运维手册。