Redis 常见使用场景与缓存问题
Redis 是一个开源的的内存数据结构存储系统,常用作数据库、缓存和消息代理。它支持多种数据结构,如字符串、哈希、列表、集合等,具备高性能和灵活性。
常见使用场景
1. 缓存
将热点数据存放在内存中,作为缓存对象以加速数据的读取,减轻数据库的负担。这种方法可以显著提高应用的响应速度,尤其是在频繁访问的数据场景中。
- 常见缓存策略:
- LRU(Least Recently Used):淘汰最少使用的缓存数据。
- TTL(Time To Live):设置缓存数据的有效时间,过期后自动删除。
2. 会话缓存
可以使用 Redis 来统一存储多台应用服务器的会话信息。通过将会话信息存储在 Redis 中,当应用服务器不再存储用户的会话信息时,系统变得无状态。这意味着用户可以请求任意一台应用服务器,这样更容易实现高可用性和可伸缩性。
- Redis会话缓存 的优势:
- 持久化:Redis 提供数据持久化机制(把内存中的数据写到磁盘中去),可以在服务器重启后恢复会话数据。
- 高并发:Redis 支持高并发访问,可以处理大量的会话请求。
- 跨区域访问:多个服务器可以共享同一份会话数据,方便跨区域部署。
3. 消息队列(发布/订阅功能)
Redis 的列表(List)或发布/订阅功能,使得系统能够轻松实现消息队列。 虽然 Redis 的 List 是一个双向链表,可以通过 LPUSH 和 RPOP 命令写入和读取消息,但在高并发和复杂场景下,使用专门的消息中间件,如 Kafka 或 RabbitMQ,通常更为合适。
- Redis List:
- 适合于简单的消息队列实现,易于使用且性能优越。
- 可以快速处理消息的推送和消费,适合较低并发的场景。
4. 排行榜
通过 Redis 的有序集合(ZSet),可以实现实时排行榜。每当用户获得新的分数或积分时,只需将该用户的分数更新到有序集合中,Redis 会自动维护排名。这种方式非常高效,可以支持大规模用户的实时排名需求。
- 实现方式:
- 使用
ZADD
命令将用户分数添加到有序集合中。 - 使用
ZRANGE
或ZREVRANGE
命令获取排名前 N 的用户。
- 使用
Redis 缓存问题
缓存穿透
缓存穿透是指客户端请求的数据在数据库中根本不存在,这样缓存永远不会生效,导致请求穿透缓存直接打到数据库,对数据库造成压力。
解决方案
缓存空对象
- 优点:实现简单,维护方便。
- 缺点:额外消耗内存(针对这个问题一般会设置一个较短的过期时间 TTL)。
-
- 通过使用布隆过滤器,可以在请求到达数据库之前先检查请求的数据是否存在于数据库中,减少无效请求对数据库的压力。
- 优点:内存占用少,没有多余key
- 缺点:实现复杂,存在误判可能
缓存雪崩
缓存雪崩是指在同一时间段大量的缓存 key 同时失效或者 Redis 服务宕机,导致大量请求直接到达数据库,造成数据库压力过大甚至宕机。这里与缓存击穿的区别在于,缓存击穿是指并发查同一条缓存 key 过期的数据,而缓存雪崩是缓存中大量不同数据同时过期,导致许多请求查不到数据,进而查数据库。
解决方案
- 给不同 key 的 TTL 加上一个随机值(例如 1-5 分钟)。
- 利用 Redis 集群 提高服务的可用性。
- 给缓存业务添加降级限流策略。
- 给业务添加多级缓存。
缓存击穿
缓存击穿问题也叫热点 key 问题,就是一个被高并发访问并且缓存重建业务较复杂的 key 突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
解决方案
- 互斥锁
- 优点:
- 没有额外的内存消耗
- 保证了数据的一致性
- 实现简单
- 缺点:
- 线程需要等待,性能受影响
- 可能有死锁的风险
- 优点:
- 逻辑过期:
- 优点:线程无需等待,性能较好
- 缺点:
- 不保证一致性
- 有额外的内存消耗
- 实现复杂