2. 限流算法基础(上):固定窗口算法
固定窗口算法(Fixed Window Algorithm)是限流领域最直观、最容易实现的算法之一。它将时间划分为固定长度的窗口(例如 1 秒、1 分钟),在每个窗口内统计请求数量,一旦超过预设阈值,后续请求将被直接拒绝或排队等待。该算法在金融 API 网关、交易接口、行情推送等场景中仍有广泛应用,尤其适合对突发流量容忍度较低、且时间窗口边界精度要求不高的场景。
2.1 核心原理与数学模型
固定窗口算法的核心思想可以概括为:“窗口内计数,超限即拒绝”。其数学模型如下:
- 窗口长度(Window Size):记为
W,单位为秒或毫秒,例如W = 1000 ms(1 秒窗口)。 - 阈值(Threshold):记为
T,表示每个窗口内允许的最大请求数,例如T = 10(每秒最多 10 次请求)。 - 当前窗口计数(Current Count):记为
C,从窗口起始时刻开始累计的请求数。 - 判定逻辑:当新请求到达时,若
C < T,则允许请求并将C加 1;若C >= T,则拒绝请求。 - 窗口重置:当系统时间进入下一个窗口时,
C重置为 0。
关键指标: 固定窗口算法的平均限流速率 = T / W(请求/秒)。例如,W=1s,T=10,则平均速率为 10 QPS。
2.2 固定窗口算法流程图
下图展示了固定窗口算法的完整判定流程,包含窗口创建、计数检查、请求放行与拒绝、以及窗口重置四个核心阶段。
2.3 Python 实现与代码示例
以下是一个基于 time.time() 的固定窗口限流器实现,适用于单机环境。代码包含窗口管理、计数检查、重置逻辑以及线程安全保护。
import time
import threading
class FixedWindowRateLimiter:
"""
固定窗口限流器
:param window_size: 窗口大小(秒)
:param threshold: 窗口内允许的最大请求数
"""
def __init__(self, window_size: float = 1.0, threshold: int = 10):
self.window_size = window_size
self.threshold = threshold
self._lock = threading.Lock()
self._window_start = time.time()
self._counter = 0
def allow_request(self) -> bool:
"""
判断当前请求是否允许通过
:return: True 表示放行,False 表示拒绝
"""
with self._lock:
now = time.time()
# 如果当前时间已超出窗口范围,重置窗口
if now - self._window_start >= self.window_size:
self._window_start = now
self._counter = 0
# 检查计数是否超过阈值
if self._counter < self.threshold:
self._counter += 1
return True
else:
return False
def reset(self):
"""手动重置窗口(用于测试或特殊场景)"""
with self._lock:
self._window_start = time.time()
self._counter = 0
使用建议: 在金融 API 测试中,建议将
window_size 设置为 1 秒,threshold 根据接口的 SLA 设定。例如,某行情接口承诺 100 QPS,则 threshold=100,window_size=1.0。
2.4 测试用例与运行效果
编写一个简单的测试脚本,模拟 15 个并发请求,观察限流器的行为:
def test_fixed_window():
limiter = FixedWindowRateLimiter(window_size=1.0, threshold=10)
allowed = 0
denied = 0
for i in range(15):
if limiter.allow_request():
allowed += 1
print(f"请求 {i+1}: 放行")
else:
denied += 1
print(f"请求 {i+1}: 拒绝 (429)")
print(f"\n结果:放行 {allowed} 次,拒绝 {denied} 次")
if __name__ == "__main__":
test_fixed_window()
预期输出(前 10 个请求放行,后 5 个请求被拒绝):
请求 1: 放行
请求 2: 放行
...
请求 10: 放行
请求 11: 拒绝 (429)
请求 12: 拒绝 (429)
请求 13: 拒绝 (429)
请求 14: 拒绝 (429)
请求 15: 拒绝 (429)
结果:放行 10 次,拒绝 5 次
2.5 优缺点分析
| 维度 | 说明 |
|---|---|
| 优点 |
|
| 缺点 |
|
2.6 边界效应与经典问题
固定窗口算法最著名的缺陷是“窗口边界突发”问题。假设阈值 T=10,窗口 W=1s。如果在第 1 秒的最后 100ms 内通过了 10 个请求,紧接着在第 2 秒的前 100ms 内又通过了 10 个请求,那么实际 200ms 内通过了 20 个请求,瞬时 QPS 达到 100,远超设定的 10 QPS。下图直观展示了这一现象:
金融场景风险: 边界突发可能导致交易接口在毫秒级窗口内承受两倍于预期的负载,引发数据库连接池耗尽或下游系统雪崩。在构建测试框架时,必须针对边界场景设计专门的压测用例,验证系统在窗口切换瞬间的稳定性。
2.7 适用场景与选型建议
- 推荐使用:
- 对突发流量容忍度较高的非核心接口(如日志上报、监控指标)。
- 单机限流场景,且 QPS 阈值较低(如 < 1000)。
- 快速原型验证或教学演示。
- 不建议使用:
- 金融核心交易链路(如订单、支付、风控),需要精确限流。
- 高并发场景(QPS > 10000),窗口切换瞬间的突发可能造成系统抖动。
- 分布式限流场景,需配合滑动窗口或令牌桶算法。