MST

星途 面试题库

面试题:Redis限流中如何避免频繁触发限流规则

在使用Redis实现限流的场景下,描述一种避免频繁触发限流规则的有效措施,并阐述其原理,同时说明如何在代码中实现(可使用你熟悉的编程语言示例)。
41.5万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

避免频繁触发限流规则的有效措施及原理

  1. 措施:采用滑动窗口算法。
  2. 原理:传统的固定窗口限流算法在窗口切换时可能会出现流量突增的情况。例如,在固定窗口限流为每分钟100次请求的情况下,在第59秒有100次请求,第60秒有100次请求,虽然在两个独立的固定窗口内都没有超出限制,但实际上这1秒内产生了200次请求,这可能导致系统负载瞬间过高。而滑动窗口算法将时间窗口进行细分,比如把1分钟的窗口细分为60个1秒的小窗口。当请求进来时,不是简单的基于整个1分钟窗口计数,而是根据当前时间确定落在哪个小窗口内,并且统计当前窗口及之前部分窗口内的请求总数,以此判断是否超出限流阈值。这样可以使限流更加平滑,避免在窗口切换时流量突然增大,从而有效避免频繁触发限流规则。

代码实现(以Python为例)

import redis
import time


class SlidingWindowRateLimiter:
    def __init__(self, redis_client, key, capacity, window_size, sub_window_count):
        self.redis_client = redis_client
        self.key = key
        self.capacity = capacity
        self.window_size = window_size
        self.sub_window_count = sub_window_count
        self.sub_window_size = window_size / sub_window_count

    def is_allowed(self):
        current_time = int(time.time())
        sub_window_index = int(current_time % self.window_size / self.sub_window_size)
        pipe = self.redis_client.pipeline()
        for i in range(self.sub_window_count):
            sub_window_key = f"{self.key}:{sub_window_index - i}" if sub_window_index - i >= 0 else f"{self.key}:{self.sub_window_count + sub_window_index - i}"
            pipe.get(sub_window_key)
        counts = pipe.execute()
        total_count = sum(int(count) if count else 0 for count in counts)
        if total_count >= self.capacity:
            return False
        pipe = self.redis_client.pipeline()
        sub_window_key = f"{self.key}:{sub_window_index}"
        pipe.incr(sub_window_key)
        pipe.expire(sub_window_key, self.sub_window_size)
        pipe.execute()
        return True


# 使用示例
if __name__ == "__main__":
    r = redis.Redis(host='localhost', port=6379, db=0)
    limiter = SlidingWindowRateLimiter(r, "test_limit_key", 100, 60, 60)
    for _ in range(150):
        if limiter.is_allowed():
            print("请求通过")
        else:
            print("请求被限流")

在上述代码中,SlidingWindowRateLimiter类实现了滑动窗口限流逻辑。构造函数初始化了Redis客户端、限流的键、容量、窗口大小以及子窗口数量。is_allowed方法首先确定当前请求所在的子窗口索引,然后从Redis中获取当前及之前子窗口的请求计数,计算总请求数并判断是否超出限流容量。如果未超出,则增加当前子窗口的请求计数并设置过期时间;如果超出,则返回请求被限流。