站内 HAProxy 工程 已经把 frontend/backend、ACL 菜谱与 Runtime 运维直觉铺成一张地图;Nginx 深度 与 Envoy 数据面 各占「多进程文件驱动」与「API 驱动 Filter/xDS」一格。网关选型 把三者放进产品对比。读者仍缺一角:一次连接如何经 bind/accept → stream/mux → HTX/ACL → backend,以及 Runtime 热改与 seamless reload 各自保证什么、丢什么。
本文是「HAProxy / 数据面代理内核」系列第 1 篇,只做三件事:
- 画出 HAProxy 相对配置运维单篇、Nginx、Envoy 的生态位与缺口。
- 钉住后续章节共用的五条坐标系,并交代用户态事件驱动 LB 的设计谱系与开放争论。
- 给出与站内系列的分工,以及 14 篇阅读路线。
本文是「HAProxy / 数据面代理内核」系列第 1 篇(共 14 篇)。→ 系列目录
篇目 核心内容 第 1 篇 · 数据面全景 生态位、主线坐标系、系列路线 第 2 篇 · 线程与调度 nbthread/ thread-group、共享内存边界第 3–5 篇 · 接入路径 accept → stream/mux → HTX 第 11–12 篇 · 动态性 Runtime API 与 seamless reload
版本锚定:HAProxy 3.4.3(LTS 线 3.4;2026-07-29)。官方 Starter Guide / Management Guide / Configuration Manual(docs.haproxy.org/3.4/)与源码树
haproxy/haproxytag v3.4.3。本篇以定位与路线为主,不粘贴未执行的show info/show sess/ stats 输出,也不编造 QPS。
一、生态位:本系列补哪一角
Nginx / HAProxy / Envoy 常被塞进同一张「反向代理」表,但默认把什么当一等公民不同——格子不是互斥,而是故障归因时先看哪一层。
flowchart TB
subgraph proxies ["Proxy paradigms"]
NGX["Nginx<br/>multi-process file-driven"]
HAP["HAProxy<br/>file/Runtime L4/L7 LB kernel"]
ENV["Envoy<br/>API-driven filter dataplane"]
EBPF["eBPF L3/L4<br/>kernel datapath"]
end
subgraph ops ["Ops / product layers"]
CFG56["network/56<br/>HAProxy config map"]
SEL60["network/60<br/>gateway selection"]
end
CFG56 -.->|"need path + failure modes"| HAP
NGX -.->|"contrast worker model"| HAP
HAP -.->|"contrast control plane"| ENV
EBPF -.->|"L7 still needs userspace"| HAP
HAP --> SEL60
ENV --> SEL60
| 形态 | 一等公民 | 典型代价中心 | 站内入口 |
|---|---|---|---|
| Nginx 多进程 | 配置文件 + worker 隔离 | reload 窗口、共享状态缺失 | network/55 |
| HAProxy 数据面 | frontend/backend + Runtime + stick-table | 线程共享、mux/HTX、reload FD 交接 | 本系列 |
| Envoy 数据面 | xDS 资源 + Filter 链 | 匹配、编解码、warming、上游池 | envoy/ |
| 配置运维单篇 | 会配、会查 stats | 不回答「卡在哪一层」 | network/56 |
| eBPF L3/L4 | 内核策略 / 负载均衡 | 不解析完整 HTTP 语义 | linux-net / Cilium |
一句话:本系列占住「文件配置 + Runtime 热改驱动的经典 L4/L7 LB 内核」那一格——不替代 56 的菜谱,也不重写 Envoy 的 Filter/xDS 全书。
主线引擎取 HAProxy 3.4.3:文档树与源码 tag 对齐,适合做「从 accept 到 reload」的连续拆解。HAProxy Enterprise 专有能力、Lua/SPOE SDK 教程不进正文;仅在选型边界出现。
读者若只带走一句:会配 frontend/backend 只是地图入门;能指出失败落在五条轴的哪一条,才算进入本系列的能力模型。
二、缺口:相对 56 / 55 / Envoy 还缺什么
| 已有内容 | 视角 | 本系列补什么 |
|---|---|---|
| network/56 | 配置模型、ACL 菜谱、Runtime 用法、运维调优 | 源码级路径、失败模式、与 reload 的语义边界 |
| network/55 | Nginx 事件模型 / worker / upstream | 对照句;不重写 Nginx |
| envoy/ | API 驱动 Filter + xDS | 对照「文件/Runtime 驱动」那一格 |
| network/60 | 网关选型排除树 | 机制前提;不重做产品评选表 |
结论:读者会写 frontend/backend、会用 Runtime socket,但不知道 accept 之后 stream/mux 如何分层、HTX 改写落在哪、stick-table 在多进程下不共享意味着什么、Runtime 改权重与 seamless reload 各自保证什么。
与 Envoy 第 1 篇 对称:那边钉的是「控制面已推送为何仍黑洞」;这边钉的是「配置已 reload / 权重已 set 为何仍丢状态或卡在错误层」。
三、设计谱系:用户态事件驱动 LB 从哪分叉
3.1 工作定义
本系列默认的 HAProxy 数据面:
- Frontend / bind:监听入口;accept 拿到连接,进入会话与协议路径。
- Stream:一次逻辑请求/会话在代理内部的工作单元;挂分析器、超时、与前后端通道。
- Mux(multiplexer):把连接上的线协议(TCP 直通、HTTP/1、HTTP/2 等)译成 stream 视图;解析与上层处理分离。
- HTX:版本无关的内部 HTTP 表示;改写/重定向落在此层,而不是永远抠原始字节缓冲。
- Backend / server:上游池、LB 算法、队列与连接复用边界。
- Stick-table / peers / Runtime / reload:共享状态与动态运维面——与「静态 cfg 一次写死」共享代理一词,但运行时不变量不同。
3.2 学术与工程谱系(本系列回指)
- C10K 与用户态事件驱动:把「每连接一线程」换成 poller + 非阻塞 I/O(经典叙述见 Dan Kegel, The C10K problem)。HAProxy Starter Guide / Management Guide 把自己钉成 multi-threaded, event-driven, non-blocking:用事件多路复用调度活动,而不是把调度外包给内核线程切换。
- 专用负载均衡器 vs 通用 Web 服务器:Nginx 从静态内容与反向代理共生;HAProxy 从第一天就以代理/LB 为中心(对照 network/56 的定位段)。工程分叉点是:会话粘性、细粒度健康检查、Runtime 改权重是否一等公民。
- 单进程多线程演进:早期多进程(
nbproc)用进程边界换隔离;现代默认路径是nbthread+ 共享地址空间内的 stick-table/stats,再用 thread-group 约束 NUMA/缓存局部性(3.2 起拓扑感知,3.4 进一步收紧默认每组线程上限等——见 3.4 发布说明)。这与 Envoy Main/Worker「连接钉死 Worker + TLS 快照」同属 shared-nothing 数据面家族,但配置分发协议不同:文件/Runtime vs xDS。
谱系收束句:产品层争论「选哪个代理」;内核层争论「共享状态放在进程内还是进程外、热更新用 Runtime 还是 reload」。 后者才是本系列主战场。
3.3 开放争论(先立靶,后各章拆)
| 争论 | A 侧 | B 侧 | 本系列落点 |
|---|---|---|---|
| 文件/Runtime vs xDS | 可 diff 进 Git、运维面窄 | 统一控制面、声明式热更新 | 第 11–12、14 篇;对照 Envoy 9–12 |
nbproc 多进程 vs nbthread |
故障隔离、CPU 重任务拆分 | stick-table 进程内共享、检查不翻倍 | 第 2、8 篇;Management Guide 限制表 |
| 「一切经 HTTP/HTX」vs 纯 TCP | 统一改写与观测 | L4 路径更短、少解析税 | 第 4–5 篇 |
| Seamless reload vs 永不 reload | 配置面完整切换 | 窗口内 SYN/ACK 竞态与状态复制成本 | 第 12 篇 |
| Stick-table 规模上限 | 进程内低延迟粘性 | 容量、锁、peers 一致性 | 第 8、14 篇 |
四、五条坐标系(后续章节回指)
后面每一篇都会落到下面某一条轴上。第 1 篇只钉名字,不展开源码。
4.1 请求路径轴
bind/accept → session → mux → stream
→ (HTTP) HTX + ACL/rules → backend/server → response path
延迟与 5xx / 断开的归因必须先回答:卡在 accept、协议 mux、规则引擎、上游连接,还是健康检查把池掏空? → 第 3–7、9、13 篇。
4.2 线程与共享状态轴
默认一进程多线程,每线程跑同一套事件循环;连接由单线程服务。Stick-table、部分
stats
等在进程地址空间内共享,靠锁与局部性设计控制争用;跨
nbproc 进程不共享
stick-table(Management Guide 明文)。→ 第 2、8
篇。
4.3 协议表示轴
TCP 可用 pass-through mux 少碰语义;HTTP 经 mux 进入
HTX。改写/重定向落在 HTX 上,避免「H2 先转成 H1
字节再解析」的双遍税(内部
doc/internals/api/htx-api.txt 叙事)。→ 第 4–5
篇。
4.4 动态运维轴
Runtime API 可热改权重、上下线、部分表项等;完整
listener/规则拓扑变更往往仍要新进程 +
reload。-x / expose-fd listeners /
master-worker 决定 FD 如何交接。→ 第 11–12 篇。
4.5 失败归因与可观测轴
Stats、会话转储、日志终止码、stick-table 计数,必须映射回上面四条轴,而不是「先怀疑网卡」。→ 第 13 篇;选型收束在第 14 篇。
五、与站内系列的分工
| 站内内容 | 负责 | 本系列不重复 |
|---|---|---|
| network/56 | 单篇配置与运维地图 | 本系列下沉路径与失败模式 |
| network/55 | Nginx worker / reload | 仅对照句 |
| envoy/ | Filter + xDS 内核 | 不重写;对称对照 |
| istio-xds/ | 网格控制面 | 不写;选型边界外链 |
| network/60 | 多代理选型表 | 机制前提,不重做对比全书 |
| libevent | Reactor 通识 | HAProxy 调度器 / poller 特有部分 |
读法:只要「建立 HAProxy 配置坐标系」→ 56 足够;要「一次请求卡在哪、reload 丢了什么」→ 本系列 01 → 04 → 08 → 12 → 13。
若目标是与 Envoy 对照做数据面选型,建议最小交叉阅读:本系列 01+02+12,加上 Envoy 01+02+12——两边各自回答「动态性如何进入热路径」,而不是先比谁的 QPS 宣传更高。
六、14 篇地图与阅读建议
| 部分 | 篇 | 一句话 |
|---|---|---|
| 进程与请求路径 | 01–06 | 从全景到 ACL 求值 |
| 上游、状态与动态性 | 07–11 | LB、stick-table、检查、TLS、Runtime |
| 生命周期与收束 | 12–14 | reload、排障、选型 |
最小路径:01 → 02 → 04 → 08 → 12 →
13。
请求路径深挖:再补 03 → 05 → 06 →
07。
动态运维联调:11 → 12 → 13。
做网关选型:01 → 13 → 14,并外链 55 / 56 /
60 / Envoy 16。
本篇不写性能排行。任何「比 Nginx/Envoy 更快」的句子若无本机口径与引用出处,一律视为无效——第 14 篇只给排除树,不给未实测延迟榜。
七、一条请求的「分层检查表」(给后续篇用)
后面排障篇会把字段映射到轴上;第 1
篇先固定提问顺序,避免一上来就改
timeout server:
- 听得见吗? bind
是否在正确地址/端口;reload 窗口是否丢
SYN;
maxconn是否打满入口。→ 第 3、12 篇。 - 协议对得上吗?
mode tcp/http、bind 上 TLS、ALPN/H2 是否与客户端一致;mux 是否选错世界。→ 第 3–5、10 篇。 - 规则把请求送去哪? ACL /
use_backend/ redirect 是否短路;stick 是否绑到已下线 server。→ 第 6、8 篇。 - 上游还能接吗?
队列、
maxconn、健康检查、timeout connect。→ 第 7、9 篇。 - 动态面刚改过什么? Runtime 改权重是否可见;是否刚做 seamless reload 导致表/FD 语义变化。→ 第 11–12 篇。
这张表不是产品对比,而是把「代理」拆成可证伪命题。Envoy 系列用 warming/ACK 回答「配置已下发」;本系列用路径轴 + 动态运维轴回答「配置已生效 / 连接已接住」。
工程间隙也先立在这里:官方 Management Guide 对 reload 失败率给过与负载相关的定性量级叙述,那是文档实验语境,不是你机房的 SLO。引用时必须写清来源与条件;本系列正文不把它改写成「生产保证」。
八、参考资料(本篇)
规范 / 官方文档(A)
- HAProxy 3.4.3, Starter Guide(docs.haproxy.org/3.4/intro.html):事件驱动定位、stick-table 能力概述。
- HAProxy 3.4.3, Management
Guide(docs.haproxy.org/3.4/management.html):多线程事件循环、连接单线程服务、
nbproc限制、reload /-x/expose-fd listeners。 - HAProxy 3.4.x, Configuration Manual(同版本 docs 树):frontend/backend/bind 等配置面(后续篇钉具体关键字)。
源码(A)
haproxy/haproxytag v3.4.3:src/、include/(后续篇钉stream、mux_*、htx、stick_table、checks等)。- 内部文档
doc/internals/api/htx-api.txt(HTX 动机与块模型;第 5 篇展开)。
谱系 / 对照(B 或经典)
- Dan Kegel, The C10K problem(用户态事件驱动问题定义)。
- HAProxy 3.4 发布说明 / 公告(thread-group 默认与争用相关改动的工程叙述,B 级)。
站内对照
实验台账
- 本篇无命令输出;不写 QPS / 延迟数字。
九、小结
- HAProxy 的生态位是文件/Runtime
驱动的经典 L4/L7 LB 内核,不是「又一个会
proxy_pass的 Web 服务器」,也不是 xDS 数据面。 - 五条坐标系(请求路径、线程共享、协议表示、动态运维、失败归因)是后续排障的共用语言。
- 与 56 的分工:单篇建立配置地图;本系列回答路径与「热改/reload 各自丢什么」。
- 开放争论先立靶:共享状态边界、HTTP 统一表示成本、reload 窗口——各章用机制拆,不提前做产品排名。
- 分层检查表要求先固定接入与协议,再查规则与上游,最后才怀疑动态运维面。
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
HAProxy / 数据面代理内核:从 Frontend 到 Seamless Reload
补齐站内 HAProxy 工程单篇与 Nginx/Envoy 选型之间的数据面内核层:线程组、stream/mux/HTX、ACL 求值、stick-table、health-check、Runtime API 与 seamless reload,并以排障与选型收束。
【HAProxy 数据面】线程与调度:nbthread、Thread-group 与共享内存边界
钉住 HAProxy 单进程多线程模型:每线程事件循环、连接单线程服务;对照 nbproc 下 stick-table 不共享,以及 Nginx 多进程与 Envoy Main/Worker;说明 poller 线程上阻塞的软警告。
【HAProxy 数据面】Frontend / bind / accept:监听、FD 与接入路径
说明 HAProxy frontend 与 bind 如何落到监听套接字;accept 之后 FD 与线程的关系;SO_REUSEPORT / cpu-map 与多线程接入;以及 expose-fd listeners 作为 seamless reload 的前置,并点到 content switching 入口而不做 ACL 百科。
【HAProxy 数据面】HTX 与 HTTP 路径:内部表示、改写落点与协议分叉
说明 HTX 作为版本无关的内部 HTTP 表示如何分离解析与处理;http-request 改写/重定向落在 HTX 而非永恒原始缓冲;HTTP/1 与 HTTP/2 在 mux 边界的分叉;以及相对纯 L4 路径的成本模型——非应用层菜谱。