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

【HAProxy 数据面】Stick-table:键类型、容量、跨线程可见性与 peers/reload

文章导航

分类入口
networkproxy
标签入口
#haproxy#stick-table#peers#nbthread#nbproc#rate-limit#persistence#3.4.3

目录

Backend / LB 解决「此刻选谁」;stick-table 解决「跨请求记住什么」——粘滞到哪台 server、某客户端的速率与标记、滥用计数等。表满、过期、多进程各记各的、reload 丢表,都会让 ACL 限流与粘滞「看起来配置正确却语义漂移」。本文钉表机制,不写 CLI 菜谱全书。

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

篇目 核心内容
第 7 篇 · Backend / LB 选主与队列
第 8 篇 · Stick-table 状态、共享、复制
第 9 篇 · Health-check 探活与调度

上一篇Backend / server / LB · 下一篇Health-check 引擎

版本锚定:HAProxy 3.4.3 Starter Guide §3.4.5 Stick-tables;Configuration Manual stick-tablestick ontrack-sc*peersManagement / 配置中关于 nbthread 的说明。源码 tag v3.4.3。无伪造 show table 输出。

本篇不展开:Enterprise Stick Table Aggregator、完整 store 类型列表背诵、peers 协议字节级分析。与规则引擎的耦合见 第 6 篇;seamless reload 进程交接见第 12 篇。


一、表是什么:粘滞与跟踪两条线

Starter Guide §3.4.5:

flowchart LR
  key["sample key"] --> table["stick-table"]
  table --> stick["server id stickiness"]
  table --> counters["rates / gpc / bytes"]
  table --> peers["peers / reload sync"]
  counters --> acl["ACL sc* fetches"]

配置形态上,表用 stick-table type <t> size <n> [expire ...] [store ...] [peers ...] ... 声明;typesize 为强制项(Configuration Manual)。stick on / stick store-request / stick store-response 写粘滞;track-sc* 写跟踪。


二、size / expire 与容量失败模式

size 规定表项容量上界;expire 规定空闲项可被回收的期限。容量与过期共同决定:高基数键空间下是「记不全」还是「记不久」。

容量失败时的典型后果(机制层,不编造某一版本的精确 purge 算法细节):

压力 可能表现
键基数 ≫ size 新客户端插不进或挤掉旧项 → 粘滞丢失、速率窗口「失忆」→ 限流变松或误放行
expire 过短 粘滞/封禁标记过早消失;滥用源换连接后计数归零
expire 过长且 size 表被历史键占满,新键更难进入
store 过多 每项字节变大,同样 size 下内存与缓存局部性变差(规划问题时要按项宽度估,而不是只看条目数)

nopurge 一类选项(社区文档与维护者博客广泛讨论)用于「满表时不要为接纳新键而驱逐」——结果是宁可拒绝新记账,也不偷偷丢掉旧策略状态。是否启用取决于你更怕「失忆放行」还是「新客户端无法进入表」。本篇强调:满表不是「自动弹性」,而是显式失败模式选择

跟踪中的项在仍被 track 时可以有「不因 expire 掉出」的语义(手册对 track 有「跟踪期间不 expire」相关说明)——因此长时间挂着的 sc 槽会钉住表项,放大容量压力。排障时要把「谁在 track」和「表 size」一起看。


三、跨线程可见性:nbthread 共享 vs nbproc 不共享

现代配置应使用 nbthread(多线程、单进程地址空间)。Configuration Manual 对历史 nbproc 路线的核心批评写在线程相关说明的演进里:多进程缺乏同步,health-check、peers、stick-tables、stats 等都会受影响;社区与维护者文档一致建议迁到 nbthread

模型 stick-table 可见性 限流/粘滞含义
nbthread(推荐) 同进程线程间共享内存中的表 ACL 读到的速率接近进程全局
nbproc > 1(历史) 每进程独立表 「全局限流」变成每进程一份,有效阈值被放大约进程数倍

这不是「线程更正确」的空话,而是状态是否在同一地址空间的直接推论。Peers 协议用于节点间同步;它不能替代「本机多进程各持一表」的缺口——维护者博客亦指出 peers 与多进程同机同步的历史限制。把 nbproc 留下来再靠 peers「补锅」通常是错误架构。

第 2 篇线程模型 的衔接:会话钉在接受它的线程上串行处理;表作为全局实体可被各线程访问,但更新路径仍有锁/原子代价。热路径上每个请求 track-sc + 多 store 计数,就是在买「跨请求记忆」的 CPU 与缓存成本。


