• 启用速率限制
    • 开始之前
    • 速率限制
    • 有条件的速率限制
    • 理解速率限制
    • 清理
    • 相关内容

    启用速率限制

    这一任务展示了如何使用 Istio 动态的对服务通信进行速率限制。

    开始之前

    • 按照安装指南在 Kubernetes 集群上设置 Istio。

    • 部署 Bookinfo 示例应用。

    Bookinfo 例子中需要部署三个版本的 reviews 服务:

    • v1 版本不会调用 ratings 服务。
    • v2 版本调用 ratings 服务,并用 1 到 5 个黑色图标显示评级信息。
    • v3 版本调用 ratings 服务,并用 1 到 5 个红色图标显示评级信息。这里需要设置一个到某版本的缺省路由,否则当发送请求到 reviews 服务的时候,Istio 会随机路由到某个版本,有时候显示评级图标,有时不显示。
    • 将所有服务的默认版本设置为 v1。

    Zip

    1. $ kubectl apply -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@

    速率限制

    在此任务中,您将 Istio 配置为根据 IP 地址将流量限制到访问 productpage 的用户。您将使用 X-Forwarded-For 请求 http header 作为客户端 IP 地址。您还将使用免除登录用户的条件速率限制。

    为方便起见,您可以配置 memquota 适配器启用速率限制。但是,在生产系统上,你需要 Redis ,然后配置 redisquota 适配器。 memquotaredisquota 适配器都支持 quota template,因此,在两个适配器上启用速率限制的配置是相同的。

    • 速率限制配置分为两部分。

      • 客户端
        • QuotaSpec 定义客户端应该请求的配额名称和大小。
        • QuotaSpecBinding 有条件地将 QuotaSpec 与一个或多个服务相关联。
      • Mixer 端
        • quota instance 定义了 Mixer 如何确定配额的大小。
        • memquota adapter 定义了 memquota 适配器配置。
        • quota rule 定义何时将配额实例分派给 memquota 适配器。运行以下命令以使用 memquota 启用速率限制:

    Zip

    1. $ kubectl apply -f @samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml@

    或者

    将以下 yaml 文件另存为 redisquota.yaml 。替换 rate_limit_algorithm,redis_server_url包含配置值。

    1. apiVersion: "config.istio.io/v1alpha2"
    2. kind: redisquota
    3. metadata:
    4. name: handler
    5. namespace: istio-system
    6. spec:
    7. redisServiceUrl: <redis_server_url>
    8. connectionPoolSize: 10
    9. quotas:
    10. - name: requestcount.quota.istio-system
    11. maxAmount: 500
    12. validDuration: 1s
    13. bucketDuration: 500ms
    14. rateLimitAlgorithm: <rate_limit_algorithm>
    15. # The first matching override is applied.
    16. # A requestcount instance is checked against override dimensions.
    17. overrides:
    18. # The following override applies to 'reviews' regardless
    19. # of the source.
    20. - dimensions:
    21. destination: reviews
    22. maxAmount: 1
    23. # The following override applies to 'productpage' when
    24. # the source is a specific ip address.
    25. - dimensions:
    26. destination: productpage
    27. source: "10.28.11.20"
    28. maxAmount: 500
    29. # The following override applies to 'productpage' regardless
    30. # of the source.
    31. - dimensions:
    32. destination: productpage
    33. maxAmount: 2
    34. ---
    35. apiVersion: "config.istio.io/v1alpha2"
    36. kind: quota
    37. metadata:
    38. name: requestcount
    39. namespace: istio-system
    40. spec:
    41. dimensions:
    42. source: request.headers["x-forwarded-for"] | "unknown"
    43. destination: destination.labels["app"] | destination.workload.name | "unknown"
    44. destinationVersion: destination.labels["version"] | "unknown"
    45. ---
    46. apiVersion: config.istio.io/v1alpha2
    47. kind: rule
    48. metadata:
    49. name: quota
    50. namespace: istio-system
    51. spec:
    52. # quota only applies if you are not logged in.
    53. # match: match(request.headers["cookie"], "session=*") == false
    54. actions:
    55. - handler: handler.redisquota
    56. instances:
    57. - requestcount.quota
    58. ---
    59. apiVersion: config.istio.io/v1alpha2
    60. kind: QuotaSpec
    61. metadata:
    62. name: request-count
    63. namespace: istio-system
    64. spec:
    65. rules:
    66. - quotas:
    67. - charge: 1
    68. quota: requestcount
    69. ---
    70. apiVersion: config.istio.io/v1alpha2
    71. kind: QuotaSpecBinding
    72. metadata:
    73. name: request-count
    74. namespace: istio-system
    75. spec:
    76. quotaSpecs:
    77. - name: request-count
    78. namespace: istio-system
    79. services:
    80. - name: productpage
    81. namespace: default
    82. # - service: '*' # Uncomment this to bind *all* services to request-count
    83. ---

    运行以下命令以使用 redisquota 启用速率限制:

    1. $ kubectl apply -f redisquota.yaml
    • 检查 memquota 的创建情况:
    1. $ kubectl -n istio-system get memquota handler -o yaml
    2. apiVersion: config.istio.io/v1alpha2
    3. kind: memquota
    4. metadata:
    5. name: handler
    6. namespace: istio-system
    7. spec:
    8. quotas:
    9. - name: requestcount.quota.istio-system
    10. maxAmount: 500
    11. validDuration: 1s
    12. overrides:
    13. - dimensions:
    14. destination: reviews
    15. maxAmount: 1
    16. validDuration: 5s
    17. - dimensions:
    18. destination: productpage
    19. maxAmount: 2
    20. validDuration: 5s

    memquota 处理程序定义了 3 种不同的速率限制方案。在没有 overrides 生效的缺省情况下,每秒限制请求为 500 次。还定义了两个 overrides 条目:

    • 如果 destination 值为 reviews ,限制值为每 5 秒 1 次。
    • 如果 destination 值为 productpage ,限制值为每 5 秒 2 次。处理请求时,Istio 会选择第一条符合条件的 overrides(读取顺序为从上到下)应用到请求上。

    或者

    确认已创建 redisquota handler :

    1. $ kubectl -n istio-system get redisquota handler -o yaml
    2. apiVersion: config.istio.io/v1alpha2
    3. kind: redisquota
    4. metadata:
    5. name: handler
    6. namespace: istio-system
    7. spec:
    8. connectionPoolSize: 10
    9. quotas:
    10. - name: requestcount.quota.istio-system
    11. maxAmount: 500
    12. validDuration: 1s
    13. bucketDuration: 500ms
    14. rateLimitAlgorithm: ROLLING_WINDOW
    15. overrides:
    16. - dimensions:
    17. destination: reviews
    18. maxAmount: 1
    19. - dimensions:
    20. destination: productpage
    21. source: 10.28.11.20
    22. maxAmount: 500
    23. - dimensions:
    24. destination: productpage
    25. maxAmount: 2

    redisquota handler 定义了 4 种不同的速率限制方案。在没有 overrides 生效的缺省情况下,每秒限制请求为 500次。它使用 ROLLING_WINDOW 算法进行配额检查,因此为 ROLLING_WINDOW 算法定义了 500ms 的 bucketDuration。还定义了 overrides 条目:

    • 如果 destination 的值为 reviews是 那么最大请求配额为 1
    • 如果 destination 的值为 productpage 并且来源是 10.28.11.20 那么最大请求配额为 500
    • 如果 destination 的值为 productpage 那么最大请求配额为 2。处理请求时,Istio 会选择第一条符合条件的 overrides(读取顺序为从上到下)应用到请求上。

    确认 quota instance 的创建情况:

    1. $ kubectl -n istio-system get quotas requestcount -o yaml
    2. apiVersion: config.istio.io/v1alpha2
    3. kind: quota
    4. metadata:
    5. name: requestcount
    6. namespace: istio-system
    7. spec:
    8. dimensions:
    9. source: request.headers["x-forwarded-for"] | "unknown"
    10. destination: destination.labels["app"] | destination.service.host | "unknown"
    11. destinationVersion: destination.labels["version"] | "unknown"

    quota 模板定义了 memquotaredisquota 使用的三个维度,用于设置匹配某些属性的请求。 destination 将被设置为 destination.labels["app"]destination.service.host"unknown" 中的第一个非空值。有关表达式的更多信息,请参阅表达式语言文档中获取更多表达式方面的内容。

    • 确认 quota rule 的创建情况:
    1. $ kubectl -n istio-system get rules quota -o yaml
    2. apiVersion: config.istio.io/v1alpha2
    3. kind: rule
    4. metadata:
    5. name: quota
    6. namespace: istio-system
    7. spec:
    8. actions:
    9. - handler: handler.memquota
    10. instances:
    11. - requestcount.quota

    rule 通知 Mixer,使用 Instance requestcount.quota 构建对象并传递给上面创建的 handler.memquota。这一过程使用 quota 模板将 dimensions 数据映射给 memquota 进行处理。

    • 确认 QuotaSpec 的创建情况:
    1. $ kubectl -n istio-system get QuotaSpec request-count -o yaml
    2. apiVersion: config.istio.io/v1alpha2
    3. kind: QuotaSpec
    4. metadata:
    5. name: request-count
    6. namespace: istio-system
    7. spec:
    8. rules:
    9. - quotas:
    10. - charge: "1"
    11. quota: requestcount

    QuotaSpec 为上面创建的 quota 实例(requstcount)设置了 charge 值为 1。

    • 确认 QuotaSpecBinding 的创建情况:
    1. $ kubectl -n istio-system get QuotaSpecBinding request-count -o yaml
    2. kind: QuotaSpecBinding
    3. metadata:
    4. name: request-count
    5. namespace: istio-system
    6. spec:
    7. quotaSpecs:
    8. - name: request-count
    9. namespace: istio-system
    10. services:
    11. - name: productpage
    12. namespace: default
    13. # - service: '*'

    QuotaSpecBinding 把前面的 QuotaSpec 绑定到需要应用限流的服务上。因为 QuotaSpecBinding 所属命名空间和这些服务是不一致的,所以这里必须定义每个服务的 namespace

    • 在浏览器中刷新 productpage 页面。

    request-count 配额适用于 productpage ,每 5 秒允许 2 个请求。如果你不断刷新页面,你会看到 RESOURCE_EXHAUSTED:Quota is exhausted for: requestcount

    有条件的速率限制

    在前面的例子中,ratings 服务受到的速率限制并没有考虑没有 dimension 属性的情况。还可以在配额规则中使用任意属性进行匹配,从而完成有条件的配额限制。

    例如下面的配置:

    1. $ kubectl -n istio-system edit rules quota
    2. apiVersion: config.istio.io/v1alpha2
    3. kind: rule
    4. metadata:
    5. name: quota
    6. namespace: istio-system
    7. spec:
    8. match: match(request.headers["cookie"], "session=*") == false
    9. actions:
    10. - handler: handler.memquota
    11. instances:
    12. - requestcount.quota

    只有当请求中没有 session = <sessionid> cookie 时,才会调度 memquotaredisquota 适配器。这可确保登录用户不受此配额的约束。

    • 验证速率限制不适用于登录用户。

    jason 身份登录并反复刷新 productpage。现在你应该能够毫无问题地做到这一点。

    • 验证速率限制在未登录时适用

    注销 jason 并反复刷新 productpage

    您应该再次看到 RESOURCE_EXHAUSTED:Quota is exhausted for: requestcount

    理解速率限制

    在前面的例子中演示了 Mixer 根据条件对请求实施速率限制的过程。

    每个有名称的 Quota 实例,例如前面的 requestcount,都代表了一套计数器。这一个集合就是所有 Quota dimensions 的笛卡尔积定义的。如果上一个 expiration 区间内的请求数量超过了 maxAmount,Mixer 就会返回 RESOURCE_EXHAUSTED 信息给 Proxy。Proxy 则返回 HTTP 429 给调用方。

    memquota 适配器使用一个为亚秒级分辨率的滑动窗口来实现速率限制。

    适配器配置中的 maxAmount 设置了关联到 Quota 实例中的所有计数器的缺省限制。如果所有 overrides 条目都无法匹配到一个请求,就只能使用 maxAmount 限制了。memquota 会选择适合请求的第一条 overrideoverride 条目无需定义所有 quota dimension, 例如例子中的 0.2 qps 条目在 4 条 quota dimensions 中只选用了三条。

    如果要把上面的策略应用到某个命名空间而非整个 Istio 网格,可以把所有 istio-system 替换成为给定的命名空间。

    清理

    • 如果使用 memquota ,删除 memquota 速率限制相关的配置:

    Zip

    1. $ kubectl delete -f @samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml@

    或者

    如果使用 redisquota ,删除 redisquota 速率限制相关的配置:

    1. $ kubectl delete -f redisquota.yaml
    • 删除应用路由规则:

    Zip

    1. $ kubectl delete -f @samples/bookinfo/networking/virtual-service-all-v1.yaml@
    • 如果不准备尝试后续任务,可参考 Bookinfo 清理 的介绍关停应用。

    相关内容

    Mixer 适配器模型

    概要说明 Mixer 的插件架构。

    Denier 适配器以及黑白名单

    展示使用简单的 Denier 适配器或黑白名单对服务进行访问控制的方法。

    Egress TLS 流量中的 SNI 监控及策略

    如何为 Egress TLS 流量配置 SNI 监控并应用策略。

    启用策略检查

    本任务讲解如何启用 Istio 策略检查功能。

    策略与遥测

    描述策略实施和遥测机制。