【HAProxy 数据面】Stick-table:键类型、容量、跨线程可见性与 peers/reload
内容提要
HAProxy的stick-table机制同时支持会话粘滞和跟踪计数,其记忆能力由键类型、大小、过期时间和存储列共同定义。表满和过期是显式失败模式,分别导致限流变松和粘滞丢失。nbthread共享表,而nbproc不共享,多进程下全局限流语义会破裂。Peers与reload继承用于对齐多节点决策状态,与FD交接不同。存储列与键空间对齐决定跨代理标记是否生效,热路径写共享表有性能成本。
延伸解读
容量规划:按项宽度估算,而非只看条目数
stick-table 的 size 是表项容量上界,但每项实际占用内存还取决于 store 列的数量与类型。store 列越多,每项字节越大,同样 size 下内存与缓存局部性越差。规划时应按项宽度估算内存,而不是只看条目数。满表时,nopurge 选项可避免驱逐旧项,但代价是新客户端无法进入表。
跨进程限流陷阱:nbproc 下阈值被放大
nbproc 多进程模式下,每个进程拥有独立的 stick-table,全局限流阈值实际被放大为进程数倍。例如,若配置限流 100 req/s,在 4 进程下每进程可独立处理 100 req/s,总限流变为 400 req/s。因此,现代配置应使用 nbthread,使表在进程内共享,保证限流语义一致。
键空间对齐:跨代理标记的静默陷阱
通过 gpc0 等标记跨代理传递状态时,必须确保各代理的 stick-table 键类型一致。例如,前端用 src(IP 地址),后端从 X-Forwarded-For 提取字符串,键类型不同会导致后端标记无法被前端读取,形成静默逻辑错误。配置校验不一定能发现此类问题,需人工核对键类型。
热路径成本:每请求写共享状态的代价
stick-table 的 track-sc 和 store 操作在热路径上会触碰共享内存结构,带来锁或原子操作开销。store 列越多、track 越早、键基数越高,每请求写共享状态的成本越接近可扩展性上限。因此,应合理设计 store 列,避免不必要的计数,以降低 CPU 与缓存压力。
Q&A
HAProxy的stick-table主要解决什么问题?
HAProxy的stick-table机制用于跨请求记住状态,如粘滞到哪台服务器、客户端速率、标记和滥用计数等,解决负载均衡中“跨请求记住什么”的问题。
HAProxy stick-table的键类型有哪些?
键类型包括整数、字符串、地址三类样本,配置面细化为ip、ipv6、integer、string、binary等声明形式。
HAProxy中nbthread和nbproc对stick-table的可见性有何不同?
nbthread(多线程)下,stick-table在进程内线程间共享,ACL读到的速率接近进程全局;nbproc(多进程)下,每个进程有独立的表,全局限流变成每进程一份,有效阈值被放大约进程数倍。
HAProxy stick-table表满或过期时会发生什么?
表满时新客户端可能插不进或挤掉旧项,导致粘滞丢失、限流变松;过期过短会导致粘滞或封禁标记过早消失,滥用源换连接后计数归零。
HAProxy peers和reload继承对stick-table有什么作用?
Peers用于在多个HAProxy节点间进行active-active复制,使粘滞和速率状态在多节点间共享;reload继承可将表内容复制到新进程,减少热更新时状态丢失。
HAProxy中store列与键空间对齐对跨代理标记有何影响?
store列与键空间对齐决定跨代理标记是否生效。如果两张表的键类型不一致(如一端ip、一端string),后端标记了但前端可能读不到,造成静默逻辑bug。
HAProxy stick-table热路径写入有什么性能成本?
热路径上每个请求track-sc加多store计数,会触碰共享结构,带来CPU和缓存成本,列越多、track越早、键基数越高,越接近每请求写共享状态的可扩展性上限。