使用 Istio 可以很方便地实现速率限制。本文介绍了速率限制的使用场景,使用 memquota\redisquota adapter 实现速率限制的方法,通过配置 rule 实现有条件的速率限制,以及速率限制的原理。

使用场景

在许多场景下都需要对服务进行速率限制。

一种常见的场景是防止来自外部服务的过度调用(如爬虫)。

另一种常见的场景是调用某些收费的外部服务,但是提供了免费配额,可以使用速率限制确保只使用免费的配额。

2  环境准备

  • 在 Kubernetes 集群上部署 Istio

  • 部署 Bookinfo 示例应用

  • 配置 Bookinfo 应用各个微服务的 destinationrule 和 virtualservice

使用 Istio 实现速率限制

1. 创建 memquota 或 redisquota 类型的 handler

一个请求到达某个服务时,一般会发生两次对 Mixer 的调用,一次是前置检查,一次是遥测报告。每一次调用,Mixer 都需要调用一个或多个适配器。因此需要定义处理速率限制的 handler,可以在 memquota 和 redisquota 这两种类型的 handler 中选择一种:

上面的 memquota handler 定义了三种不同的速率限制模式:

  • 如果没有 override 能够匹配,默认每秒限制 500 次请求;

  • 如果请求的 destination 是 reviews,每 5 秒限制 1 次请求;

  • 如果请求的 destination 是 productpage,每 5 秒限制 1 次请求。

然后创建 memquota handler:

上面使用的是 memquota handler,memquota handler 绑定在 Mixer 进程上,没有持久化,无 HA 能力,因此并不适合生产使用。可以用 redisquota handler 替代 memquota handler 实现持久化:

上面定义了一个 redisquota handler,定义的三种速率限制模式和上文的 memquota handler相同。

其中 rateLimitAlgorithm 字段可以选择 ROLLING_WINDOW 或者 FIXED_WINDOW,两种算法的介绍见下文“速率限制的原理”一节。

然后创建该 redisquota handler:

 2. 创建 quota template 的 instance

不同的适配器需要不同的数据块作为输入来进行处理。例如日志适配器需要日志输入,指标适配器需要指标输入,认证适配器需要凭据输入。适配器在请求时消费的数据是由 Mixer 的 template 来描述的,通过 quota template 可以定义 memquota\redisquota handler 需要的 dimension 数据。

编辑 quota_instance.yaml 内容如下:

上面的 quota template 定义了四种可以被 memquota\redisquota 使用的 dimension,可以 override 匹配到某些属性的请求。比如 destination 会被置为 destination.labels["app"], destination.service.host 和 "unknown" 中第一个不为空的值。

然后执行如下命令创建 quota template 的 instance:

3. 创建 quota rule 

Rule 负责通知 Mixer,哪个 instance 应该在什么时候发送给哪个 handler。

编辑 quota_rule.yaml 内容如下:

上面这条 rule 告诉 Mixer 使用上面创建的 handler.memquota\handler.redisquota handler,并将上面创建的 requestcount.quota instance 构建的对象传递给该 handler。

然后执行如下命令创建上述 rule:

4. 创建 QuotaSpec

QuotaSpec 对象用于定义每次请求消费的 quota instance 的数量。

编辑 quota_spec.yaml 内容如下:

在上面的 QuotaSpec 中,我们定义每次请求消费 1 个 quota instance。

然后执行如下命令创建上述 QuotaSpec:

5. 创建 QuotaSpecBinding

QuotaSpecBinding 对象用于将上面创建的 QuotaSpec 绑定到需要应用限流的服务上。通过给不同的服务绑定不同的 QuotaSpec,可以实现对于调用代价较高的服务,每个请求消费较多的 quota instance。

编辑 quota_spec_binding.yaml 内容如下:

上面的 QuotaSpecBinding 将 productpage 绑定到名为 request-count 的 QuotaSpec 上。需要注意的是,如果服务的 namespace 和 QuotaSpecBinding 不同,需要指定 namespace。

然后执行如下命令创建上述 QuotaSpec:

6. 在浏览器中刷新 productpage 页面

因为限制了 productpage 只允许每 5 秒 2 个请求,所以如果持续刷新页面,会看到如下的 RESOURCE_EXHAUSTED:Quota is exhausted for: requestcount。

