一、概要
單機限流可以解決單個服務實例的限流問題,在分布式環境中同一個服務往往存在多個實例,單機限流缺少全局視角無法感知整體系統狀態。應用服務網格提供了全局限流能力,支持在ingress網關和sidecar實現全局限流,以下是全局限流相關的說明。
二、全局限流架構
全局限流架構圖如下,在Ingress網關和sidecar處均可配置全局限流策略,請求經過數據面代理時,數據面請求外部的全局限流服務判斷本次請求放行或攔截。
當前數據面采用Envoy實現,這里的全局限流服務也是遵循Envoy規范的gRPC服務,Envoy社區也提供了一個實現參考,具體可以查看envoyproxy/ratelimit項目。
三、全局限流使用配置說明
應用服務網格封裝了Envoy全局限流能力,定義了GlobalRateLimiter K8s CRD,實現Ingress網關和Sidecar全局限流能力;您可以在應用服務網格控制臺-》流量管理中心-》全局限流 菜單下管理全局限流策略。
例如要對Ingress網關做全局限流,可以配置:
apiVersion: istio.daliqc.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.daliqc.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.daliqc.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.daliqc.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.daliqc.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.daliqc.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.daliqc.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.daliqc.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