速率限制

本文介绍如何使用 Service Infrastructure 对与 Service Management API 集成的托管服务实施速率限制。

托管服务可以为许多服务使用方提供服务。为了保护系统容量并确保合理使用,托管服务通常使用速率限制在服务使用方之间分配容量。 借助 Service Management API 和 Service Control API,您可以管理和实施速率限制。

配置速率限制

如要使用速率限制功能,请为您的服务生产者项目在服务配置中配置 _quota metrics__quota limits_

当前,受支持的速率限制是每个服务使用者每分钟的请求数,其中服务使用者是由 API 密钥、项目 ID 或项目编号标识的 Google Cloud 项目。对于速率限制,请求是一个模糊的概念。服务可以选择 HTTP 请求作为请求,也可以选择有效负载的字节作为请求。速率限制功能独立于请求的语义。

配额指标

指标是命名的计数器,用于衡量特定值随时间变化的情况。例如,服务收到的 HTTP 请求次数就是一个指标。配额指标是用于限制配额和速率的指标。当服务发生某项活动时,一个或多个配额指标可能会升高。当指标值达到预定义的配额限制时,服务应拒绝该活动并显示 429 错误。

配额限制

配额限制是对配额指标的强制性限制。例如,每个服务使用方每分钟的请求次数就是一个配额限制。目前,唯一受支持的配额限制类型是每位使用者每分钟的配额,具体来说就是 1/min/{project}

服务/使用方对的实际速率限制由 3 项设置控制:

  • 为托管服务指定的默认限制。
  • 服务使用方对应的服务提供方替换值。
  • 服务使用方对应的服务使用方替换值。

有效的速率限制如下:

  • 如果没有任何替换值,则采用默认限制。
  • 如果有服务提供方替换值,但没有服务使用方替换值,则采用服务提供方替换值。
  • 如果有服务使用方替换值,但没有服务提供方替换值,则采用服务使用方替换值和默认限制中的最小值。
  • 如果既有服务提供方替换值,也有服务使用方替换值,则采用服务使用方替换值和服务提供方替换值中的最小值。

强制实施速率限制

要强制实施速率限制,属于托管式服务的每台服务器都需要定期调用 Service Control API services.allocateQuota 方法。如果 services.allocateQuota 方法的响应指示用量超出限制,则服务器应拒绝相应传入请求并显示 429 错误。如需了解详情,请参阅 services.allocateQuota 方法的参考文档。

建议每台服务器都应使用批处理、缓存和预测逻辑来提高系统性能和可靠性。一般来说,一台服务器每秒只应为同一(服务/使用方/指标)元组调用 services.allocateQuota 方法一次。

下面的示例演示如何调用 services.allocateQuota 方法来检查速率限制。服务名称、使用方 ID、指标名称和指标值这些重要请求参数必须正确设置。services.allocateQuota 方法会尝试将(服务/使用方/指标)元组对应的用量增加指定的值。如果增加后的使用量超出限制,则会返回错误。以下示例使用 gcurl 命令演示该调用。如需了解如何进行这项设置,请参阅 Service Control API 使用入门

gcurl -d '{
  "allocateOperation": {
    "operationId": "123e4567-e89b-12d3-a456-426655440000",
    "methodName": "google.example.hello.v1.HelloService.GetHello",
    "consumerId": "project:endpointsapis-consumer",
    "quotaMetrics": [{
      "metricName": "endpointsapis.appspot.com/requests",
      "metricValues": [{
        "int64Value": 1
      }]
    }],
    "quotaMode": "NORMAL"
  }
}' https://servicecontrol.googleapis.com/v1/services/endpointsapis.appspot.com:allocateQuota
{
  "operationId": "123e4567-e89b-12d3-a456-426655440000",
  "quotaMetrics": [
    {
      "metricName": "serviceruntime.googleapis.com/api/consumer/quota_used_count",
      "metricValues": [
        {
          "labels": {
            "/quota_name": "endpointsapis.appspot.com/requests"
          },
          "int64Value": "1"
        }
      ]
    }
  ],
  "serviceConfigId": "2017-09-10r0"
}

错误处理

如果 HTTP 响应代码为 200,并且响应中包含 RESOURCE_EXHAUSTED QuotaError,则您的服务器应拒绝相应请求并显示 429 错误。如果该响应不包含任何配额错误,则您的服务器应继续处理传入请求。对于所有其他配额错误,您的服务器应拒绝相应请求并显示 409 错误。考虑到安全风险,您在错误消息中添加错误信息时应非常谨慎。

如果出现的是其他任何 HTTP 响应代码,那么您的服务器可能存在一些编程错误。建议您在调试问题时让服务器继续处理传入请求。如果 services.allocateQuota 方法返回任何意外错误,则您的服务应记录该错误并接受传入请求。您可以稍后再调试该错误。

应急开启

速率限制功能的作用是防止您的托管服务过载,以及在服务使用方之间合理分配服务容量。由于大多数服务使用方在正常操作期间都不会达到其速率限制,因此如果速率限制功能不可用,您的托管服务应接受所有传入请求(也称为“应急开启”)。 这可以避免服务可用性受到速率限制系统的影响。

如果使用 services.allocateQuota 方法,则服务必须忽略 500503504 错误,而无需重试。为避免过度依赖速率限制功能,Service Control API 会定期执行有限的错误注入。