【HAProxy 数据面】ACL / 规则引擎:求值顺序、副作用与 stick-table 耦合

💡 原文中文,约7700字,阅读约需19分钟。
📝

内容提要

本文介绍HAProxy规则引擎(ACL)在数据面的位置与副作用。核心要点:规则按相位(连接、内容、HTTP请求)顺序求值,动作有副作用,顺序即语义;use_backend是有序内容交换,选中后仍有LB/队列;track与reject/deny的相对顺序影响限流计数;内容规则可反复求值,需注意性能;与stick-table耦合实现跨段状态共享。

🔎

延伸解读

相位错位是ACL不生效的常见根因

文章指出,很多ACL“写了却不生效”并非语法错误,而是求值相位不对。例如,连接期规则读不到Host,或track-sc排在reject之后导致计数为空。理解tcp-request connection、tcp-request content、http-request等相位的可读样本和动作,是排障的第一步。

动作顺序决定限流语义

规则引擎中动作有副作用,顺序即语义。先reject再track,被拒连接可能不计入计数;先track再reject,速率窗口包含当前连接。类似地,http-request deny若写在track-sc之前,会导致表空但403多。设计限流时,必须明确想要的失败模式,并据此安排动作顺序。

use_backend选路不等于上游可用

use_backend是有序内容交换,选中backend后仍有LB、队列和健康检查。即使选路成功,也可能因无可用server或队列满而返回503。排障时应区分选路问题和上游可用性问题,不要在前端ACL层假设上游一定可用。

内容规则反复求值需注意性能

tcp-request content阶段的ACL会随缓冲填充反复求值,直到出现accept/reject或检查延迟到期。昂贵ACL(如大regex)可能被多次执行,放大CPU消耗。应合理设置inspect delay,并将重计算放在依赖完整头部的条件中,以控制性能影响。

Q&A

HAProxy中ACL规则在数据面的求值顺序是怎样的?

HAProxy的ACL规则按相位顺序求值:tcp-request connection、tcp-request content、http-request、use_backend、backend http-request。每个相位有各自的可读样本和可执行动作,规则按声明顺序执行,条件在动作前求值。

use_backend和ACL的关系是什么?为什么说use_backend是有序内容交换?

use_backend根据ACL条件选择后端,列表是有序的,先命中先生效,未命中则落到default_backend。它不同于所有ACL同时成立再投票,而是按顺序匹配。选中后端后,仍有负载均衡、队列等处理,不代表上游一定可用。

在HAProxy中,track和reject的顺序对限流有什么影响?

如果先reject再track,被拒绝的连接可能不会计入计数器,导致限流不准确;如果先track再reject,则速率窗口包含当前连接,能更准确限流。顺序决定了计数语义,应根据期望的失败模式选择。

HAProxy中ACL规则与stick-table是如何耦合的?

ACL条件可以读取sticky counter(如sc0_http_req_rate),动作侧用track-sc*、sc-inc-gpc*等写入。通过stick-table,可以在不同proxy(如frontend和backend)之间共享状态,实现跨段标记和限流。但需注意表共享模型(nbthread vs nbproc)的影响。

为什么说HAProxy的内容检查规则会反复求值?对性能有什么影响?

在TCP内容检查阶段,随着请求内容更新,ACL规则会反复求值,直到出现accept/reject/switch-mode或检查延迟到期。这可能导致昂贵ACL(如大regex)被多次执行,放大CPU消耗。应合理设置inspect delay,并将重计算放在需要完整头部的条件中。

HAProxy中ACL短路求值是什么意思?如何利用它优化性能?

ACL的OR已真或AND已假时短路,后续子句不求值。因此应将便宜且区分度高的fetch放在前面,昂贵的regex或大map放后面,以减少不必要的计算,提升性能。

🏷️

标签

➡️

继续阅读