MST

星途 面试题库

面试题:安全认证 - 如何处理JWT速率限制中的多用户并发场景

假设你的系统中有大量用户同时访问API,在基于JWT进行API速率限制时,如何处理多用户并发场景,以确保速率限制的准确性和系统性能?请说明采用的技术方案和数据结构。
11.8万 热度难度
后端开发安全认证

知识考点

AI 面试

面试题答案

一键面试

技术方案

  1. 令牌桶算法:为每个用户分配一个令牌桶,令牌以固定速率生成并放入桶中。用户每次访问API时,从桶中取出一个令牌。如果桶中没有令牌,则拒绝访问。这样可以平滑地限制用户的访问速率。
  2. 使用缓存:将用户的令牌桶状态存储在缓存中,如Redis。缓存具有高读写性能,能够快速处理大量并发请求,保证系统性能。同时,缓存可以设置过期时间,方便管理用户的访问周期。

数据结构

  1. 哈希表:在缓存中,使用哈希表来存储每个用户的令牌桶信息。哈希表的键为用户ID,值为包含令牌桶状态(如当前令牌数量、上次更新时间等)的对象。
  2. 时间戳:记录令牌桶上次更新的时间,结合令牌生成速率,计算当前应该有的令牌数量。例如,在Java中可以使用System.currentTimeMillis()获取当前时间戳。

示例代码(Python + Redis实现)

import redis
import time

class TokenBucket:
    def __init__(self, capacity, rate, user_id):
        self.capacity = capacity
        self.rate = rate
        self.user_id = user_id
        self.redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)
        self.last_update = self.redis_client.get(f'{self.user_id}:last_update')
        if not self.last_update:
            self.redis_client.set(f'{self.user_id}:last_update', int(time.time()))
            self.redis_client.set(f'{self.user_id}:tokens', self.capacity)
        else:
            self.last_update = int(self.last_update)

    def get_tokens(self):
        now = int(time.time())
        # 计算新生成的令牌数
        new_tokens = (now - self.last_update) * self.rate
        current_tokens = int(self.redis_client.get(f'{self.user_id}:tokens'))
        current_tokens = min(current_tokens + new_tokens, self.capacity)
        self.redis_client.set(f'{self.user_id}:tokens', current_tokens)
        self.redis_client.set(f'{self.user_id}:last_update', now)
        return current_tokens

    def consume_token(self):
        tokens = self.get_tokens()
        if tokens >= 1:
            self.redis_client.decr(f'{self.user_id}:tokens')
            return True
        return False

在API处理逻辑中,可以这样使用:

# 假设capacity为100,rate为10(每秒生成10个令牌)
token_bucket = TokenBucket(100, 10, 'user123')
if token_bucket.consume_token():
    # 处理API请求
    print('API request processed')
else:
    print('Rate limit exceeded')