Redis 使用场景:缓存、队列与限流
你已经构建了一个在开发环境中运行良好的 Web 应用,但随着流量增长,你注意到响应时间变慢和数据库过载。罪魁祸首通常是重复的昂贵操作:从数据库获取相同数据、同步处理任务,或允许滥用请求速率。Redis 是一个内存数据存储,为这些问题提供了优雅的解决方案。在本文中,我们将探讨三个实用的 Redis 使用场景:缓存、队列和限流。你将通过代码示例学习如何实现每种模式,并理解何时应用它们。
为什么选择 Redis?
Redis 是一个开源的内存键值存储,以其速度和多功能性而闻名。它支持字符串、列表、集合和哈希等数据结构,使其适用于简单缓存之外的多种任务。由于它将数据保存在内存中,Redis 提供亚毫秒级延迟,非常适合高性能场景。它还提供持久化选项,因此重启时不会丢失数据。让我们深入了解这三个使用场景。
1. 使用 Redis 进行缓存
缓存是最常见的 Redis 使用场景。思路很简单:将昂贵操作(如数据库查询或 API 调用)的结果存储在 Redis 中,并在后续请求中直接提供这些结果。这减少了对主数据库的负载并加快了响应时间。
如何实现缓存
- 检查缓存:在访问数据库之前,使用唯一键(例如
user:123)查询 Redis 获取数据。 - 如果找到(缓存命中):立即返回缓存数据。
- 如果未找到(缓存未命中):从数据库获取数据,将其存储在 Redis 中并设置过期时间(TTL),然后返回。
以下是使用 redis-py 的 Python 示例:
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0)
def get_user(user_id):
cache_key = f'user:{user_id}'
cached = r.get(cache_key)
if cached:
return json.loads(cached)
# 模拟数据库获取
user = fetch_user_from_db(user_id)
r.setex(cache_key, 3600, json.dumps(user)) # 缓存 1 小时
return user
最佳实践:选择有意义的键,设置适当的 TTL 以避免数据过时,并考虑缓存失效策略。对于读密集型工作负载,缓存可以将数据库负载减少几个数量级。
2. 使用 Redis 实现队列
队列将耗时的任务从请求-响应周期中解耦。例如,发送电子邮件、处理图像或生成报告可以异步完成。Redis 列表或流非常适合实现简单队列。
实现基本队列
使用 LPUSH 将任务添加到列表左侧,使用 BRPOP 阻塞并从右侧弹出。这创建了一个 FIFO 队列。
# 生产者:添加任务
r.lpush('email_queue', json.dumps({'to': 'user@example.com', 'subject': 'Welcome'}))
# 消费者:处理任务
while True:
_, job = r.brpop('email_queue', timeout=30)
if job:
process_email(json.loads(job))
对于更高级的需求,Redis Streams 提供消费者组、确认和可重放性,使其适用于健壮的消息处理。
3. 使用 Redis 进行限流
限流保护你的 API 免受滥用并确保公平使用。Redis 的原子操作使得实现自动过期的计数器变得容易。
固定窗口限流
在固定窗口方法中,你允许每个时间窗口 N 个请求(例如,每个 IP 每小时 100 个请求)。使用 INCR 和 EXPIRE:
def is_allowed(ip, limit=100, window=3600):
key = f'rate:{ip}'
current = r.incr(key)
if current == 1:
r.expire(key, window)
return current