Azure API Management并发限制设为1却允许2次执行的问题
为什么APIM设置
limit-concurrency max-count=1却允许2次并发? 这个问题我之前处理过,最常见的原因是APIM服务的多实例部署,结合limit-concurrency策略的本地计数机制导致的,下面详细拆解:
核心原因:limit-concurrency是实例级限制,而非全局限制
limit-concurrency策略的并发计数是每个APIM服务实例本地维护的,不是跨实例的全局计数。如果你的APIM服务是Basic、Standard或Premium层级(这些层级支持多实例部署),并且当前运行着2个实例:
- 每个实例都会独立执行
max-count=1的限制 - 两个实例同时处理请求时,总并发数就会达到2,当第三个请求被路由到已经有一个正在处理请求的实例时,才会触发429状态码
这完全符合你描述的“允许2次并发,第三次返回429”的现象。
其他可能的次要原因
除了多实例问题,还有两个小概率情况需要排查:
- 策略执行时机的短暂窗口:当第一个请求还在
forward-request阶段(尚未完成策略执行),第二个请求快速进入limit-concurrency策略时,单实例下理论上应该被限制,但如果是网络或APIM内部处理的微小延迟,可能出现短暂的2次并发(不过这种情况非常罕见,且持续时间极短) - 策略配置重叠:检查是否在API级别或全局级别也配置了
limit-concurrency策略,导致多个策略的限制逻辑叠加,但这种情况通常会让限制更严格,而非放宽
解决办法
根据你的需求,分两种情况处理:
1. 保持实例级限制(每个实例最多1个并发)
如果你的需求就是每个实例限制1个并发,当前配置是正确的,总并发数等于实例数量。如果想减少总并发,只需在Azure门户的APIM「规模」选项卡中减少实例数量即可。
2. 需要全局级别的并发限制(整个APIM服务最多1个并发)
limit-concurrency本身不支持全局计数,需要借助Azure Redis Cache来实现全局的并发控制,大致步骤如下:
- 在Azure中创建Redis Cache实例
- 在APIM的操作策略中添加以下逻辑:
- 使用
cache-lookup-value从Redis获取当前并发计数 - 如果计数≥1,直接返回429状态码
- 如果计数<1,使用
cache-store-value将计数加1(设置合适的过期时间,避免请求异常时计数无法重置) - 执行
forward-request转发请求 - 在请求完成(成功或失败)后,使用
cache-store-value将计数减1
- 使用
示例策略片段(简化版):
<choose> <when condition="@(int.Parse((string)context.Variables["current_concurrency"]) >= 1)"> <return-response> <set-status code="429" reason="Too Many Requests" /> <set-header name="Retry-After" exists-action="override"> <value>10</value> </set-header> </return-response> </when> <otherwise> <cache-store-value key="global_concurrency" value="@((int.Parse((string)context.Variables["current_concurrency"]) + 1).ToString())" duration="seconds" timeout="300" /> <backend> <forward-request timeout="120" /> </backend> <cache-store-value key="global_concurrency" value="@((int.Parse((string)context.Variables["current_concurrency"]) - 1).ToString())" duration="seconds" timeout="300" /> </otherwise> </choose>
验证步骤
你可以先验证实例数量:
- 登录Azure门户,进入你的APIM服务
- 切换到「规模」选项卡,查看当前运行的实例数量
如果确实是2个,那就能完全解释你的问题;临时将实例数改为1后再测试,应该只能同时执行1次请求,第二次就返回429。
内容的提问来源于stack exchange,提问作者marco
相关产品推荐
相关产品推荐

