Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cluster key rate limit #1002

Merged
merged 5 commits into from
Jun 12, 2024
Merged

Conversation

hanxiantao
Copy link
Collaborator

@hanxiantao hanxiantao commented May 26, 2024

Ⅰ. Describe what this PR did

cluster key rate limit

Ⅱ. Does this pull request fix one issue?

fixes #851

Ⅲ. Why don't you add test cases (unit test/integration test)?

Ⅳ. Describe how to verify it

1)、识别请求参数 apikey,进行区别限流

wasmplugin.yam:

apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
  name: test
  namespace: higress-system
spec:
  defaultConfig:
    rule_name: default_limit_by_param_apikey
    limit_by_param: apikey
    limit_keys:
    - key: 9a342114-ba8a-11ec-b1bf-00163e1250b5
      query_per_minute: 10
    - key: a6a6d7f2-ba8a-11ec-bec2-00163e1250b5
      query_per_hour: 100
    redis:
      service_name: redis
      service_host: redis
      service_port: 80
      service_source: ip
    show_limit_quota_header: true
  url: oci://registry.cn-hangzhou.aliyuncs.com/wasm-plugin/wasm-plugin:0.0.51
  imagePullSecret: aliyun

1)根据第一个apikey进行限流

一分钟内请求三次:

curl -kvv -X GET 'http://localhost:8082/test?apikey=9a342114-ba8a-11ec-b1bf-00163e1250b5' \
-H 'Host: www.test.com'

根据请求参数限流

响应头中x-ratelimit-limit为10(限制的总请求数),x-ratelimit-remaining为7(剩余还可以发送的请求数)

触发限流后:

根据请求参数限流触发限流后

2)根据第二个apikey限流

请求三次:

curl -kvv -X GET 'http://localhost:8082/test?apikey=a6a6d7f2-ba8a-11ec-bec2-00163e1250b5' \
-H 'Host: www.test.com'

根据请求参数限流2
redis中数据:

根据请求参数限流 redis数据

2)、识别请求头 x-ca-key,进行区别限流

wasmplugin.yam:

apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
  name: test
  namespace: higress-system
spec:
  defaultConfig:
    rule_name: default_limit_by_param_x-ca-key
    limit_by_header: x-ca-key
    limit_keys:
    - key: 102234
      query_per_minute: 10
    - key: 308239
      query_per_hour: 100
    redis:
      service_name: redis
      service_host: redis
      service_port: 80
      service_source: ip
    show_limit_quota_header: true  
  url: oci://registry.cn-hangzhou.aliyuncs.com/wasm-plugin/wasm-plugin:0.0.51
  imagePullSecret: aliyun

1)根据第一个x-ca-key限流

一分钟内请求三次:

curl -kvv -X GET 'http://localhost:8082/test' \
-H 'Host: www.test.com' \
-H 'x-ca-key: 102234'

根据请求头限流

响应头中x-ratelimit-limit为10(限制的总请求数),x-ratelimit-remaining为7(剩余还可以发送的请求数)

触发限流后:

根据请求头触发限流后

3)、根据请求头 x-forwarded-for 获取对端IP,进行区别限流

apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
  name: test
  namespace: higress-system
spec:
  defaultConfig:
    limit_by_per_ip: from-header-x-forwarded-for
    rule_name: limit_by_per_ip
    redis:
      service_name: redis
      service_host: redis
      service_port: 80
      service_source: ip
    show_limit_quota_header: true
    limit_keys:
      - key: 1.1.1.1
        query_per_day: 10
      - key: 1.1.1.0/24
        query_per_day: 100
      - key: 0.0.0.0/0
        query_per_day: 1000
  url: oci://registry.cn-hangzhou.aliyuncs.com/wasm-plugin/wasm-plugin:0.0.51
  imagePullSecret: aliyun

1)命中1.1.1.1

请求三次:

curl -kvv -X GET 'http://localhost:8082/test' \
-H 'Host: www.test.com' \
-H 'x-forwarded-for: 1.1.1.1'

根据客户端ip限流

2)命中1.1.1.0/24

请求四次:

curl -kvv -X GET 'http://localhost:8082/test' \
-H 'Host: www.test.com' \
-H 'x-forwarded-for: 1.1.1.2'

根据客户端ip限流2

redis中数据(key名称包含从x-forwarded-for中获取的IP 1.1.1.2):

根据客户端ip限流2 redis中数据

Ⅴ. Special notes for reviews

@hanxiantao hanxiantao changed the title feat: cluster rate limit by client ip feat: cluster key rate limit Jun 1, 2024
@hanxiantao hanxiantao requested a review from johnlanni June 1, 2024 07:59
@hanxiantao hanxiantao force-pushed the key-cluster-rate-limit branch 2 times, most recently from 148a8cb to 83cb0ac Compare June 2, 2024 05:27
@hanxiantao
Copy link
Collaborator Author

