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

【HAProxy 数据面】Runtime API:可热改边界与必须 reload 的配置面

文章导航

分类入口
networkproxy
标签入口
#haproxy#runtime-api#stats-socket#master-cli#reload#stick-table#3.4.3

目录

第 10 篇 把 TLS 终结与透传钉在请求路径上。运维下一问往往不是「怎么配」,而是:权重、上下线、限流计数能不能在不停流量下改;哪些变更必须走配置文件 + reload。

本文钉 Runtime API(stats socket / Unix Socket commands)的热改面结构面分界,以及 master-worker 下的 Master CLI。命令只写语义与调用形态,不粘贴伪造的 show info / show sess 输出。菜谱级脚本与运维手法见站内 HAProxy 工程(network/56);进程交接与 FD 语义见 第 12 篇

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

篇目 核心内容
第 10 篇 · SSL/TLS 终结 vs 透传
第 11 篇 · Runtime API 热改范围 vs reload
第 12 篇 · Seamless reload FD 交接与 soft-stop

版本锚定:HAProxy 3.4.3 Management Guide §9(Unix Socket commands / Master CLI)。热改结果在内存中生效,默认不写回配置文件;reload 后未持久化的 Runtime 变更会丢失,除非另有 state file / peers 等机制。


一、两个运维平面:热改 vs 结构变更

HAProxy 的配置模型仍是「启动时解析、进程生命周期内结构基本固定」。Runtime API 补的是在既有结构上改运行态,而不是把整个配置树变成 xDS 式资源。

flowchart TD
  change["Config change request"] --> q{"Structural?"}
  q -->|"no: weight / state / map entry"| rt["Runtime API on stats socket"]
  q -->|"yes: new bind / frontend / rule tree"| file["Edit cfg + seamless reload"]
  rt --> mem["In-memory only until reload"]
  file --> handoff["New workers + FD handoff"]
平面 载体 典型操作 持久性
Runtime stats socketlevel admin 改权重、server state、clear table、add/del map/acl 条目 内存;reload 默认冲掉
结构 配置文件 + reload bind、新 frontend/backend 段、改写规则树拓扑 文件;由新进程解析

常见误区:把 Runtime 当成「迷你控制面」。它没有 ACK 树、没有 warming 依赖图;成功与否以命令返回与后续 show * 语义为准,而不是以外部编排的「已推送」文案为准。对照 API 驱动范式见 Envoy 选型收束;网关产品层横向对比见 network/60

谱系上,这是「静态配置文件 + 窄动态面」传统:进程启动时把 frontend/backend/server 对象图固定下来,再用 socket 命令改对象上的可变字段。它与 Envoy 的 xDS 资源树不是同一抽象层次——后者把依赖、warming、ACK 做成协议;前者把运维速度押在「少 reload、多改内存」。两者都能「不停流量改行为」,但失败模式不同:Runtime 错了立刻作用在当前进程;xDS 错了可能停在 NACK/warming(见 Envoy 系列)。选型时先问组织有没有控制面编制,再问要不要 HAProxy 这层热改,而不是反过来。

权限模型也属于平面分界的一部分。stats socketleveluser / operator / admin)决定能看还是能改;生产自动化若共用一个 admin socket,等于把摘流与清表能力交给每一条流水线。更稳妥的做法是:只读监控走低权限 socket,变更走受控的 admin 通道并审计命令文本。TCP 暴露 stats socket 在文档里被标为危险默认——本系列默认假设 UNIX 域套接字 + 文件系统权限。


二、可热改:服务器、表、ACL/Map、前端开关

下列能力以 Management Guide 3.4.3 Unix Socket commands 为准(名称以文档命令表为准;参数细节随 patch 核对)。

2.1 服务器运行态

命令族 语义
set weight / set server … weight 改 LB 权重;影响后续调度,不迁移已有连接
enable server / disable server 启用 / 维护下线(经典写法)
set server … state {ready\|drain\|maint} ready 接新流量;drain 不再接新请求但仍服务存量;maint 停流量
set server … addr [port] 改地址/端口(动态后端场景)
add server / del server 已有、且满足动态算法约束的 backend 上增删 server;del 前通常需 maint 且无残留 stream

