Stick-Table是HAProxy内存中维护客户端与后端1:1映射关系的键值表,支持IP、Header、Cookie等多维度标识提取,实现无状态后端下的可靠会话保持,且不依赖客户端Cookie支持。

Stick-Table 是什么,为什么不能只靠 cookie 插入
HAProxy 的 stick-table 不是会话保持的“备选方案”,而是唯一能真正实现**无状态后端 + 客户端无 cookie 支持 + 多维度关联**的机制。单纯用 cookie insert 依赖客户端存储和回传,一旦用户禁用 cookie、使用 CLI 工具调用 API,或后端返回 302 跳转丢失 cookie,就会断连。而 stick-table 在 HAProxy 内存中维护映射关系,只要请求能被 HAProxy 解析(比如带 IP、Header、URL 参数),就能绑定到同一后端服务器。
如何定义 stick-table 并关联 backend
必须在 backend 或 listen 块中显式声明 stick-table,且需搭配 stick on 才生效。常见错误是只写 stick-table 却漏掉 stick on,结果表建了但完全不触发匹配。
-
stick-table type ip size 1m expire 30m:按源 IP 绑定,适合内网固定出口场景;size 1m表示最多存 100 万条记录,不是字节数 -
stick-table type string len 64 size 100k expire 1h:用于提取 header 或 URL 参数,len 64必须 ≥ 实际值长度,否则截断导致误匹配 -
stick on req.cook(NAME):提取名为NAME的 cookie 值;若 cookie 不存在,该请求不会命中 stick-table,走默认调度(如 roundrobin) -
stick on hdr(X-User-ID):提取请求头,注意大小写敏感,且 HAProxy 默认不保留原始 header 大小写(需option http-ignore-probes等配合)
如何从请求中提取稳定标识并写入 stick-table
仅“读取”标识不够,还需确保首次请求能成功写入表中——否则后续请求永远查不到。关键在于 stick store-request 和 http-request set-var 的组合使用。
- 若想用 JWT 中的
sub字段做粘性:先用http-request set-var(req.sub) str(0) if { path_beg /api/ }占位,再用http-request set-var(req.sub) str(%[hdr(x-jwt)])提取(实际需解析 JWT,此处简化),最后stick store-request req.sub - 更稳妥的做法是用
http-request set-header X-Stick-ID %[src]强制注入一个可追踪 ID,再stick on hdr(X-Stick-ID),避免首次请求因无标识而跳过写入 - 不要在
frontend中定义stick-table后直接use_backend跳转:stick-table 只对当前作用域(backend/listen)有效,跨 scope 不共享
调试 stick-table 是否生效的三个实操步骤
最常卡在“配置写了但没效果”,根本原因是没验证 stick-table 是否真在收数据、是否真在匹配。别猜,直接看运行时状态。
- 启用 stats 页面:
stats enable+stats uri /haproxy?stats,登录后点 “Sticking rules” 标签页,看 “Entries” 数量是否增长 - 用
echo "show table mytable" | sudo socat stdio /var/run/haproxy.sock(路径以stats socket配置为准),检查 key 是否是你期望的值(如192.168.1.100或user-123) - 加日志:
option http-log+log global,观察 access log 中%{+Q}r和%s字段,确认 backend server 名与 stick-table 记录一致;若%s总是空,说明stick on没匹配上任何请求
stick-table 的 key 生命周期、内存占用、跨进程同步(多 worker 下)都是隐性复杂点,上线前务必用真实流量压测,而不是只跑 curl 几次。











