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-table、stick on、track-sc*、peers;Management / 配置中关于nbthread的说明。源码 tag v3.4.3。无伪造show table输出。
本篇不展开:Enterprise Stick Table Aggregator、完整 store 类型列表背诵、peers 协议字节级分析。与规则引擎的耦合见 第 6 篇;seamless reload 进程交接见第 12 篇。
一、表是什么:粘滞与跟踪两条线
Starter Guide §3.4.5:
- 粘滞(stickiness):键是识别访客的样本(源地址、SSL ID、cookie、从 URL/载荷取出的客户号等),值是 server 标识;在请求或响应处理中,当键与 server 都已知时提交。
- 键类型:整数、字符串、地址三类样本(配置面细化为
ip/ipv6/integer/string/binary等声明形式)。 - 每 proxy 引用一张主表(以 proxy 名指代);最多 8 路并行学习源可指向不同表。
- 跟踪(tracking):可不粘滞到
server,而只把每客户端统计写入表;最多同时跟踪
3 个来自不同表的
key(
track-sc0/1/2)。 - 可 store
的额外信息:出入带宽、并发连接、连接速率与计数、错误频度、标签与计数器等,需显式
store。 - 复制:可通过 peers 在节点间以 multi-master 方式复制;reload 时也可复制到新进程,使多节点/新旧进程在客户端打散时仍倾向相同路由决策。
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 ...] ...
声明;type 与 size
为强制项(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 两句钉死运维语义:
- 表内容可与称为 peers 的其他 HAProxy 节点做 active-active 复制;
- 也可在 reload 时复制到新进程,使负载均衡节点共享信息并在客户端打散时倾向相同路由决策。
含义:
- 多节点 active-active:没有 peers 时,粘滞与速率状态是每节点局部的;客户端经 DNS/ECMP/VIP 飘移会换节点,表现为粘滞失效或限流「变松」。
- reload:新进程若能继承表,可减少「热更新瞬间人人变成新访客」。继承失败或未配置 peers/reload 同步路径时,粘滞与封禁标记会掉——这与 seamless reload 的 FD 交接是不同轴:FD 保住了连接,不自动等于表状态保住了。
- 一致性模型:peers 是为路由决策趋同服务的复制,不是线性一致数据库。把 stick-table 当成跨机精确账本会高估它;适合粘滞与粗粒度滥用控制,不适合强一致配额。
配置上需 peers 段 + 表声明中的
peers <section>;本机 peer 名需与
-L / localpeer 约定一致。细节以 Configuration
Manual peers 章节为准,本篇不展开证书式逐步操作。
Peers
复制的是表项内容,不是「把整份配置变成强一致状态机」。计数型
store 在多节点写入时,开源 peers 路径的聚合语义与 Enterprise
侧聚合器不同——本系列只钉开源 3.4.3:以文档所述 multi-master
复制服务路由决策趋同为限,不为未引用的聚合产品写保证。reload
继承同样服务于「新进程不要从零认识所有客户端」,若表在旧进程已因
size 驱逐而残缺,新进程继承的也是残缺快照。
五、与 ACL / LB 的交界(只钉耦合)
- 粘滞命中:LB 算法被绕过或降级为「已钉
server」(见第 7 篇
balance开篇条件)。 - 跟踪 + ACL:第 6 篇的
track-sc/sc*_rate/ GPC 标记模式;表是状态,规则是控制流。 - Runtime:表项可被 CLI
检索、转储、清理(Starter
Guide)——属于观测与急救,不替代合理的
size/expire设计。
对照 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)
- HAProxy 3.4.3 Starter Guide §3.4.5 Stick-tables;§3.3.6 Stickiness。
- HAProxy 3.4.3 Configuration
Manual:
stick-table、stick on、track-sc*、peers、nbthread。
维护者 / 官方博客(B)
- HAProxy Technologies,Multithreading in HAProxy(线程模型、表与连接亲和)。
- HAProxy Technologies,Introduction to HAProxy stick
tables(
nbproc下表不共享、peers 动机)。
源码(A)
- tag v3.4.3:
stick_table/ peers 相关实现目录(以树内名为准)。
站内
实验台账
- 本篇无
show table实跑输出;不声称未测量的 peers 延迟数字。
九、小结
- Stick-table
同时服务粘滞与跟踪计数;键类型、
size、expire、store共同定义记忆能力。 - 满表与过期是一等失败模式;会表现为限流变松或粘滞丢失,而不是清晰的配置错误。
nbthread共享表;nbproc不共享——「全局限流」在多进程下语义破裂。- Peers 与 reload 继承对齐的是多节点/新旧进程的决策状态;与 FD 交接不是同一保证。
store列与键空间对齐决定跨 proxy 标记能否生效;热路径写共享表有明确成本。
→ 系列目录 · 上一篇:Backend / server / LB · 下一篇:Health-check 引擎
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【HAProxy 数据面】线程与调度:nbthread、Thread-group 与共享内存边界
钉住 HAProxy 单进程多线程模型:每线程事件循环、连接单线程服务;对照 nbproc 下 stick-table 不共享,以及 Nginx 多进程与 Envoy Main/Worker;说明 poller 线程上阻塞的软警告。
【HAProxy 数据面】Seamless reload 与 soft-stop:FD 交接、排空与状态保留
按 HAProxy 3.4.3 Management Guide 拆解 -x / expose-fd listeners / master-worker sockpair 的 listen FD 交接、SIGUSR1 soft-stop 排空,以及 stick-table/peers 在 reload 下的保留边界;对照 Nginx 与 Envoy hot-restart。
【HAProxy 数据面】ACL / 规则引擎:求值顺序、副作用与 stick-table 耦合
把 ACL 与 http-request / use_backend 当作数据面机制:说明连接期到 L7 的求值顺序、动作副作用如何改写后续条件,以及与 stick-table 限流/标记的耦合点;不写 ACL 关键字百科。
【HAProxy 数据面】Runtime API:可热改边界与必须 reload 的配置面
按 HAProxy 3.4.3 Management Guide 钉住 Runtime API 能改什么、不能改什么;区分 worker stats socket 与 master CLI,说明热改与 seamless reload 的语义边界。