add server 的文档约束值得单独记住:动态创建的 server 不会在 reload 后自动复现,除非配置文件里也写了对应条目(或配合 state 持久化流程)。热加只解决「当前进程内扩容」,不替代 Git 里的真相源。

drainmaint 的差别常被脚本写反:drain 适合发布前摘流——存量连接继续结束,调度器不再把新请求打上去;maint 适合故障隔离或即将 del server——更彻底地停流量。权重改成 \(0\) 与进入 drain 在调度结果上可能相近,但状态机与健康检查交互不同,自动化应以 state 命令为准,而不是只改百分比。agent-check 启用时,agent 回报可能再次改变 server 状态;文档要求删除前先处理好 agent,否则会出现「刚 maint 又被 agent 拉起」的竞态。

与健康检查的交叉:Runtime 把 server 标 UP/ready,并不保证检查探针定义本身正确——探针参数多数仍属结构面,见 第 9 篇。排障时若「Runtime 已 enable 但仍无流量」,先看 check 是否仍判死,再看 ACL 是否选到该 backend。

2.2 Stick-table 与限流状态

命令 语义
show table 列出表或转储条目(键、计数器、过期)
clear table … 按 key / data 条件 / ptr 清条目

限流、粘滞、封禁若落在 stick-table,clear table运行态急救,不是改规则本身。表类型、容量与 peers 复制见 第 8 篇;reload 时表是否保留取决于 peers 配置,见第 12 篇。

2.3 ACL / Map 条目(不是规则树)

add acl / del acl / clear acladd map / set map / del map 等改的是已声明 pattern 文件或内联表的内容,不是把 use_backend if … 拓扑重写一遍。

能热改 仍需 reload
白名单 IP 增删、map 键值更新 新增 ACL 表达式、改匹配字段、改 http-request 动作链结构
对已有 map 做 prepare/commit 版本切换 新 frontend、新 backend 名、新 stick 规则拓扑

prepare / commit 一类版本化更新,是为了让大表替换接近原子:先在新版本填条目,再切换命中版本,避免「清表到填完」窗口里策略空洞。具体命令参数以 3.4.3 命令表为准;工程上要把它当成事务,而不是一串互不相关的 add

SSL 证书热更新(set ssl cert 与 commit/abort 事务)属于另一条窄动态面:能换 PEM 内容,不等于能随意改 bind 上的证书选择拓扑。证书运维手册不在本系列展开;只需记住——能 commit 的走事务命令,文档写明 reload 后不恢复的,必须回写配置。

2.4 Frontend 开关与 maxconn

disable frontend / enable frontendset maxconn frontend 等可在不停进程的情况下关掉入口或调并发上限。disable frontend 会释放该 frontend 的监听绑定语义(文档描述为停止接受),常用于事故隔离;它不等于增加一个新的 bind 地址。

命令形态(语义示例,路径以本机 stats socket 为准):

echo "set server api/s1 weight 50%" | socat stdio /run/haproxy/admin.sock
echo "set server api/s1 state drain" | socat stdio /run/haproxy/admin.sock
echo "clear table http_front key 10.0.1.55" | socat stdio /run/haproxy/admin.sock
echo "show info" | socat stdio /run/haproxy/admin.sock

show info / show stat / show sess / show table 用于核对进程身份、计数器与会话;本系列不粘贴未在本机实跑的输出。字段含义与排障落点见 第 13 篇;具体脚本见 network/56


三、必须 reload:结构、绑定、规则拓扑

下列变更默认写文件并走 seamless reload(-sf / master-worker SIGUSR2),而不是指望一条 CLI:

  1. 新的 bind / 监听地址族 / 端口拓扑(含多数 SSL bind 结构变更)。
  2. 新增或删除 frontend / backend / listen 段(结构性增删;个别实验性/受限的动态 backend 命令不改变「配置文件仍是真相源」这一运维模型)。
  3. ACL / use_backend / http-request 规则树的结构改写(字段、动作、顺序),而不只是 pattern 内容。
  4. 全局调优与多数 tune.*、线程组布局、日志目标拓扑等进程级参数。
  5. 健康检查探针定义、多数 filter/SPOE 挂载点等与解析期绑定的对象。
