Skip to content

Commit 634de3f

Browse files
authored
feat: cluster key rate limit enhancement (#1036)
1 parent 12cc44b commit 634de3f

File tree

6 files changed

+430
-228
lines changed

6 files changed

+430
-228
lines changed

plugins/wasm-go/extensions/cluster-key-rate-limit/README.md

+146-85
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,50 @@
11
# 功能说明
22

3-
`key-cluster-rate-limit`插件实现了基于特定键值实现集群限流,键值来源可以是 URL 参数、HTTP 请求头、客户端 IP 地址
3+
`key-cluster-rate-limit`插件实现了基于特定键值实现集群限流,键值来源可以是 URL 参数、HTTP 请求头、客户端 IP 地址、consumer 名称、cookie中 key 名称
44

55

66

77
# 配置说明
88

9-
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
10-
| ----------------------- | ------ | ---- | ------ | ---- |
11-
| rule_name | string || - | 限流规则名称,根据限流规则名称和限流的客户端IP段来拼装redis key |
12-
| limit_by_header | string | 否,`limit_by_header`,`limit_by_param`,`limit_by_per_ip` 中选填一项 | - | 配置获取限流键值的来源 http 请求头名称 |
13-
| limit_by_param | string | 否,`limit_by_header`,`limit_by_param`,`limit_by_per_ip` 中选填一项 | - | 配置获取限流键值的来源 URL 参数名称 |
14-
| limit_by_per_ip | string | 否,`limit_by_header`,`limit_by_param`,`limit_by_per_ip` 中选填一项 | - | 配置获取限流键值的来源 IP 参数名称,从请求头获取,以`from-header-对应的header名`,示例:`from-header-x-forwarded-for`,直接获取对端socket ip,配置为`from-remote-addr` |
15-
| limit_keys | array of object || - | 配置匹配键值后的限流次数 |
9+
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
10+
| ----------------------- | ------ | ---- | ------ |---------------------------------------------------------------------------|
11+
| rule_name | string || - | 限流规则名称,根据限流规则名称+限流类型+限流key名称+限流key对应的实际值来拼装redis key |
12+
| rule_items | array of object || - | 限流规则项,按照rule_items下的排列顺序,匹配第一个rule_item后命中限流规则,后续规则将被忽略 |
1613
| show_limit_quota_header | bool || false | 响应头中是否显示`X-RateLimit-Limit`(限制的总请求数)和`X-RateLimit-Remaining`(剩余还可以发送的请求数) |
17-
| rejected_code | int || 429 | 请求被限流时,返回的HTTP状态码 |
18-
| rejected_msg | string || Too many requests | 请求被限流时,返回的响应体 |
19-
| redis | object || - | redis相关配置 |
14+
| rejected_code | int || 429 | 请求被限流时,返回的HTTP状态码 |
15+
| rejected_msg | string || Too many requests | 请求被限流时,返回的响应体 |
16+
| redis | object || - | redis相关配置 |
17+
18+
`rule_items`中每一项的配置字段说明
19+
20+
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
21+
| --------------------- | --------------- | -------------------------- | ------ | ------------------------------------------------------------ |
22+
| limit_by_header | string | 否,`limit_by_*`中选填一项 | - | 配置获取限流键值的来源 HTTP 请求头名称 |
23+
| limit_by_param | string | 否,`limit_by_*`中选填一项 | - | 配置获取限流键值的来源 URL 参数名称 |
24+
| limit_by_consumer | string | 否,`limit_by_*`中选填一项 | - | 根据 consumer 名称进行限流,无需添加实际值 |
25+
| limit_by_cookie | string | 否,`limit_by_*`中选填一项 | - | 配置获取限流键值的来源 Cookie中 key 名称 |
26+
| limit_by_per_header | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 HTTP 请求头,并对每个请求头分别计算限流,配置获取限流键值的来源 HTTP 请求头名称,配置`limit_keys`时支持正则表达式或`*` |
27+
| limit_by_per_param | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 URL 参数,并对每个参数分别计算限流,配置获取限流键值的来源 URL 参数名称,配置`limit_keys`时支持正则表达式或`*` |
28+
| limit_by_per_consumer | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 consumer,并对每个 consumer 分别计算限流,根据 consumer 名称进行限流,无需添加实际值,配置`limit_keys`时支持正则表达式或`*` |
29+
| limit_by_per_cookie | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 Cookie,并对每个 Cookie 分别计算限流,配置获取限流键值的来源 Cookie中 key 名称,配置`limit_keys`时支持正则表达式或`*` |
30+
| limit_by_per_ip | string | 否,`limit_by_*`中选填一项 | - | 按规则匹配特定 IP,并对每个 IP 分别计算限流,配置获取限流键值的来源 IP 参数名称,从请求头获取,以`from-header-对应的header名`,示例:`from-header-x-forwarded-for`,直接获取对端socket ip,配置为`from-remote-addr` |
31+
| limit_keys | array of object || - | 配置匹配键值后的限流次数 |
2032

2133
`limit_keys`中每一项的配置字段说明
2234

23-
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
24-
| ---------------- | ------ | ------------------------------------------------------------ | ------ | ------------------ |
25-
| key | string || - | 匹配的键值 |
26-
| query_per_second | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每秒请求次数 |
27-
| query_per_minute | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每分钟请求次数 |
28-
| query_per_hour | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每小时请求次数 |
29-
| query_per_day | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每天请求次数 |
35+
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
36+
| ---------------- | ------ | ------------------------------------------------------------ | ------ | ------------------------------------------------------------ |
37+
| key | string || - | 匹配的键值`limit_by_per_header`,`limit_by_per_param`,`limit_by_per_consumer`,`limit_by_per_cookie` 类型支持配置正则表达式(以regexp:开头后面跟正则表达式)或者*(代表所有),正则表达式示例:`regexp:^d.*`(以d开头的所有字符串);`limit_by_per_ip`支持配置 IP 地址或 IP 段 |
38+
| query_per_second | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每秒请求次数 |
39+
| query_per_minute | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每分钟请求次数 |
40+
| query_per_hour | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每小时请求次数 |
41+
| query_per_day | int | 否,`query_per_second`,`query_per_minute`,`query_per_hour`,`query_per_day` 中选填一项 | - | 允许每天请求次数 |
3042

3143
`redis`中每一项的配置字段说明
3244

3345
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
3446
| ------------ | ------ | ---- | ---------------------------------------------------------- | --------------------------- |
35-
| service_name | string | 必填 | - | 输入redis服务的注册名称 |
47+
| service_name | string | 必填 | - | redis 服务名称,带服务类型的完整 FQDN 名称,例如 my-redis.dns、redis.my-ns.svc.cluster.local |
3648
| service_port | int || 服务类型为固定地址(static service)默认值为80,其他为6379 | 输入redis服务的服务端口 |
3749
| username | string || - | redis用户名 |
3850
| password | string || - | redis密码 |
@@ -43,91 +55,140 @@
4355
# 配置示例
4456

4557
## 识别请求参数 apikey,进行区别限流
58+
4659
```yaml
47-
rule_name: limit_by_param_apikey
48-
limit_by_param: apikey
49-
limit_keys:
50-
- key: 9a342114-ba8a-11ec-b1bf-00163e1250b5
51-
query_per_second: 10
52-
- key: a6a6d7f2-ba8a-11ec-bec2-00163e1250b5
53-
query_per_minute: 100
60+
rule_name: default_rule
61+
rule_items:
62+
- limit_by_param: apikey
63+
limit_keys:
64+
- key: 9a342114-ba8a-11ec-b1bf-00163e1250b5
65+
query_per_minute: 10
66+
- key: a6a6d7f2-ba8a-11ec-bec2-00163e1250b5
67+
query_per_hour: 100
68+
- limit_by_per_param: apikey
69+
limit_keys:
70+
# 正则表达式,匹配以a开头的所有字符串,每个apikey对应的请求10qds
71+
- key: "regexp:^a.*"
72+
query_per_second: 10
73+
# 正则表达式,匹配以b开头的所有字符串,每个apikey对应的请求100qd
74+
- key: "regexp:^b.*"
75+
query_per_minute: 100
76+
# 兜底用,匹配所有请求,每个apikey对应的请求1000qdh
77+
- key: "*"
78+
query_per_hour: 1000
5479
redis:
5580
service_name: redis.static
5681
show_limit_quota_header: true
5782
```
5883
84+
85+
5986
## 识别请求头 x-ca-key,进行区别限流
87+
6088
```yaml
61-
rule_name: limit_by_param_x-ca-key
62-
limit_by_header: x-ca-key
63-
limit_keys:
64-
- key: 102234
65-
query_per_second: 10
66-
- key: 308239
67-
query_per_hour: 10
89+
rule_name: default_rule
90+
rule_items:
91+
- limit_by_header: x-ca-key
92+
limit_keys:
93+
- key: 102234
94+
query_per_minute: 10
95+
- key: 308239
96+
query_per_hour: 10
97+
- limit_by_per_header: x-ca-key
98+
limit_keys:
99+
# 正则表达式,匹配以a开头的所有字符串,每个apikey对应的请求10qds
100+
- key: "regexp:^a.*"
101+
query_per_second: 10
102+
# 正则表达式,匹配以b开头的所有字符串,每个apikey对应的请求100qd
103+
- key: "regexp:^b.*"
104+
query_per_minute: 100
105+
# 兜底用,匹配所有请求,每个apikey对应的请求1000qdh
106+
- key: "*"
107+
query_per_hour: 1000
68108
redis:
69109
service_name: redis.static
70-
show_limit_quota_header: true
110+
show_limit_quota_header: true
71111
```
72112
113+
114+
73115
## 根据请求头 x-forwarded-for 获取对端IP,进行区别限流
74116
75117
```yaml
76-
rule_name: limit_by_per_ip_from-header-x-forwarded-for
77-
limit_by_per_ip: from-header-x-forwarded-for
78-
limit_keys:
79-
# 精确ip
80-
- key: 1.1.1.1
81-
query_per_day: 10
82-
# ip段,符合这个ip段的ip,每个ip 100qps
83-
- key: 1.1.1.0/24
84-
query_per_day: 100
85-
# 兜底用,即默认每个ip 1000qps
86-
- key: 0.0.0.0/0
87-
query_per_day: 1000
118+
rule_name: default_rule
119+
rule_items:
120+
- limit_by_per_ip: from-header-x-forwarded-for
121+
limit_keys:
122+
# 精确ip
123+
- key: 1.1.1.1
124+
query_per_day: 10
125+
# ip段,符合这个ip段的ip,每个ip 100qpd
126+
- key: 1.1.1.0/24
127+
query_per_day: 100
128+
# 兜底用,即默认每个ip 1000qpd
129+
- key: 0.0.0.0/0
130+
query_per_day: 1000
88131
redis:
89132
service_name: redis.static
90-
show_limit_quota_header: true
133+
show_limit_quota_header: true
91134
```
92135
93-
## 对特定路由或域名开启
136+
137+
138+
## 识别consumer,进行区别限流
94139
95140
```yaml
96-
# 使用_rules_字段进行细粒度规则配置
97-
_rules_:
98-
# 规则一:按路由名称匹配生效
99-
- _match_route_:
100-
- route-a
101-
- route-b
102-
rule_name: limit_rule1
103-
limit_by_per_ip: from-header-x-forwarded-for
104-
limit_keys:
105-
# 精确ip
106-
- key: 1.1.1.1
107-
query_per_day: 10
108-
# ip段,符合这个ip段的ip,每个ip 100qps
109-
- key: 1.1.1.0/24
110-
query_per_day: 100
111-
# 兜底用,即默认每个ip 1000qps
112-
- key: 0.0.0.0/0
113-
query_per_day: 1000
114-
redis:
115-
service_name: redis.static
116-
# 规则二:按域名匹配生效
117-
- _match_domain_:
118-
- "*.example.com"
119-
- test.com
120-
rule_name: limit_rule2
121-
limit_by_param: apikey
122-
limit_keys:
123-
- key: 9a342114-ba8a-11ec-b1bf-00163e1250b5
124-
query_per_second: 10
125-
- key: a6a6d7f2-ba8a-11ec-bec2-00163e1250b5
126-
query_per_minute: 100
127-
redis:
128-
service_name: redis.static
129-
show_limit_quota_header: true
141+
rule_name: default_rule
142+
rule_items:
143+
- limit_by_consumer: ''
144+
limit_keys:
145+
- key: consumer1
146+
query_per_second: 10
147+
- key: consumer2
148+
query_per_hour: 100
149+
- limit_by_per_consumer: ''
150+
limit_keys:
151+
# 正则表达式,匹配以a开头的所有字符串,每个consumer对应的请求10qds
152+
- key: "regexp:^a.*"
153+
query_per_second: 10
154+
# 正则表达式,匹配以b开头的所有字符串,每个consumer对应的请求100qd
155+
- key: "regexp:^b.*"
156+
query_per_minute: 100
157+
# 兜底用,匹配所有请求,每个consumer对应的请求1000qdh
158+
- key: "*"
159+
query_per_hour: 1000
160+
redis:
161+
service_name: redis.static
162+
show_limit_quota_header: true
163+
```
164+
165+
166+
167+
## 识别cookie中的键值对,进行区别限流
168+
169+
```yaml
170+
rule_name: default_rule
171+
rule_items:
172+
- limit_by_cookie: key1
173+
limit_keys:
174+
- key: value1
175+
query_per_minute: 10
176+
- key: value2
177+
query_per_hour: 100
178+
- limit_by_per_cookie: key1
179+
limit_keys:
180+
# 正则表达式,匹配以a开头的所有字符串,每个cookie中的value对应的请求10qds
181+
- key: "regexp:^a.*"
182+
query_per_second: 10
183+
# 正则表达式,匹配以b开头的所有字符串,每个cookie中的value对应的请求100qd
184+
- key: "regexp:^b.*"
185+
query_per_minute: 100
186+
# 兜底用,匹配所有请求,每个cookie中的value对应的请求1000qdh
187+
- key: "*"
188+
query_per_hour: 1000
189+
rejected_code: 200
190+
rejected_msg: '{"code":-1,"msg":"Too many requests"}'
191+
redis:
192+
service_name: redis.static
193+
show_limit_quota_header: true
130194
```
131-
此例 `_match_route_` 中指定的 `route-a` 和 `route-b` 即在创建网关路由时填写的路由名称,当匹配到这两个路由时,将使用此段配置;
132-
此例 `_match_domain_` 中指定的 `*.example.com` 和 `test.com` 用于匹配请求的域名,当发现域名匹配时,将使用此段配置;
133-
配置的匹配生效顺序,将按照 `_rules_` 下规则的排列顺序,匹配第一个规则后生效对应配置,后续规则将被忽略

0 commit comments

Comments
 (0)