因爲要對微服務項目進行流量限制,於是就是學習了下istio的官網教程,下面示例代碼需要改成你自己的服務名就可生效了。
開啓限流
- istio默認是開啓的,爲false表示已經開啓了。
kubectl -n istio-system get cm istio -o jsonpath="{@.data.mesh}" | grep disablePolicyChecks
- 沒有啓動的話,修改一下就可以了
istioctl manifest apply --set values.global.disablePolicyChecks=false
限流的組成部分
限速配置分爲兩個部分
client Side
- QuotaSpec: 定義客戶端應該請求的配額名稱和數量 (指定quota)
- QuotaSpecBinding: 有條件的將QuotaSpec與一項或多項服務相關聯(把quota spec綁定到你想要綁定的服務上去。如果是service:’*’ ,則把所有服務都綁定到QuotaSpec上)
Mixer Side
- quota instance : 定義Mixer如何確定(根據那些字段)配額
- memquota handler : 定義memquota適配器(adapter)配置
- quota rule: 定義何時將配額實例調度到memquota適配器(爲handler指定對應的instance)
- 生產系統中建議使用redisquota,兩種配置是一樣的。
- redis的話,修改redisServerUrl 和rateLimitAlgorithm兩個字段就可用了。
- Redis quota 依賴redis server 來儲存quota values, redis作爲一個共享的數據儲存
代碼示例
- 定義了上面的5個對象:
apiVersion: config.istio.io/v1alpha2
kind: memquota
metadata:
name: handler
namespace: istio-system
spec:
quotas:
- name: requestcount.quota.istio-system
maxAmount: 500
validDuration: 1s
# The first matching override is applied.
# A requestcount instance is checked against override dimensions.
overrides:
# The following override applies to 'reviews' regardless
# of the source.
- dimensions:
destination: reviews
maxAmount: 1
validDuration: 5s
# The following override applies to 'productpage' when
# the source is a specific ip address.
- dimensions:
destination: productpage
source: "10.28.11.20"
maxAmount: 500
validDuration: 1s
# The following override applies to 'productpage' regardless
# of the source.
- dimensions:
destination: productpage
maxAmount: 2
validDuration: 5s
---
apiVersion: config.istio.io/v1alpha2
kind: quota
metadata:
name: requestcount
namespace: istio-system
spec:
dimensions:
source: request.headers["x-forwarded-for"] | "unknown"
destination: destination.labels["app"] | destination.service.name | "unknown"
destinationVersion: destination.labels["version"] | "unknown"
---
apiVersion: config.istio.io/v1alpha2
kind: QuotaSpec
metadata:
name: request-count
namespace: istio-system
spec:
rules:
- quotas:
- charge: 1
quota: requestcount
---
apiVersion: config.istio.io/v1alpha2
kind: QuotaSpecBinding
metadata:
name: request-count
namespace: istio-system
spec:
quotaSpecs:
- name: request-count
namespace: istio-system
services:
- name: productpage
namespace: default
# - service: '*' # Uncomment this to bind *all* services to request-count
---
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: quota
namespace: istio-system
spec:
# quota only applies if you are not logged in.
# match: match(request.headers["cookie"], "user=*") == false
actions:
- handler: handler.memquota
instances:
- requestcount.quota
代碼內容解釋
- memquota裏面4個不同的限速方案:
- 如果下面的沒有匹配的,默認每秒最大500個請求
- 如果目標服務是reviews, 每5s最多1個請求
- 如果目標服務是productpage and source is 10.28.11.20,每秒500請求
- 如果目標服務是productpage ,每5s最多2個請求
代碼運行結果
當部署完後,刷新productpage頁面,會出現RESOURCE_EXHAUSTED:Quota is exhausted for: requestcount.
部署和確認創建結果
服務需要使用VirtualService
kubectl apply -f mixer-ratelimit.yaml
確認quota instance 是否created
這個查詢不到,但是也限速測試也生效了
kubectl get instance requestcountquota -o yaml -n istio-system
kubectl get instance -n istio-system
確認quota rule 是否被創建
kubectl get rule quota -o yaml -n istio-system
kubectl get rule -n istio-system
確認quotaSpec 是否被創建
kubectl get QuotaSpec request-count -o yaml -n istio-system
確認quotaSpecBinding 是否被創建
kubectl -n istio-system get QuotaSpecBinding request-count -o yaml
clean up
上面測試完了後就可以清理掉了
kubectl delete -f mixer-ratelimit-crd.yaml
其它
根據條件限制速率
- 比如根據cookie,確保已經登錄的用戶不受速率限制的影響
kubectl -n istio-system edit rules quota
...
spec:
match: match(request.headers["cookie"], "session=*") == false
actions:
...
對速率限制的理解
通過前面的例子,我們理解了Mixer是如何根據匹配的條件對請求進行速率限制的
- 當最後一個validDuration期限內請求數超過了maxAmount,Mixer 會向Envoy代理返回一個RESOURCE_EXHAUSTED消息,Envoy會像調用者返回HTTP 429
- memquota 使用滑動窗口協議來進行速率限制,可以配置爲ROLLING_WINDOW 或者 FIXED_WINDOW
- FIXED_WINDOW 允許兩倍峯值的指定速率,而滾動窗口則不允許
- ROLLING_WINDOW 精度的提高是以增加Redis資源使用爲代價的
參考質料
- istio官網