@johnlanni 代码已调整,麻烦再帮忙review下


| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| -------------- | ------ | ---- | ------ | ----------------------------------------------- |
| service_source | string | 必填 | - | 类型为固定ip或者DNS,输入redis服务的注册来源 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/alibaba/higress/blob/main/plugins/wasm-go/extensions/ai-cache/main.go

麻烦参考下这里的redis配置解析和client初始化逻辑,使用FQDNCluster,简化用户的配置方式

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/alibaba/higress/blob/main/plugins/wasm-go/extensions/ai-cache/main.go

麻烦参考下这里的redis配置解析和client初始化逻辑,使用FQDNCluster,简化用户的配置方式

好的,这里我再调整下

| service_name | string | 必填 | - | 输入redis服务的注册名称 |
| service_port | int | 必填 | - | 输入redis服务的服务端口 |
| service_host | string | 必填 | - | 当类型为固定ip时必须填写,输入redis服务的主机名 |
| service_domain | string | 必填 | - | 当类型为DNS时必须填写,输入redis服务的domain |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

其实redis 不需要设置domain

rule_name: limit_by_per_ip_from-header-x-forwarded-for
limit_by_per_ip: from-header-x-forwarded-for
limit_keys:
# 精确ip
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里有一段空白符

| 配置项 | 类型 | 必填 | 默认值 | 说明 |
| ----------------------- | ------ | ---- | ------ | ---- |
| rule_name | string || - | 限流规则名称,根据限流规则名称和限流的客户端IP段来拼装redis key |
| limit_by_header | string | 否,`limit_by_header`,`limit_by_param`,`limit_by_per_ip` 中选填一项 | - | 配置获取限流键值的来源 http 请求头名称 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以考虑加一个 limit_by_consumer, 现在通过 x-mse-consumer 这个request header可以取出 consumer 的名字

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以考虑加一个 limit_by_consumer, 现在通过 x-mse-consumer 这个request header可以取出 consumer 的名字

这个应该是要配合认证的插件一起使用对吧

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,如果用户开了 key-auth 等认证插件,就可以配合基于 consumer 做流控了,在openapi场景下挺有用的

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,如果用户开了 key-auth 等认证插件,就可以配合基于 consumer 做流控了,在openapi场景下挺有用的

好的

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以考虑加一个 limit_by_consumer, 现在通过 x-mse-consumer 这个request header可以取出 consumer 的名字

这个目前根据请求头限流的应该可以覆盖这个场景了,limit_by_header直接配置成x-mse-consumer就可以了,如果单独再实现一个limit_by_consumer会有点奇怪,在limit_by_header使用文档中添加下对x-mse-consumer的使用场景的说明会更好些

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

limit_by_consumer 更好一些,目前通过header传递consumer信息的方式后续可能会调整,有了limit_by_consumer,用户就不感知这个调整

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

limit_by_consumer 更好一些,目前通过header传递consumer信息的方式后续可能会调整,有了limit_by_consumer,用户就不感知这个调整

好的,limit_by_consumer实现的时候也会和limit_by_per_header、limit_by_per_param一样支持配置一个正则表达式

| show_limit_quota_header | bool || false | 响应头中是否显示`X-RateLimit-Limit`(限制的总请求数)和`X-RateLimit-Remaining`(剩余还可以发送的请求数) |
| rejected_code | int || 429 | 请求被限流时,返回的HTTP状态码 |
| rejected_msg | string || Too many requests | 请求被限流时,返回的响应体 |
| redis | object || - | redis相关配置 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以进一步扩展一下,类似 per ip 这种,用于不可枚举场景的限流:
limit_by_per_header
limit_by_per_param

key 可以支持配置一个正则表达式,符合正则匹配的进行限制

Copy link
Collaborator Author

@hanxiantao hanxiantao Jun 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以进一步扩展一下,类似 per ip 这种,用于不可枚举场景的限流: limit_by_per_header limit_by_per_param

key 可以支持配置一个正则表达式,符合正则匹配的进行限制

key以regexp-开头的标识根据正则表达式匹配,示例如下:

rule_name: limit_by_param_x-ca-key
limit_by_header: x-ca-key
limit_keys:
- key: 102234
  query_per_second: 10
- key: regexp-\d+
  query_per_hour: 10

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regexp:\d+

用冒号分隔看上去自然一些

}

// 构建redis限流key和参数
limitKey := fmt.Sprintf(ClusterRateLimitFormat, config.ruleName, key)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redis key add ruleType

Copy link
Collaborator

@johnlanni johnlanni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@johnlanni johnlanni merged commit 12cc44b into alibaba:main Jun 12, 2024
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

基于ip的限流插件
2 participants