一、概要
单机限流可以解决单个服务实例的限流问题,在分布式环境中同一个服务往往存在多个实例,单机限流缺少全局视角无法感知整体系统状态。应用服务网格提供了全局限流能力,支持在ingress网关和sidecar实现全局限流,以下是全局限流相关的说明。
二、全局限流架构
全局限流架构图如下,在Ingress网关和sidecar处均可配置全局限流策略,请求经过数据面代理时,数据面请求外部的全局限流服务判断本次请求放行或拦截。
当前数据面采用Envoy实现,这里的全局限流服务也是遵循Envoy规范的gRPC服务,Envoy社区也提供了一个实现参考,具体可以查看envoyproxy/ratelimit项目。
三、全局限流使用配置说明
应用服务网格封装了Envoy全局限流能力,定义了GlobalRateLimiter K8s CRD,实现Ingress网关和Sidecar全局限流能力;您可以在应用服务网格控制台-》流量管理中心-》全局限流 菜单下管理全局限流策略。
例如要对Ingress网关做全局限流,可以配置:
apiVersion: istio.ctyun.cn/v1beta1
kind: GlobalRateLimiter
metadata:
name: gateway-limit
spec:
workloadSelector:
labels:
istio: ingressgateway
context: GATEWAY
rateLimitService:
clusterName: outbound|8081||ratelimit.istio-system.svc.cluster.local
failureModeDeny: true
timeout: 10s
configs:
- routeConfig:
vhost:
name: ""
# 针对ingressgateway网关,对访问路径/ratelimit限制每秒最多10次,其他路径限制每秒100次
rateLimitConfigs:
- limit:
requests_per_unit: 100
unit: second
- limit:
requests_per_unit: 10
unit: second
match:
- name: :path
exact_match: /ratelimit
match_source: HEADER
GlobalRateLimiter配置说明如下:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
workloadSelector | WorkloadSelector | no | 一组标签key-value对,用于选中需要执行限流的数据面 |
context | PatchContext | no | 数据面生效的场景,支持四种类型: SIDECAR_INBOUND:sidecar入流量方向生效 SIDECAR_OUTBOUND:sidecar出流量方向生效 GATEWAY:网关处生效 ANY:匹配所有 默认为ANY |
RateLimitService | RateLimitService | no | 全局限流服务定义,默认为ratelimit.default.svc.cluster.local服务,8081端口,超时时间为10秒 |
Configs | []*GlobalConfig | no | 限流配置 |
RateLimitService定义:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
ClusterName | string | no | istio中的全局限流服务名称,如outbound|8081||ratelimit.default.svc.cluster.local |
FailureModeDeny | bool | no | 调用全局限流服务失败时的行为控制,设置为true时如果调用全局限流服务失败,则请求会被拦截;默认为false |
Timeout | string | no | 调用全局限流服务的超时时间,默认为10s |
GlobalConfig定义:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
RouteConfig | RouteConfigurationMatch | no | 对应EnvoyFilter中的configPatches.match.routeConfiguration,用于实现virtual host和route匹配 |
RateLimitConfigs | []*GlobalRateLimit | no | 匹配到虚拟主机和路由后执行的限流策略 |
RouteConfigurationMatch定义:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
Vhost | RouteConfigurationMatch_VirtualHostMatch | no | istio中的全局限流服务名称,如outbound|8081||ratelimit.default.svc.cluster.local |
RouteConfigurationMatch_VirtualHostMatch定义:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
Name | string | no | 匹配的虚拟主机名称 |
Route | RouteConfigurationMatch_RouteMatch | no | 路由匹配条件 |
RouteConfigurationMatch_RouteMatch定义:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
Name | string | no | 匹配的路由名称 |
GlobalRateLimit定义:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
Limit | GlobalRateLimitConfig | no | 限流值配置 |
Match | []*GlobalRateLimitMatcher | no | 限流匹配条件配置,多个条件之间是AND关系 |
GlobalRateLimitConfig定义:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
RequestsPerUnit | uint32 | no | 限流值 |
Unit | string | no | 限流时间单位,用于定义限流统计时间窗口,如second,minute |
GlobalRateLimitMatcher定义:
字段 | 类型 | 必选 | 说明 |
---|---|---|---|
Name | string | no | 匹配字段名称 |
RegexMatch | string | no | 正则匹配,对头部和query匹配生效 |
ContainsMatch | string | no | 包含匹配,对头部和query匹配生效 |
ExactMatch | string | no | 精确匹配,对头部、query和IP匹配生效 |
PrefixMatch | string | no | 前缀匹配,对头部和query匹配生效 |
SuffixMatch | string | no | 后缀匹配,对头部和query匹配生效 |
PresentMatch | bool | no | 存在匹配,仅对头部匹配生效,如果为true,目标头部存在则匹配 |
InvertMatch | bool | no | 反向匹配,基于前面的匹配结果取反作为最终匹配的结果 |
MatchSource | string | no | 匹配数据源,支持HEADER,QUERY、IP |
注意任何一个匹配规则只能选择一种匹配策略。
四、全局限流体验
部署全局限流服务
我们才有envoy官方实现的全局限流服务envoyproxy/ratelimit,使用configmap管理限流服务配置,同时还依赖redis,具体配置如下
apiVersion: v1
kind: Service
metadata:
name: redis
labels:
app: redis
spec:
ports:
- name: redis
port: 6379
selector:
app: redis
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- image: registry-huadong1.crs-internal.ctyun.cn/mstools/redis:alpine
imagePullPolicy: IfNotPresent
name: redis
ports:
- name: redis
containerPort: 6379
restartPolicy: Always
serviceAccountName: ""
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ratelimit-config
data:
config.yaml: |
domain: gateway-ratelimit
descriptors:
- key: PATH
value: "/gateway"
rate_limit:
unit: minute
requests_per_unit: 2
---
apiVersion: v1
kind: Service
metadata:
name: ratelimit
labels:
app: ratelimit
spec:
ports:
- name: http-port
port: 8080
targetPort: 8080
protocol: TCP
- name: grpc-port
port: 8081
targetPort: 8081
protocol: TCP
- name: http-debug
port: 6070
targetPort: 6070
protocol: TCP
selector:
app: ratelimit
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ratelimit
spec:
replicas: 1
selector:
matchLabels:
app: ratelimit
strategy:
type: Recreate
template:
metadata:
labels:
app: ratelimit
spec:
containers:
- image: registry-huadong1.crs-internal.ctyun.cn/mstools/envoyratelimit
imagePullPolicy: IfNotPresent
name: ratelimit
command: ["/bin/ratelimit"]
env:
- name: LOG_LEVEL
value: debug
- name: REDIS_SOCKET_TYPE
value: tcp
- name: REDIS_URL
value: redis:6379
- name: USE_STATSD
value: "false"
- name: RUNTIME_ROOT
value: /data
- name: RUNTIME_SUBDIRECTORY
value: ratelimit
- name: RUNTIME_WATCH_ROOT
value: "false"
- name: RUNTIME_IGNOREDOTFILES
value: "true"
- name: HOST
value: "::"
- name: GRPC_HOST
value: "::"
ports:
- containerPort: 8080
- containerPort: 8081
- containerPort: 6070
volumeMounts:
- name: config-volume
mountPath: /data/ratelimit/config
volumes:
- name: config-volume
configMap:
name: ratelimit-config
部署业务服务
部署nginx作为业务服务,请基于当前注入策略配置命名空间和pod的标签,确保nginx pod注入sidecar,如下
apiVersion: v1
kind: Service
metadata:
name: ngmtls
labels:
app: ngmtls
service: ngmtls
spec:
ports:
- port: 8080
targetPort: 80
name: http
selector:
app: ngmtls
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ngmtls
labels:
app: ngmtls
spec:
replicas: 1
selector:
matchLabels:
app: ngmtls
name: ngmtls
template:
metadata:
labels:
app: ngmtls
name: ngmtls
source: CCSE
spec:
containers:
- name: ngmtls
image: registry-huadong1.crs-internal.ctyun.cn/mstools/nginx:1.26-alpine-perl-mtls
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
- containerPort: 443
创建ingress网关
创建Ingress网关并绑定ELB,系统自动创建istio Gateway资源,如下
配置网关VirtualService
在VirtualService中指定路由名称为ngroute,匹配路径/index.html,转发到我们部署好的nginx服务
通过浏览器访问/index.html可以看到返回正常的页面
网关VirtualHost限流
在网关所属的命名空间创建全局限流策略(通过workloadSelector选中网关工作负载),匹配网关的vhost(名称为"")针对/index.html的访问限流每秒2次
apiVersion: istio.ctyun.cn/v1beta1
kind: GlobalRateLimiter
metadata:
name: gateway-limit
spec:
workloadSelector:
labels:
gateway-unique-name: "cce-primary.csmgw.ingressgateway.gw1112"
context: GATEWAY
rateLimitService:
clusterName: outbound|8081||ratelimit.ratelimit.svc.cluster.local
failureModeDeny: true
timeout: 10s
configs:
- routeConfig:
vhost:
name: ""
# 针对ingressgateway网关,对访问路径/index.html限制每秒最多2次,其他路径限制每秒100次
rateLimitConfigs:
- limit:
requests_per_unit: 100
unit: second
- limit:
requests_per_unit: 2
unit: second
match:
- name: :path
exact_match: /index.html
match_source: HEADER
创建完成后,打开配置编辑页面可以看到Status字段增加了限流配置,envoyproxy/ratelimit服务可以读取这些配置并执行对应的限流策略;
将这些配置拷贝到全局限流服务的configmap并重启全局限流服务。
连续请求/index.html页面,请求到达限流阈值后可以看到后端返回了HTTP 429错误
网关Route限流
以下配置匹配网关的vhost和route,执行指定的限流策略,如我们在网关配置的路由为ngroute,可以配置匹配该路由的限流策略,如下
apiVersion: istio.ctyun.cn/v1beta1
kind: GlobalRateLimiter
metadata:
name: gateway-limit
spec:
workloadSelector:
labels:
gateway-unique-name: "cce-primary.csmgw.ingressgateway.gw1112"
context: GATEWAY
rateLimitService:
clusterName: outbound|8081||ratelimit.ratelimit.svc.cluster.local
failureModeDeny: true
timeout: 10s
configs:
- routeConfig:
vhost:
name: ""
route:
name: "ngroute" # 该名称需要和virtualservice下的route name一致
# 针对default虚拟服务路由配置限流规则,对访问路径/index.html限制每秒最多2次,其他路径限制每秒100次
rateLimitConfigs:
- limit:
requests_per_unit: 100
unit: second
- limit:
requests_per_unit: 2
unit: second
match:
- name: :path
exact_match: /index.html
match_source: HEADER
Sidecar VirtualHost限流
全局限流策略也支持在Sidecar生效,只需要通过workloadSelector选中sidecar所在的工作负载,指定sidecar context(SIDECAR_INBOUND或者SIDECAR_OUTBOUND,一般配置为SIDECAR_INBOUND,即被调服务入口处限流)。
Sidecar vhost限流配置策略如下
apiVersion: istio.ctyun.cn/v1beta1
kind: GlobalRateLimiter
metadata:
name: ng-limit
spec:
workloadSelector:
labels:
app: "ngmtls"
context: SIDECAR_INBOUND
rateLimitService:
clusterName: outbound|8081||ratelimit.ratelimit.svc.cluster.local
failureModeDeny: true
timeout: 10s
configs:
- routeConfig:
vhost:
name: inbound|http|8080
# 对访问路径/index.html限制每秒最多2次,其他路径限制每秒100次
rateLimitConfigs:
- limit:
requests_per_unit: 100
unit: second
- limit:
requests_per_unit: 2
unit: second
match:
- name: :path
exact_match: /index.html
match_source: HEADER
Sidecar Route限流
相比于vhost限流,增加了路由名称的匹配
apiVersion: istio.ctyun.cn/v1beta1
kind: GlobalRateLimiter
metadata:
name: ng-limit
spec:
workloadSelector:
labels:
app: "ngmtls"
context: SIDECAR_INBOUND
rateLimitService:
clusterName: outbound|8081||ratelimit.ratelimit.svc.cluster.local
failureModeDeny: true
timeout: 10s
configs:
- routeConfig:
vhost:
name: inbound|http|8080
route:
name: default
# 对访问路径/index.html限制每秒最多2次,其他路径限制每秒100次
rateLimitConfigs:
- limit:
requests_per_unit: 100
unit: second
- limit:
requests_per_unit: 2
unit: second
match:
- name: :path
exact_match: /index.html
match_source: HEADER