# 速率限制

> Shoplazza REST API 的速率限制机制：应用与店铺两个维度、漏桶算法、限流响应头，以及 429 响应的处理方式。

## Shoplazza API 速率限制

所有 Shoplazza API 都有速率限制。REST Admin API 使用**基于请求数**的限制：每个请求计数相同，与返回的数据量无关。

REST Admin API 基于两个维度执行速率限制：

* 应用/店铺：每个应用和店铺组合都有独立限制。
* 店铺：每个店铺都有独立限制。

例如：每次请求都会同时计入这两个维度。例如，App A 调用 Store 1 时，请求会消耗 App A 与 Store 1 组合的桶容量，也会消耗 Store 1 的桶容量。只有两个桶都有剩余容量时，请求才会成功。

| 当前桶状态 | 结果 |
| --- | --- |
| App A + Store 1 为 `39/40`，Store 1 为 `79/80` | 请求可以执行。计入后，两个桶分别变为 `40/40` 和 `80/80`。 |
| App A + Store 1 为 `40/40`，Store 1 为 `10/80` | 请求会被节流，因为应用/店铺维度的桶已满。 |
| App A + Store 1 为 `10/40`，Store 1 为 `80/80` | 请求会被节流，因为店铺维度的桶已满。 |

应用/店铺维度的默认设置如下：

* 桶大小：每个应用/店铺 40 个请求
* 漏出速率：每秒 2 个请求

店铺维度的默认设置如下：

* 桶大小：每个店铺 80 个请求
* 漏出速率：每秒 20 个请求

为避免被限流，在客户端采用以下做法：

* 为每个店铺维护独立请求队列，避免某个店铺的突发请求影响其它店铺。
* 控制每个应用/店铺组合的请求发送速率，使其低于应用/店铺维度的漏出速率。
* 统计每个店铺的总请求量，使调用同一店铺的所有应用或 worker 合计低于店铺维度的漏出速率。
* 监控每次响应中的 `X-Shoplazza-Shop-Api-Call-Limit` 响应头。当数值接近桶容量时，在桶满之前主动降速。
* 缓存可复用的响应，尤其是针对同一资源的重复读取。
* 收到 `429` 时，暂停受影响的请求队列并读取 `Retry-After` 响应头。等待其指定的秒数后再恢复请求。

## 漏桶算法

所有 Shoplazza API 都使用漏桶算法管理请求。只要不让桶溢出，应用就可以在一段时间内突发地发出请求。该模型的要点如下：

* 每个应用都有一个可容纳固定数量"弹珠"的"桶"（例如 40 个）。
* 每个 API 请求向桶中投入一个弹珠。
* 桶以固定速率漏出弹珠（例如每秒 2 个），持续腾出空间。
* 如果桶满了，后续请求会失败并返回错误，直到桶漏出足够空间。

## 速率限制响应头 {#rate-limit-headers}

通过每次 API 响应返回的 `X-Shoplazza-Shop-Api-Call-Limit` 响应头，可以查看你针对某个店铺已发出的请求数。

X-Shoplazza-Shop-Api-Call-Limit: 32/40

* 32：桶中当前的弹珠数。
* 40：最大桶容量。

计数会随漏出而递减。例如，响应头显示 39/40 后若停止发送请求，10 秒后可能显示 19/40。

`Retry-After` 响应头指定收到 **429 Too Many Requests** 响应后重试前需等待的秒数。

## 处理 429 响应 {#retry-after-header}

当请求超过速率限制时，Shoplazza 返回 **429 Too Many Requests** 错误和 `Retry-After` 响应头。按响应头指定的秒数等待后再重试。在此期间发出的任何请求都将被节流。

X-Shoplazza-Shop-Api-Call-Limit: 40/40\
Retry-After: 2.0
