ALB Ingress 限流基础用法:从注解到自定义 Action
ALB 限流不是把流量挡在 K8s 集群外,而是把”超额请求”在云厂商的边缘负载均衡上直接拒绝。本文基于 alibaba-load-balancer-controller 源码梳理 ACK ALB Ingress 的 TrafficLimit 用法,包括注解、自定义 Action、组合写法与避坑指南。
为什么要在 ALB 上做限流?
在 Kubernetes 集群里,限流通常有两种做法:
| 位置 |
典型实现 |
优点 |
缺点 |
| 业务代码 / 中间件 |
Sentinel、Istio 限流 Filter |
灵活、可基于业务维度 |
回源后才拦截,浪费带宽;与业务耦合 |
| 云负载均衡边缘 |
ALB TrafficLimit Action |
拒绝在边缘发生、不回源、纯声明式 |
维度有限,只看 IP / 全局 QPS |
对于”防爬虫、防刷、秒杀压测兜底、批量接口保护”这类典型场景,把限流下推到 ALB 才是最经济的:
- ALB 直接返回 HTTP 503,请求不会到达后端 Pod,省回源带宽、省 Pod 算力;
- 通过 Ingress 注解或
actions 自定义即可下发,无需修改业务代码;
- 限流阈值随 Ingress 一起
kubectl apply,与 GitOps 流水线天然契合。
能力概览
ACK ALB Controller 通过 Ingress Annotation 或 自定义 Action 两种方式下发 ALB 的 TrafficLimit 规则。
| 维度 |
说明 |
| 作用对象 |
单条 Ingress 路由(或通过自定义 Action 精确到路径) |
| 生效位置 |
ALB 七层监听器(HTTP / HTTPS),四层监听器不生效 |
| 维度 1 |
全局限流:限制整个 Ingress 的总 QPS(TrafficLimitConfig.QPS) |
| 维度 2 |
单 IP 限流:限制每个客户端 IP 的 QPS(TrafficLimitConfig.PerIpQps) |
| 生效顺序 |
两个维度同时存在时,ALB 取”先触发”的那一个(源码校验 PerIpQps < QPS) |
| 取值范围 |
1 ~ 100000(整数,源码在 model_build_listener_rules.go 做范围校验) |
| 超出行为 |
直接返回 HTTP 503,请求不回源 |
源码位置(alibaba-load-balancer-controller):
- 注解常量:
pkg/controller/ingress/reconcile/annotations/annotations.go(L82-83)
- 模型定义:
pkg/model/alb/alb.go :: TrafficLimitConfig(L248-251)
- 取值范围:
pkg/util/constant.go :: ActionTrafficLimitQpsMin = 1(L342)
- 构建逻辑:
pkg/controller/ingress/reconcile/builder/albconfig_manager/model_build_listener_rules.go :: buildQpsLimitAction(L736-793)
- SDK 转换:
pkg/provider/alibaba/alb/rule.go(L387-396 / L757-792)
两种使用方式
方式 1:注解形式(整 Ingress 范围生效,最简单)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: api-with-rate-limit namespace: default annotations: alb.ingress.kubernetes.io/traffic-limit-qps: "1000" alb.ingress.kubernetes.io/traffic-limit-ip-qps: "10" spec: ingressClassName: alb rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: backend-api-svc port: number: 80
|
要点:
- 两个注解都是可选的,只填一个也可生效。
- 当两个都填时,源码会校验
PerIpQps < QPS,否则 reconcile 失败并提示 traffic limit action qps per ip must less than qps。
方式 2:自定义 Action 形式(路径级,可与转发策略组合)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: api-path-level-limit namespace: default annotations: alb.ingress.kubernetes.io/actions.heavy-svc: | [{"type":"TrafficLimit","TrafficLimitConfig":{"QPS":"50"}}] alb.ingress.kubernetes.io/actions.light-svc: | [{"type":"TrafficLimit","TrafficLimitConfig":{"PerIpQps":"20"}}] spec: ingressClassName: alb rules: - host: api.example.com http: paths: - path: /heavy pathType: Prefix backend: service: { name: heavy-svc, port: { number: 80 } } - path: /light pathType: Prefix backend: service: { name: light-svc, port: { number: 80 } }
|
要点:
actions.<svcName> 的 JSON 数组里可以与 ForwardGroup / InsertHeader / Rewrite 等组合,实现”先限流再转发”。
QPS / PerIpQps 必须是字符串数字(如 "50"),来自源码 transSDKTrafficLimitConfigToCreateRules。
互斥规则
源码(model_build_listener_rules.go:867-873)中明确:注解形式(traffic-limit-qps / traffic-limit-ip-qps)与自定义 Action 中的 TrafficLimit 不能同时存在,否则 reconcile 报错:
1
| can't exist action trafficlimit and annotation traffic-limit-qps at the same time
|
4 个典型用法配置
下面给出一份可一键 kubectl apply -f 的完整示例,覆盖最常见的 4 种用法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
apiVersion: v1 kind: Namespace metadata: name: alb-demo ---
apiVersion: v1 kind: Service metadata: name: backend-api-svc namespace: alb-demo spec: selector: app: backend-api ports: - name: http port: 80 targetPort: 8080 --- apiVersion: apps/v1 kind: Deployment metadata: name: backend-api namespace: alb-demo spec: replicas: 2 selector: matchLabels: app: backend-api template: metadata: labels: app: backend-api spec: containers: - name: app image: nginx:1.25-alpine ports: - containerPort: 8080 readinessProbe: httpGet: path: / port: 8080 ---
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-global-qps namespace: alb-demo annotations: alb.ingress.kubernetes.io/traffic-limit-qps: "100" spec: ingressClassName: alb rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: backend-api-svc port: number: 80 ---
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-per-ip-qps namespace: alb-demo annotations: alb.ingress.kubernetes.io/traffic-limit-ip-qps: "5" spec: ingressClassName: alb rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: backend-api-svc port: number: 80 ---
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-combined-qps namespace: alb-demo annotations: alb.ingress.kubernetes.io/traffic-limit-qps: "1000" alb.ingress.kubernetes.io/traffic-limit-ip-qps: "10" spec: ingressClassName: alb rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: backend-api-svc port: number: 80 ---
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-path-level-qps namespace: alb-demo annotations: alb.ingress.kubernetes.io/actions.heavy-svc: | [{"type":"TrafficLimit","TrafficLimitConfig":{"QPS":"50"}}] alb.ingress.kubernetes.io/actions.light-svc: | [{"type":"TrafficLimit","TrafficLimitConfig":{"PerIpQps":"20"}}] spec: ingressClassName: alb rules: - host: api.example.com http: paths: - path: /heavy pathType: Prefix backend: service: name: heavy-svc port: number: 80 - path: /light pathType: Prefix backend: service: name: light-svc port: number: 80
|
典型场景速查
| 场景 |
推荐配置 |
说明 |
| 活动期间保护后端 |
traffic-limit-qps: "100" |
全局硬上限,超额直接 503 |
| 防爬虫 / 防刷 |
traffic-limit-ip-qps: "5" |
每个客户端 IP 最多 5 QPS |
| 生产推荐组合 |
traffic-limit-qps: "1000" + traffic-limit-ip-qps: "10" |
全局兜底 + 每 IP 防滥用 |
| 路径级差异化 |
actions.<svc> + TrafficLimit |
重接口 / 价值低的接口单独配 |
一句话原则:接口越重、价值越低,越要限——例如管理后台、报表导出、批量接口单独配限。
与 ALB 自定义转发的组合写法
TrafficLimit 类型的 Action 可以和 ForwardGroup、Rewrite、InsertHeader、FixedResponse 等并列存在。下面是一个”先限流、再插头部、再转发到指定 server group”的例子:
1 2 3 4 5 6 7
| annotations: alb.ingress.kubernetes.io/actions.limited-fwd: | [ {"type":"TrafficLimit","TrafficLimitConfig":{"QPS":"200","PerIpQps":"20"}}, {"type":"InsertHeader","InsertHeaderConfig":{"key":"X-Rate-Limited","value":"true","valueType":"UserDefined"}}, {"type":"ForwardGroup","ForwardConfig":{"ServerGroups":[{"ServerGroupID":"sgp-xxxxxxxx","Weight":100}]}} ]
|
说明:QPS 和 PerIpQps 同时配置时,源码同样校验 PerIpQps < QPS。
验证生效
压测观测
1 2 3 4
| ab -n 2000 -c 50 -H "Host: api.example.com" http://<ALB-endpoint>/
|
在 ALB 控制台确认
监控 → ALB 实例 → 选择实例 → 访问日志 / 监控指标:
检查控制器是否识别了注解
1
| kubectl describe ingress <ingress-name> -n <ns> | grep -A 5 "Annotations"
|
期望看到:
1 2
| alb.ingress.kubernetes.io/traffic-limit-qps: 1000 alb.ingress.kubernetes.io/traffic-limit-ip-qps: 10
|
如果 controller 在 reconcile 过程中判定限流值非法(例如 PerIpQps >= QPS),会在 Ingress 或 AlbConfig 的 status / 事件中报错,可通过 kubectl describe ingress 或 kubectl get events 查看原因。
常见问题
| 问题 |
原因与处置 |
reconcile 一直失败:traffic limit action qps out of range |
QPS 取值需 >= 1,且 <= 100000 |
reconcile 一直失败:qps per ip must less than qps |
同时配置两个注解时,PerIpQps 必须严格小于 QPS |
can't exist action trafficlimit and annotation traffic-limit-qps at the same time |
注解形式与自定义 Action 形式互斥,二选一 |
| 限流不生效 |
确认 ingressClassName: alb、且走的是 ALB 七层监听器(HTTP/HTTPS),四层监听器不生效 |
| 修改后没生效 |
注解变更后 controller reconcile 需要 10~30s,可用 kubectl get albconfig -w 观察 |
源码速查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| pkg/controller/ingress/reconcile/annotations/annotations.go 82: AlbTrafficLimitQps = AnnotationAlbPrefix + "traffic-limit-qps" 83: AlbTrafficLimitIpQps = AnnotationAlbPrefix + "traffic-limit-ip-qps"
pkg/controller/ingress/reconcile/builder/albconfig_manager/model_build_listener_rules.go 736-793: buildQpsLimitAction(qps, qpsPerIp) - 校验 qpsi >= ActionTrafficLimitQpsMin (1) - 校验 PerIpQps < QPS - 构造 alb.Action{Type:"TrafficLimit", TrafficLimitConfig:{QPS, PerIpQps}} 867-873: 互斥校验:注解形式与自定义 Action 不能同时存在
pkg/model/alb/alb.go 248-251: type TrafficLimitConfig struct { QPS int PerIpQps int }
pkg/util/constant.go 342: ActionTrafficLimitQpsMin = 1
pkg/provider/alibaba/alb/rule.go 387-396: 数字转字符串后写入 ALB OpenAPI QPS / PerIpQps 757-792: transSDKTrafficLimitConfigToCreateRules
|
总结
把限流下推到 ALB 边缘,是用 ACK 时最被低估的”省成本”手段之一。它的核心价值在于:
- 声明式:用 Ingress 注解就能配置,随 GitOps 一起发布;
- 零回源:超额请求在 ALB 边缘被直接拒绝,省回源带宽、省 Pod 算力;
- 双维度:全局 + 单 IP 双层防护覆盖大多数典型场景;
- 可组合:
TrafficLimit 可以与 ForwardGroup / InsertHeader 等 Action 组合,写法灵活。
踩坑要点只有三个:取值范围 1~100000、**PerIpQps < QPS、注解与自定义 Action 互斥**。把这三条记牢,剩下的就交给 ALB 即可。
参考