启用速率限制
这部分内容将向您展示如何使用 Istio 去动态限制服务间的流量。
开始之前
依照安装指引在 Kubernetes 中 安装 Istio。
部署 Bookinfo 示例应用。
Bookinfo 部署了 3 个版本的
reviews
服务:- 版本 v1 不会调用
ratings
服务。 - 版本 v2 调用
ratings
服务,且为每个评价显示 1 到 5 颗黑色星星。 - 版本 v3 调用
ratings
服务,且为每个评价显示 1 到 5 颗红色星星。
您需要指定其中一个版本为默认路由。否则,当您向
reviews
服务发送请求时,Istio 会随机路由到其中一个服务上,表现为有时显示星星,有时不会。- 版本 v1 不会调用
将所有服务的默认版本设置为 v1。
$ kubectl apply -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@
速率限制
在这部分,Istio 将以客户端的 IP 地址限制 productpage
的流量。
您将会使用 X-Forwarded-For
请求头作为客户端 IP 地址。也将会针对已登录的用户应用有条件的速率限制。
方便起见,配置 memory quota(memquota
) 适配器用以启用速率限制。
如果在生产系统使用的是 Redis,那么启用 Redis quota
(redisquota
) 适配器。memquota
与 redisquota
适配器都支持 quota template,
所以他们的配置是一样的。
速率限制的配置分为两部分。
- 客户端
QuotaSpec
定义 quota 名称与客户端请求的数量。QuotaSpecBinding
条件化的关联QuotaSpec
到一个或多个服务。
- Mixer 端
quota instance
定义 quota 的维度。memquota handler
定义memquota
适配器的配置。quota rule
定义 quota 实例何时分发到memquota
适配器。
执行如下命令使用
memquota
开启速率限制:$ kubectl apply -f @samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml@
memquota
处理器定义了 4 个不同的速率限制规则。默认如果没有匹配到优先规则,是500
个请求量每秒 (1s
)。 我们也定义了三个优先规则:- 第一种是
1
个请求量 (maxAmount
字段) 每5s
(validDuration
字段),如果目标服务
是reviews
。 - 第二种是
500
个请求量每1s
,如果目标服务
是productpage
且来源于10.28.11.20
。 - 第三种是
2
个请求量每5s
,如果目标服务
是productpage
。
当一个请求被处理时,第一个被匹配到的优先规则会被触发(从上到下)。
或者
执行如下命令使用
redisquota
开启流量限制:$ kubectl apply -f @samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml@
注意: 替换您的配置中 rate_limit_algorithm, redis_server_url 的值.
redisquota
处理器定义了 4 个不同的速率限制规则。默认如果没有匹配到优先规则,是500
个请求量每秒 (1s
)。 使用了ROLLING_WINDOW
算法作为 quota 检查且为之定义了 500ms 的bucketDuration
。我们也定义了三个优先规则:- 第一种是
1
个请求量 (maxAmount
字段),如果目标服务
是reviews
。 - 第二种是
500
,如果目标服务
是productpage
且来源于10.28.11.20
。 - 第三种是
2
,如果目标服务
是productpage
。
当一个请求被处理时,第一个被匹配到的优先规则会被触发(从上到下)。
- 客户端
确认
quota 实例
已被创建:$ kubectl -n istio-system get instance requestcountquota -o yaml
quota
模板通过memquota
或redisquota
定义了三个维度以匹配特定的属性的方式设置优先规则。目标服务
会被设置为destination.labels ["app"]
,destination.service.host
,或"unknown"
中的第一个非空值。 表达式的更多信息,见 Expression Language。确认
quota rule
已被创建:$ kubectl -n istio-system get rule quota -o yaml
rule
告诉 Mixer 去调用memquota
或redisquota
处理器(上面创建的)且传递requestcountquota
构造的对象(也是上面创建的)。 这里将quota
模板与memquota
或redisquota
处理器的维度一一对应。确认
QuotaSpec
已被创建:$ kubectl -n istio-system get QuotaSpec request-count -o yaml
QuotaSpec
用值1
定义了您上面创建的requestcountquota
。确认
QuotaSpecBinding
已被创建:$ kubectl -n istio-system get QuotaSpecBinding request-count -o yaml
QuotaSpecBinding
绑定了您上面创建的QuotaSpec
与您想要生效的服务。productpage
显式的绑定了request-count
, 注意您必须定义与QuotaSpecBinding
不同的命名空间。 如果最后一行注释被打开,service: '*'
将绑定所有服务到QuotaSpec
使得首个 entry 是冗余的。在浏览器上刷新 product 页面。
request-count
quota 应用于productpage
且只允许 2 个请求量每 5 秒。如果您持续刷新页面将会看到RESOURCE_EXHAUSTED:Quota is exhausted for: requestcount
。
条件化的速率限制
在上面的例子我们为每个客户端 IP 地址的 productpage
限制了 2 rps
。
考虑这样一个场景,如果您想要对已登录的用户放开速率限制。在 bookinfo
的例子中,我们用 cookie session=<sessionid>
去指代一个已登录用户。
在现实场景中您可能会用 jwt
token 去实现这个目的。
您可以添加基于 cookie
的匹配条件更新 quota rule
。
$ kubectl -n istio-system edit rules quota
...
spec:
match: match(request.headers["cookie"], "session=*") == false
actions:
...
memquota
或 redisquota
适配器现在只有请求中存在 session=<sessionid>
cookie 才会被分发。
这可以确保已登录的用户不会受限于这个 quota。
确认速率限制没有生效于已登录的用户。
以
jason
身份登录且反复刷新productpage
页面。现在这样做不会出现任何问题。确认速率限制 生效 于未登录的用户。
退出登录且反复刷新
productpage
页面。 您将会再次看到RESOURCE_EXHAUSTED:Quota is exhausted for: requestcount
。
理解原理
在先前的例子中你已经看到了 Mixer 是怎么通过匹配特定的条件对请求应用速率限制的。
每个具名的 quota 实例比如 requestcount
会提供一组计数器。
这组计数器用所有 quota 维度的笛卡尔积来定义。如果最后一个有效期
内的请求数超出 maxAmount
,
Mixer 返回一个 RESOURCE_EXHAUSTED
消息给 Envoy 代理,然后 Envoy 返回状态码 HTTP 429
给调用者。
memquota
适配器使用一个亚秒级的滑动窗口来执行速率限制。
redisquota
适配器可以配置使用 ROLLING_WINDOW
或 FIXED_WINDOW
算法之一来执行速率限制。
适配器配置内的 maxAmount
为所有关联到 quota 实例的计数器设置了默认限制。这个默认限制应用在其他优先规则没有被匹配到的时候。
memquota/redisquota
适配器会选择第一个与请求相匹配的优先规则。一个优先规则不能指明所有的 quota 维度。
在这个例子里,0.2 qps 的规则被选择到通过只匹配了四分之三的 quota 维度。
如果您想要策略在给定的命名空间上执行而非整个 Istio 网格,可以把前面所有出现的 istio-system
替换为您想要的命名空间。
清理
如果使用
memquota
,移除memquota
速率限制配置:$ kubectl delete -f @samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml@
如果您使用 Istio 1.1.2 或更低:
$ kubectl delete -f @samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml@
或
如果使用
redisquota
,移除redisquota
速率限制配置:$ kubectl delete -f @samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml@
移除应用路由规则:
$ kubectl delete -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@
如果您不准备探索更多的任务,参考 Bookinfo cleanup 关闭整个应用。