反模式:重复使用配额政策

您正在查看 ApigeeApigee Hybrid 文档。
查看 Apigee Edge 文档。

借助 Apigee,您能够使用配额政策配置在特定时间段内 API 代理允许的请求的数量。

反模式

如果重复使用配额政策,每次执行配额政策时,配额计数器都将递减,而无论配额政策在何处使用。也就是说,如果在以下位置重复使用了配额政策:

  • 在 API 代理的同一流或不同流中
  • 在 API 代理的不同目标端点中

那么,每次执行配额政策时配额计数器都会递减,我们收到配额违规错误的时间将比预期的指定时间间隔早得多。

下面我们通过一个例子来说明这种情况的原理。

API 代理

假设我们有一个名为“TestTargetServerQuota”的 API 代理,它根据资源路径将流量路由到两个不同的目标服务器。我们希望将每个目标服务器的 API 流量限制为每分钟 10 个请求。以下表格描述了此情况:

资源路径 目标服务器 配额
/target-us target-US.somedomain.com 每分钟 10 个请求
/target-eu target-EU.somedomain.com 每分钟 10 个请求

配额政策

由于两个目标服务器的流量配额相同,我们定义一条名为“Quota-Minute-Target-Server”配额政策,如下所示:

<!-- /antipatterns/examples/1-8.xml -->
<Quota name="Quota-Minute-Target-Server">
  <Interval>1</Interval>
  <TimeUnit>minute</TimeUnit>
  <Distributed>true</Distributed>
  <Allow count="10"/>
</Quota>

目标端点

我们在目标端点“Target-US”的前流 (preflow) 中使用配额政策“Quota-Minute-Target-Server”:

<!-- /antipatterns/examples/1-9.xml -->
<TargetEndpoint name="Target-US">
  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <Name>Quota-Minute-Target-Server</Name>
      </Step>
    </Request>
  </PreFlow>
  <HTTPTargetConnection>
    <URL>http://target-us.somedomain.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

在另一目标端点“Target-EU”的前流中重复使用同一配额政策“Quota-Minute-Target-Server”:

<!-- /antipatterns/examples/1-10.xml -->
<TargetEndpoint name="Target-EU">
  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <Name>Quota-Minute-Target-Server</Name>
      </Step>
    </Request>
  <Response/>
  </PreFlow>
  <HTTPTargetConnection>
    <URL>http://target-us.somedomain.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

传入流量模式

假设在以下模式下,我们在前 30 秒内共收到针对此 API 代理的 10 个 API 请求:

资源路径 /target-us /target-eu 全部
请求数 4 6 10

假设在 32 秒后,我们收到资源路径为 /target-us 的第 11 个 API 请求。

我们认为,根据允许的配额,目标端点 target-us 还可以接受 6 个 API 请求,因此该请求能够成功通过。

但实际上,我们得到了 Quota violation error

原因:因为我们在两个目标端点中使用同一配额政策,因此系统使用单个配额计数器跟踪到达两个目标端点的 API 请求。因此,我们用光了每分钟总共(而不是单个目标端点)10 个请求的配额。

影响

这种反模式可能导致与预期根本不匹配的情况,使人们认为配额限制被提前用尽。

最佳做法

  • 通过定义单个配额政策,使用 <Class><Identifier> 元素来确保维护多个不同的计数器。我们将标头 target_id 用作 <Identifier> 来重新定义上一部分介绍的配额政策“Quota-Minute-Target-Server”,如下所示:
    <!-- /antipatterns/examples/1-11.xml -->
    <Quota name="Quota-Minute-Target-Server">
      <Interval>1</Interval>
      <TimeUnit>minute</TimeUnit>
      <Allow count="10"/>
      <Identifier ref="request.header.target_id"/>
      <Distributed>true</Distributed>
    </Quota>
    • 与之前一样,我们将继续在目标端点“Target-US”和“Target-EU”中使用此配额政策。
    • 现在,假设标头 target_id 的值为“US”,则请求将路由到目标端点“Target-US”。
    • 同样,如果标头 target_id 的值为“EU”,则请求会被路由到目标端点“Target-EU”。
    • 因此,即使我们在两个目标端点中使用同一配额政策,系统也会根据 <Identifier> 值维护单独的配额计数器。
    • 因此,通过使用 <Identifier> 元素,我们可以确保每个目标端点都获得 10 个请求的允许配额。
  • 在每个流/目标端点/API 代理中使用单独的配额政策,以确保始终获得允许的 API 请求数量。现在,我们来看看上一部分中使用的示例,了解如何为每个目标端点实现 10 个请求的允许配额。
    • 为每个目标端点(“Target-US”和“Target-EU”)定义单独的配额政策

      目标端点“Target-US”的配额政策:

      <!-- /antipatterns/examples/1-12.xml -->
      <Quota name="Quota-Minute-Target-Server-US">
        <Interval>1</Interval>
        <TimeUnit>minute</TimeUnit>
        <Distributed>true</Distributed>
        <Allow count="10"/>
      </Quota>

      目标端点“Target-EU”的配额政策:

      <!-- /antipatterns/examples/1-13.xml -->
      <Quota name="Quota-Minute-Target-Server-EU">
        <Interval>1</Interval>
        <TimeUnit>minute</TimeUnit>
        <Distributed>true</Distributed>
        <Allow count="10"/>
      </Quota>
    • 使用目标端点定义中各自的配额政策,如下所示:

      目标端点“Target-US”:

      <!-- /antipatterns/examples/1-14.xml -->
      <TargetEndpoint name="Target-US">
        <PreFlow name="PreFlow">
          <Request>
            <Step>
              <Name>Quota-Minute-Target-Server-US</Name>
            </Step>
          </Request>
          <Response/>
        </PreFlow>
        <HTTPTargetConnection>
          <URL>http://target-us.somedomain.com</URL>
        </HTTPTargetConnection>
      </TargetEndpoint>

      目标端点“Target-EU”:

      <!-- /antipatterns/examples/1-15.xml -->
      <TargetEndpoint name="Target-EU">
        <PreFlow name="PreFlow">
          <Request>
            <Step>
              <Name>Quota-Minute-Target-Server-EU</Name>
            </Step>
          </Request>
          <Response/>
        </PreFlow>
        <HTTPTargetConnection>
          <URL>http://target-eu.somedomain.com</URL>
        </HTTPTargetConnection>
      </TargetEndpoint>
    • 由于我们在目标端点“Target-US”和“Target-EU”中使用了单独的配额政策,因此系统将维护单独的计数器。这可确保为每个目标端点获得允许的配额(每分钟 10 个 API 请求)。
  • 使用 <Class><Identifier> 元素确保维护多个不同的计数器。