【问题标题】:Limit parallel request amount by a user限制用户的并行请求量
【发布时间】:2018-01-02 21:06:48
【问题描述】:

我想像这样限制我的产品:

  • starter:没有并行调用(只允许同步调用)
  • 高级版:10 个并行调用(允许有限制的异步调用)

api网关后面的服务需要一些时间,所以有些人想进行异步调用以获得更多结果。

我从 azure 发现的唯一限制是速率和配额限制。但是它们的限制是每次调用,我需要它来进行并行调用。

我想过这个逻辑:

<inbound>
<http-call>
send user id to a azure function, that increases the counter for the user, returns the current counter
</http-call>
<when>
compare counter value with the product limit (x = 0 for starter or x <= 10 for premium)
if true route to the service, if false generate a "too many requests" response
</when>
</inbound>

<outbound>
<http-call>
decrease the counter
</http-call>
</outbound>

我不确定这是否是最好的逻辑,因为函数需要时间来更新值。有没有办法保存某种“共享变量”,每个请求都可以访问它以检查 api 管理中的计数器,而不是通过外部函数?

【问题讨论】:

  • 目前唯一的方法是外部服务(如您的示例)或缓存(如下面的 mimo)。很快将引入新策略以允许限制并发,但仅限于每个节点,即不针对整个服务全局。

标签: azure parallel-processing rate-limiting azure-api-management


【解决方案1】:

我找到了一种使用缓存的方法(我认为缓存功能是全局的,但尚未得到证实。您只需一个缓存数组,将用户 ID 作为键并计算并行请求的数量):

<inbound>
        <set-variable name="user-id" value="@(context.User.Id)" />
        <!--Look for user-counter for this user in the cache -->
        <cache-lookup-value key="@("user-counter-" + context.Variables["user-id"])" variable-name="user-counter" />
        <choose>
            <!-- check the limit -->
            <when condition="@(context.Variables.ContainsKey("user-counter"))">
                <choose>
                    <!-- -->
                    <when condition="@((int)context.Variables["user-counter"] > 0)">
                        <return-response>
                            <set-status code="429" reason="TOO MANY REQUESTS" />
                            <set-body>too many parallel requests</set-body>
                        </return-response>
                    </when>
                    <when condition="@((int)context.Variables["user-counter"] <= 0)">
                        <cache-store-value key="@("user-counter-" + context.Variables["user-id"])" value="@((int)context.Variables["user-counter"] + 1)" duration="100000" />
                    </when>
                </choose>
            </when>
            <!-- If we don’t find it in the cache, create it with the value 1 -->
            <when condition="@(!context.Variables.ContainsKey("user-counter"))">
                <cache-store-value key="@("user-counter-" + context.Variables["user-id"])" value="0" duration="100000" />
            </when>
        </choose>
</inbound>

<outbound>
        <base />
        <!-- remove user-counter -->
        <cache-lookup-value key="@("user-counter-" + context.Variables["user-id"])" variable-name="user-counter-old" />
        <cache-store-value key="@("user-counter-" + context.Variables["user-id"])" value="@((int)context.Variables["user-counter-old"] - 1)" duration="100000" />
</outbound>

【讨论】:

  • 缓存是一种有效的方法,缓存确实是整个服务共享的,但是应该谨慎,因为缓存操作不是原子的,即在缓存查找值和缓存存储值策略之间执行在 APIM 服务的一个节点上,其他节点可能会更新缓存中的值,并且此更新将丢失。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-18
  • 2018-07-18
  • 2019-04-22
  • 1970-01-01
  • 2019-07-31
  • 2021-12-08
  • 2019-11-12
相关资源
最近更新 更多