Redis的15种常用场景
1. 缓存
Redis最常见的用途是作为缓存,用于加速应用程序的响应速度。
把频繁访问的数据放在内存中,可以减少对后端数据库的访问压力。如热点数据缓存(明星出轨),对象缓存、全页缓存、可以提升热点数据的访问速度。
SET user:1001 "{name: 'Alice', age: 30}" EX 3600 #设置1小时过期时间
2.分布式锁
日常开发中,我们经常会使用Redis做为分布式锁。可以在分布式系统中协调多节点对共享资源的访问,确保操作的原子性。
用redisson写了个分布式锁模板:
public <T> T executeWithLock(String lockKey, long timeout, Callable<T> action) {
RLock lock = redissonClient.getLock(lockKey);
boolean isLock = false;
try {
// 尝试获取锁,最大等待时间1秒,锁自动释放时间为timeout秒
isLock = lock.tryLock(1, timeout, TimeUnit.SECONDS);
if (isLock) {
try {
// 执行传入的操作并返回结果
return action.call();
} finally {
// 检查是否持有锁再释放
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
} else {
System.out.println("未能获取锁,稍后重试");
return null; // 或者抛出异常
}
} catch (InterruptedException e) {
// 处理异常,恢复线程中断状态
Thread.currentThread().interrupt();
System.out.println("获取锁时被中断");
return null; // 或者抛出异常
} catch (Exception e) {
// 处理其他异常
System.out.println("执行操作时发生异常: " + e.getMessage());
return null; // 或者抛出异常
}
}
3. 排行榜
redis 经常用来做排行榜,比如游戏积分实时排名、直播送礼排名等等。
可以基于Sorted Set
来实现:
实时排名更新:
ZADD game_leaderboard 1000 "player_1" # 插入分数
ZINCRBY game_leaderboard 50 "player_1" # 增加分数
ZREVRANGE game_leaderboard 0 9 WITHSCORES # 获取Top10
4. 计数器
redis 也经常应用作为计数器,如文章的阅读量、微博点赞数等等。
# 用户 1001 点赞文章 123
SADD article:123:likes 1001
# 获取文章 123 的点赞数
SCARD article:123:likes
# 检查用户 1001 是否点赞了文章 123
SISMEMBER article:123:likes 1001
# 用户 1001 取消点赞文章 123
SREM article:123:likes 1001
5. 消息队列
Redis 可以作为消息队列使用,特别是使用其 List 数据结构以及相关的阻塞操作(BLPOP 和 BRPOP)。这些操作使得 Redis 成为一种简单、高效的消息队列解决方案,广泛用于消息传递、任务队列等场景。
假设你有一个队列 task_queue
:
生产者(Producer)向队列中添加任务:
bash
LPUSH task_queue "task1"
LPUSH task_queue "task2"
消费者(Consumer)从队列中取出任务,设置超时为 5 秒:
bash
BLPOP task_queue 5
6.会话管理
Redis 非常适合用作 会话管理,尤其是在分布式应用中。
-
分布式会话:解决多服务器间 Session 共享问题。
-
快速失效:通过 EXPIRE 实现自动会话清理。
HSET session:abBitmapc123 user_id 1001 last_active 1690000000
EXPIRE session:abc123 1800 # 30分钟过期
7. Bitmap 记录签到
Redis Bitmap
是一种非常适合用于签到系统的数据结构。它通过位图(bit array)存储和操作数据,可以高效地处理大量的签到操作,特别适合于需要频繁更新并查询某个用户是否已签到的场景。
假设每个用户的签到状态通过 位图(Bitmap) 记录,每个用户对应一个唯一的 ID,通过设置和查询位来确定该用户是否签到。
设置用户 101 已签到
SETBIT sign_in_bitmap 101 1
比如查询用户 ID 为 101 的签到状态
GETBIT sign_in_bitmap 101
统计总共有多少用户已签到
BITCOUNT sign_in_bitmap
8. 地理位置服务
Redis 可以作为地理位置服务(Geolocation Service)的存储和查询引擎。Redis 提供了 GEO 数据结构,专门用于存储和查询地理位置信息。
比如类似场景:
用户打开 App,查找当前位置附近的餐厅或商店。
# 添加餐厅地理位置
GEOADD restaurants 13.361389 38.115556 "餐厅A"
GEOADD restaurants 15.087269 37.502669 "餐厅B"
GEOADD restaurants 9.191383 45.464211 "餐厅C"
# 用户当前位置:经纬度 (14, 37)
# 查找附近 100 公里内的餐厅
GEORADIUS restaurants 14 37 100 km
# 返回:餐厅A 餐厅B
9. 限流
Redis 适合用于限流(Rate Limiting)场景。限流的目的是控制某个操作在特定时间内的访问频率,比如 API 请求、短信发送、登录尝试等。Redis 的原子操作和高效性能使其成为实现限流的理想工具。
比如使用 Redis 实现滑动窗口计数器
-
使用 Redis 的 ZSET(有序集合)存储每次请求的时间戳。
-
每次请求时,移除时间窗口外的旧记录,并添加新记录。
-
统计当前时间窗口内的记录数,如果超过阈值则拒绝请求。
def sliding_window_rate_limit(user_id, limit=10, window_size=60):
"""
滑动窗口限流函数
:param user_id: 用户 ID
:param limit: 时间窗口内的最大请求数
:param window_size: 时间窗口大小(秒)
:return: True(允许请求)或 False(拒绝请求)
"""
key = f"rate_limit:{user_id}"
current_time = int(time.time())
window_start = current_time - window_size
# 移除时间窗口外的旧记录
redis_client.zremrangebyscore(key, 0, window_start)
# 添加当前请求的时间戳
redis_client.zadd(key, {current_time: current_time})
# 统计时间窗口内的请求数
request_count = redis_client.zcard(key)
if request_count > limit:
return False # 超过阈值,拒绝请求
return True # 允许请求
# 测试滑动窗口限流
user_id = "user123"
for i in range(15):
if sliding_window_rate_limit(user_id, limit=10, window_size=60):
print(f"请求 {i + 1}:允许")
else:
print(f"请求 {i + 1}:拒绝")
time.sleep(1) # 模拟请求间隔
10. 发布订阅
实时消息广播
# 订阅频道
SUBSCRIBE news_updates
# 发布消息
PUBLISH news_updates "Breaking: Redis 7.0 released!"
11. 延迟任务(Delayed Task)
Redis 可以作为延迟任务的实现工具。
-
基于 Sorted Set 的延迟任务。
利用 Sorted Set 的 有序性 和 范围查询 特性,将任务的执行时间作为分数(score),任务数据作为成员(member),定时轮询获取到期的任务。
-- 添加延迟任务:
ZADD delayed_tasks <timestamp> "task_data"
-- 定时轮询获取到期任务
ZRANGEBYSCORE delayed_tasks 0 <current_timestamp>
12.全局ID
在分布式系统中生成唯一ID。
基于 INCR:
INCR global_id # 返回唯一ID
基于雪花算法:
SET global_id_snowflake 0
INCR global_id_snowflake
13. 推荐模型
基于用户行为推荐商品。
基于Sorted Set:
ZADD recommendations:user1001 0.9 "product_1" 0.8 "product_2"
ZRANGE recommendations:user1001 0 9 WITHSCORES
14. 用户关注
之前在第一个公司上班的时候,看到代码,有使用redis去维护用户关注、粉丝的关系。
SADD user:1001:followers "user2"
SADD user:1002:following "user1"
15. 用户消息时间线(Timeline)
Redis适合实现用户消息时间线(Timeline)功能.用户消息时间线通常用于展示用户动态、朋友圈、微博等场景,核心需求是按时间顺序存储和展示用户的相关消息或动态。
-- 使用 LPUSH 将新消息插入到时间线的头部:
LPUSH timeline:user1001 "New post: Hello, Redis!"
-- 使用 LRANGE 获取指定范围内的消息:
LRANGE timeline:user1001 0 9 # 获取最新的10条消息