面试题答案
一键面试权重分配逻辑设计
- 用户维度:通常用户是核心主体,若应用主要面向个人用户,且希望重点限制单个用户行为,可给予较高权重。比如业务是内容发布,为防止单个用户大量发布垃圾信息,将用户维度权重设为 5。
- IP 维度:主要用于防止恶意 IP 攻击。若网络环境复杂,存在大量代理 IP 等情况,可适当给予较低权重,如设为 3,以避免误判正常用户行为。
- 设备维度:可作为辅助维度,若应用在多种设备上使用,为防止单个设备异常操作,权重设为 2。
利用 Redis 数据结构和命令实现
- 数据结构选择
- 使用 Redis 的
Hash
结构存储每个维度的限流信息。例如,以limit:{key}
作为Hash
的 key,其中key
可以是用户 ID、IP 地址或设备 ID。Hash
的 field 存储时间窗口相关信息,value 存储对应时间窗口内的访问次数。 - 例如,
limit:user:1
这个Hash
结构,field 为10s
(表示 10 秒时间窗口),value 为3
(表示 10 秒内访问了 3 次)。
- 使用 Redis 的
- 实现步骤
- 初始化限流数据:在系统启动或用户首次访问时,为每个维度的 key 在 Redis 中创建对应的
Hash
结构,并初始化时间窗口内的访问次数为 0。
import redis r = redis.Redis(host='localhost', port=6379, db=0) def init_limit(key, time_windows): data = {window: 0 for window in time_windows} r.hmset(f'limit:{key}', data)
- 每次请求处理:每次请求到达时,根据请求的用户 ID、IP 地址和设备 ID 获取对应的
Hash
结构,更新相应时间窗口内的访问次数。
def incr_limit(key, time_window): current_count = r.hincrby(f'limit:{key}', time_window, 1) return current_count
- 限流判断:根据权重分配,计算总访问次数,与设定的限流阈值比较。假设用户权重为
user_weight
,IP 权重为ip_weight
,设备权重为device_weight
,限流阈值为threshold
。
def check_limit(user_key, ip_key, device_key, time_window, user_weight, ip_weight, device_weight, threshold): user_count = r.hget(f'limit:{user_key}', time_window) ip_count = r.hget(f'limit:{ip_key}', time_window) device_count = r.hget(f'limit:{device_key}', time_window) total_count = (int(user_count) if user_count else 0) * user_weight + \ (int(ip_count) if ip_count else 0) * ip_weight + \ (int(device_count) if device_count else 0) * device_weight return total_count <= threshold
- 初始化限流数据:在系统启动或用户首次访问时,为每个维度的 key 在 Redis 中创建对应的
通过上述设计和实现,可以在 Redis 中实现多维度带权重的限流。