面试题答案
一键面试数据结构选择
- 有序集合(Sorted Set):用于记录每个请求的时间戳。有序集合的score字段可以存储时间戳,member字段可以存储请求的唯一标识(如请求ID)。这样可以方便地根据时间范围进行查询和统计。
- 字符串(String):用于记录当前窗口内的请求计数。可以使用一个键值对,键为API的标识,值为当前窗口内的请求数量。
主要实现步骤
- 初始化:
- 设定窗口大小
windowSize
(例如,60秒)和最大请求数maxRequests
。 - 创建一个有序集合键,例如
api:request:timestamps
,用于存储请求时间戳。 - 创建一个字符串键,例如
api:request:count
,初始值设为0,用于记录当前窗口内的请求数量。
- 设定窗口大小
- 请求到达时:
- 获取当前时间戳
currentTimestamp
。 - 将
currentTimestamp
作为score,请求唯一标识作为member添加到有序集合api:request:timestamps
中。 - 使用
ZREMRANGEBYSCORE
命令删除有序集合中时间戳小于currentTimestamp - windowSize
的元素,这些元素已经超出了当前滑动窗口。 - 使用
ZCARD
命令获取当前有序集合的元素数量,即当前窗口内的请求数量currentCount
。 - 判断
currentCount
是否大于maxRequests
。如果currentCount <= maxRequests
,则允许请求通过,并将api:request:count
的值更新为currentCount
;否则,拒绝请求。
- 获取当前时间戳
滑动窗口算法相较于固定窗口算法的优势
- 平滑限流:
- 固定窗口算法:存在临界问题。例如,窗口大小为1分钟,允许100次请求。如果在第59秒突然有100次请求,然后在第60秒到第61秒又有100次请求,实际上在这2秒内有200次请求,超过了预期的限流。
- 滑动窗口算法:通过不断滑动窗口,将时间窗口细化,能够更平滑地处理请求,避免临界问题。例如,将1分钟的窗口划分为多个小窗口(如10秒一个小窗口),即使在窗口切换时也能准确统计请求数量,不会出现请求突增导致的限流失效。
- 更精确的限流控制:
- 固定窗口算法:只能以固定的窗口粒度进行限流,无法精确到更小的时间单位。
- 滑动窗口算法:可以根据实际需求设置非常小的时间窗口粒度,从而实现更精确的限流控制,更符合复杂业务场景的需求。