有条件的速率限制

上面只使用了 dimensions 来定义速率限制的条件,还可以在 rule 中使用任意属性来定义规则。

例如,在某些场景下,我们不需要对已经登录的用户进行速率限制。在 bookinfo 示例中,我们通过设置 cookie user=<username> 来识别已经登录的用户。

修改 quota_rule.yaml 内容如下:

然后执行如下命令修改 rule:

修改后的 rule 使得当且仅当 user=<username> cookie 为空时才应用 memquota 或者 redisquota 适配器,从而保证了已登录的用户免受速率限制。

以“kokokobe”用户登录,并持续刷新页面,每次都可以刷出下图所示页面。

登出之后持续刷新页面,会再一次看到下图所示的 RESOURCE_EXHAUSTED:Quota is exhausted for: requestcount。

5 速率限制的原理

速率限制有 Token Bucket、Fixed Window、Rolling Window 等常见的算法实现。

Token Bucket 算法每经过固定的时间间隔会产生一个 token,如果此时 bucket 没有满,则产生的 token 可以被放入 bucket 中。当请求到来时,如果此时 bucket 中有足够多的 token,则可以同时取走多个;如果此时 bucket 中 token 不够,则拒绝服务。

Fixed Window 算法每个时间间隔对应一个计数器,每当有请求到来,如果此时计数器未达到配额的限定值,则计数器加 1,否则拒绝服务。当进入下一个时间间隔时,计数器失效被重置。该算法的缺点在于不能保证在任意的时间间隔内,速率都被限制在配额以下。即如果请求集中在计数器失效的时间点附近,则在该时间点附近的时间间隔内,速率最大能达到配额的两倍。

Rolling Window 算法通过对上一个时间间隔请求数和当前时间间隔已处理的请求数进行加权,实现了对任意时间间隔的速率的估算。

图片来自

https://blog.cloudflare.com/counting-things-a-lot-of-different-things/

如上图所示,在上一分钟内处理了 42 个请求,当前这一分钟已经过去了 15 秒,处理了 18 个请求,则当前这一分钟的速率可以估算为:

rate = 42 * ((60-15)/60) + 18 = 42 * 0.75 + 18 = 49.5

如果使用 memquota adapter,默认使用亚秒级分辨率的 rolling window 实现速率限制。

如果使用 redisquota adapter,可以配置使用 Rolling Window 算法或者 Fixed Window 算法。

如果在该时间间隔内的请求数超过了 maxAmount,Mixer 会返回 RESOURCE_EXHAUSTED 信息给 Envoy,Envoy 再返回 HTTP 429 StatusTooManyRequests 给调用者。

idou老师教你学Istio:如何用 Istio 实现速率限制的更多相关文章

  1. idou老师教你学Istio11 : 如何用Istio实现流量熔断

    在之前的最佳实践中,已经带大家通过一系列的实践任务领略了Istio的无穷魅力.今天,将向大家介绍如何用Istio实现流量熔断. 熔断机制是创建弹性微服务应用程序的重要模式.熔断可以帮助您自由控制故障影 ...

  2. idou老师教你学Istio06: 如何用istio实现流量迁移

    流量迁移是流量管理的一个重要功能.istio提供的流量管理功能将流量从基础设施扩展中解耦,支持动态请求路由,故障注入.超时重试.熔断和流量迁移等.流量迁移的主要目的是将流量从微服务的某一版本的逐步迁移 ...

  3. idou老师教你学Istio05: 如何用Isito实现智能路由配置

    要介绍istio请求路由,我们不由得先从pilot 和 envoy开始谈起. 在服务网格中,Pilot管理和配置所有的envoy实例.在pilot中,你几乎可以配置所有的关于流量导向规则及其他故障恢复 ...

  4. idou老师教你学Istio 07: 如何用istio实现请求超时管理

    在前面的文章中,大家都已经熟悉了Istio的故障注入和流量迁移.这两个方面的功能都是Istio流量治理的一部分.今天将继续带大家了解Istio的另一项功能,关于请求超时的管理. 首先我们可以通过一个简 ...

  5. idou老师教你学Istio 24:如何在Istio使用Prometheus进行监控

    使用Prometheus进行监控是Istio提供的监控能力之一.Istio提供丰富的监控能力,为网格中的服务收集遥测数据.Mixer是负责提供策略控制和遥测收集的Istio组件. Istio通过Mix ...

  6. idou老师教你学Istio 09: 如何用Istio实现K8S Ingress流量管理

    前言 在Istio的世界里,如果想把外部的请求流量引入网格,你需要认识并会学会配置Istio Ingress Gateway 什么是Ingress Gateway 由于Kubernetes  Ingr ...

  7. idou老师教你学Istio :如何用istio实现监控和日志采集

    大家都知道istio可以帮助我们实现灰度发布.流量监控.流量治理等功能.每一个功能都帮助我们在不同场景中实现不同的业务.那Istio是如何帮助我们实现监控和日志采集的呢? 这里我们依然以Bookinf ...

  8. idou老师教你学Istio: 如何用Istio实现K8S Egress流量管理

    本文主要介绍在使用Istio时如何访问集群外服务,即对出口流量的管理. 默认安装的Istio是不能直接对集群外部服务进行访问的,如果需要将外部服务暴露给 Istio 集群中的客户端,目前有两种方案: ...

  9. idou老师教你学Istio 25:如何用istio实现监控和日志采集

    大家都知道istio可以帮助我们实现灰度发布.流量监控.流量治理等功能.每一个功能都帮助我们在不同场景中实现不同的业务.那Istio是如何帮助我们实现监控和日志采集的呢? 这里我们依然以Bookinf ...