四、Peers 复制与 reload 继承

Starter Guide §3.4.5 两句钉死运维语义:

  1. 表内容可与称为 peers 的其他 HAProxy 节点做 active-active 复制;
  2. 也可在 reload 时复制到新进程,使负载均衡节点共享信息并在客户端打散时倾向相同路由决策。

含义:

配置上需 peers 段 + 表声明中的 peers <section>;本机 peer 名需与 -L / localpeer 约定一致。细节以 Configuration Manual peers 章节为准,本篇不展开证书式逐步操作。

Peers 复制的是表项内容,不是「把整份配置变成强一致状态机」。计数型 store 在多节点写入时,开源 peers 路径的聚合语义与 Enterprise 侧聚合器不同——本系列只钉开源 3.4.3:以文档所述 multi-master 复制服务路由决策趋同为限,不为未引用的聚合产品写保证。reload 继承同样服务于「新进程不要从零认识所有客户端」,若表在旧进程已因 size 驱逐而残缺,新进程继承的也是残缺快照。


五、与 ACL / LB 的交界(只钉耦合)

对照 Envoy:Envoy 粘滞常靠一致哈希 / 会话亲和扩展;进程内「通用多列计数表 + peers」并不是同构一等公民。选型时不要假设「有 stick-table 就有 outlier」或反过来。


六、store 列与热路径成本

Starter Guide 把可存储统计概括为带宽、并发连接、连接速率与计数、错误频度、标签与计数器等,并强调必须显式声明。配置里常见的 store http_req_rate(10s),conn_rate(1s),gpc0 一类写法,每一列都占用表项宽度,并在 track/更新时触碰共享结构。

工程上可分成三档用途(机制分类,不是菜谱):

用途档 典型 store 数据面含义
粘滞 (server id 由 stick 规则写入) 改变选主;与 balance 条件互补
速率窗 http_req_rate / conn_rate ACL 限流;窗口长度写进类型参数
标记 gpc0 / 通用计数 跨 proxy 传「已判定滥用」等布尔式状态

手册示例把 frontend 拒绝与 backend 检测拆开,靠 gpc0 跨表传递——这要求两张表的键空间对齐(通常都是 src),否则「后端标了、前端永远读不到」。键类型不一致(一端 ip、一端从 X-Forwarded-For 取出的 string)是静默逻辑 bug,配置校验不一定能救你。

tune 层面对 sticky counter / 共享计数也有内存与线程组相关旋钮(Configuration Manual 的 tune 章节);本篇不逐条展开,但结论是:表不是免费的旁路字典,列越多、track 越早、键基数越高,越接近「每请求写共享状态」的可扩展性上限。这与第 2 篇线程组、第 14 篇开放问题中的 stick-table 规模讨论同一条线。


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

谱系:会话亲和从 cookie / 源哈希发展到可复制的进程内表,是为了在无共享存储的 LB 节点之间尽量对齐决策(Starter Guide 对 stickiness / stick-tables 的表述)。速率与 GPC 把同一结构从「记 server」扩展到「记行为」,使 DDoS/滥用对抗能跑在代理热路径上。

争论:表状态应更大更久,还是应无尽无状态哈希粘滞。前者运维强大但有容量与复制复杂度;后者简单但 server 变更时扰动大。官方同时提供两条路,本身就说明没有单一最优。

开放问题:peers 在高变更率计数(每请求 http_req_rate)下的复制开销与「决策足够相同」之间的定量边界,依赖部署拓扑,难以用文档中的定性句替代容量规划;跨线程更新的可扩展性与 NUMA 局部性仍是系列研究台账中的开放项。


八、参考资料

规范 / 官方文档(A)

维护者 / 官方博客(B)

源码(A)

站内

实验台账


九、小结

  1. Stick-table 同时服务粘滞与跟踪计数;键类型、sizeexpirestore 共同定义记忆能力。
  2. 满表与过期是一等失败模式;会表现为限流变松或粘滞丢失,而不是清晰的配置错误。
  3. nbthread 共享表;nbproc 不共享——「全局限流」在多进程下语义破裂。
  4. Peers 与 reload 继承对齐的是多节点/新旧进程的决策状态;与 FD 交接不是同一保证。
  5. store 列与键空间对齐决定跨 proxy 标记能否生效;热路径写共享表有明确成本。

系列目录 · 上一篇:Backend / server / LB · 下一篇:Health-check 引擎

读完这篇,下一步读什么

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


By .