Runtime:  改「已有对象的运行态与表内容」
Reload:   改「对象图本身与 bind 拓扑」

边界上的灰色地带(如部分 SSL 证书热更新、动态 server)仍以 3.4.3 命令表 + Configuration Manual 为准:能 commit 的走事务命令;文档写明「reload 后不恢复」的,必须回写配置或 state 流程。

Nginx 深度(network/55) 对照:Nginx 的动态面更窄,多数变更直接等同 reload;HAProxy 把「服务器与表」从 reload 里拆了出来,但没有把结构面拆成可 ACK 的资源树——那是 Envoy/xDS 的格。进程级交接本身(旧进程如何 soft-stop、FD 如何交接)见 第 12 篇;其时间线与 Envoy hot-restart 同属「新听旧排」家族,但日常触发频率因 Runtime 面宽度而不同。

实践上还有一类「看起来像结构、其实可热改」的错觉:例如「加一个后端机器」。若 backend 与动态算法已在文件里声明,且用 add server(并接受 reload 后须回写的纪律),可以不 reload;若要的是新的 backend 名、新的 balance 算法族、或新的 use_backend 分支,则必须 reload。判断口诀:改对象属性 → Runtime;改对象图 → 文件。


四、Master CLI:看得到 leaving worker

globalmaster-worker(或 -W)下,可用 -S 绑定 Master CLIManagement Guide §9.4)。它面向所有进程:当前 worker、以及 soft-stop 尚未退出的 leaving worker。

要点:

# Master CLI:列出进程,再对指定 worker 发命令(路径示例)
echo "show proc" | socat stdio /run/haproxy-master.sock
echo "@!11955 show info" | socat stdio /run/haproxy-master.sock

Worker 上的 stats socket 仍是日常自动化首选;Master CLI 是生命周期与多进程可见性的补丁,不是替代整个 Runtime 菜谱。

reload 窗口里若只连 worker 的 admin.sock,可能连到 current,也可能在多 socket 场景下连到非预期进程——文档提醒多进程共享同类 socket 时「谁捡起请求谁回答」。因此涉及「刚 reload」的核对,优先 Master CLI 显式选 PID,再发只读命令。写变更时更要小心:对 leaving worker 做 set weight 往往无意义(它已在排空),对 current 的变更又不会自动回写文件。


五、运维模型:何时 Runtime、何时 reload

场景 优先路径 原因
单机摘流、改权重、清限流键 Runtime 无双进程窗口;秒级生效
扩容动态 server 且可回写 cfg/state Runtime + 持久化纪律 避免 reload 后幽灵节点
新域名 bind、新路由树、改 LB 算法结构 文件 + reload 结构只能由解析器重建
二进制升级、全局线程布局 reload / 滚动 必须新进程镜像

争论点(工程,非跑分):频繁 reload 会引入文档已记载的毫秒级 bind 竞态窗口与 backlog 丢连接可能(见第 12 篇);过度依赖 Runtime 则使磁盘配置与内存真相分叉,事故时「Git 与线上不一致」。健康模型是:结构变更走文件;运行态急救走 Runtime;关键 Runtime 变更有回写或 state 门禁。

一个可操作的门禁草案(本机落地时再改成脚本,此处只定语义):结构合并进主分支后必须 haproxy -c 通过再 reload;Runtime 变更若影响容量规划(权重、maxconn、动态 server),必须在变更流水线留下命令审计,并在约定时间内回写配置或刷新 state file;任何「只存在于内存」的长期状态视为债务。对照 network/56 的运维章节可把门禁落成具体命令,但不要把菜谱复制进机制文。

开放衔接:stick-table 在热清与 peers 复制下的一致性、以及「reload 与 Runtime 混用」的可观测缺口,收在 第 14 篇


六、参考资料

规范 / 官方文档(A)

工程对照(B)

源码锚点(A,路径级)

读完这篇,下一步读什么

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


By .