随机推荐

  1. python3: 字符串和文本(3)

    11. 删除字符串中不需要的字符  strip() 方法能用于删除开始或结尾的字符: lstrip() 和 rstrip() 分别从左和从右执行删除操作 >>> s = ' hell ...

  2. PHP设计模式系列 - 解释器模式

    解释器模式 解释器模式 用于分析一个实体的关键元素,并且针对每个元素提供自己的解释或相应动作.解释器模式非常常用,比如PHP的模板引擎 就是非常常见的一种解释器模. 代码: <?php //解释 ...

  3. java Date日期类和SimpleDateFormat日期类格式

    ~Date表示特定的时间,精确到毫秒~构造方法:public Date()//构造Date对象并初始化为当前系统的时间public Date(long date) //1970-1-1 0:0:0到指 ...

  4. 自定义input[type="checkbox"]的样式

    对复选框自定义样式,我们以前一直用的脚本来实现,不过现在可以使用新的伪类 :checkbox 来实现. 如果直接对复选框设置样式,那么这个伪类并不实用,因为没有多少样式能够对复选框起作用.不过,倒是可 ...

  5. MySql+Memcached架构的问题

    Memcached采用客户端-服务器的架构,客户端和服务器端的通讯使用自定义的协议标准,只要满足协议格式要求,客户端Library可以用任何语言实现. Memcached服务器使用基于Slab的内存管 ...

  6. 【openjudge】【递推】例3.4 昆虫繁殖

    [题目描述] 科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强.每对成虫过x个月产y对卵,每对卵要过两个月长成成虫.假设每个成虫不死,第一个月只有一对成虫,且卵长成成虫后的第一个月不产卵 ...

  7. 20145203盖泽双:Java实验报告二

    Java实验报告二:Java面向对象程序设计 实验要求: 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验内容 ...

  8. ES6新特性6:模块Module

    本文摘自ECMAScript6入门,转载请注明出处. 一.Module简介 ES6的Class只是面向对象编程的语法糖,升级了ES5的构造函数的原型链继承的写法,并没有解决模块化问题.Module功能 ...

  9. 访问 IIS 元数据库失败解决问题的方法

    近日调试一Asp.net程序,出现了“访问 IIS 元数据库失败”的错误信息,最后经过搜索发现了解决问题的方法. 解决方法如下: 1.依次点击“开始”-“运行”. 2.在“运行”栏内输入 “C:\WI ...

  10. 为什么can接口要接通用CAN隔离收发器啊?

    为什么can接口要接通用CAN隔离收发器啊? 主要是为了实现远端接地环路断开的系统,让接口允许在很大的共模电压变化下保证可靠通讯.通常使用CAN通讯的系统,都是要实现远距离可靠通讯,这也恰恰是CAN- ...