Skip to content

redis常见使用场景

约 1990 字大约 7 分钟

2025-05-25

缓存

这个场景式极高频的场景, 一般是为了提高系统的性能, 减少数据库的压力, 注意合理设置缓存时长以及大Key相关问题即可, 不做过多赘述.

分布式锁

利用已存在的key无法重复设置的原理, 实现分布式锁, 一般是为了防止重复操作, 例如: 防止重复下单, 防止重复发送短信等.

  • EX: 设置键的过期时间(单位为秒)
  • PX: 设置键的过期时间(单位为毫秒)
  • NX: 仅在键不存在时设置键 SET key value NX 效果等同于 SETNX key value
  • XX: 仅在键已存在时设置键

分布式锁有一些需要注意事项:

  • 锁的超时时间: 锁的超时时间是为了防止死锁, 当锁的持有者出现异常时, 锁不会一直存在, 避免死锁.
  • 锁的释放: 锁的释放是为了防止死锁, 当锁的持有者出现异常时, 锁不会一直存在, 避免死锁. 注意锁的时间过期会自动释放, 主动释放时, 注意确定锁是否是当前持有者, 避免误释放.
  • 锁的粒度: 锁的粒度是为了防止锁的冲突, 当锁的粒度过大时, 锁的冲突会非常严重, 影响性能.
  • 锁的重试: 锁的重试是为了能最大可能自动获取.
  • 锁的续期: 锁的续期是为了防止锁的过期, 如 锁的时间是 1s , 但是业务处理时间超过 1s , 为了避免并发操作引起异常, 这时候就需要锁的续期.

计数器(incr)

计数器使用与一些博客或者社交类产品, 例如:文章的阅读量、微博点赞数、允许一定的延迟,先写入Redis再定时同步到数据库

计数功能应该是最适合 Redis 的使用场景之一了,因为它高频率读写的特征可以完全发挥 Redis 作为内存数据库的高效。在 Redis 的数据结构中,string、hash和sorted set都提供了incr方法用于原子性的自增操作,下面举例说明一下它们各自的使用场景:

  • 如果应用需要显示每天的注册用户数,便可以使用string作为计数器,设定一个名为REGISTERED_COUNT_TODAY的 key,并在初始化时给它设置一个到凌晨 0 点的过期时间,每当用户注册成功后便使用incr命令使该 key 增长 1,同时当每天凌晨 0 点后,这个计数器都会因为 key 过期使值清零。
  • 每条微博都有点赞数、评论数、转发数和浏览数四条属性,这时用hash进行计数会更好,将该计数器的 key 设为weibo:weibo_id,hash的 field 为like_number、comment_number、forward_number和view_number,在对应操作后通过hincrby使hash 中的 field 自增。
  • 如果应用有一个发帖排行榜的功能,便选择sorted set吧,将集合的 key 设为POST_RANK。当用户发帖后,使用zincrby将该用户 id 的 score 增长 1。sorted set会重新进行排序,用户所在排行榜的位置也就会得到实时的更新。

留存率、活跃度、日活、月活(BitMap)

任务队列

Redis 中list的数据结构实现是双向链表,所以可以非常便捷的应用于消息队列(生产者 / 消费者模型)。消息的生产者只需要通过lpush将消息放入 list,消费者便可以通过rpop取出该消息,并且可以保证消息的有序性。如果需要实现带有优先级的消息队列也可以选择sorted set。

时间轴

list作为双向链表,不光可以作为队列使用。如果将它用作栈便可以成为一个公用的时间轴。

  • 当用户发完微博后,都通过lpush将它存放在一个 key 为LATEST_WEIBO的list中,之后便可以通过lrange取出当前最新的微博。为了保证数据不会无限扩大, 维持一个后台任务, 定时清理数据即可.
  • 各种产品的最新公告等场景

点赞、签到 、打卡

加入一条微博ID是 wb1001,用户ID是 u3001

用 like:wb1001 来维护 wb1001 这条微博的所有点赞用户

  • 点赞了这条微博:sadd like:wb1001 u3001
  • 取消点赞:srem like:wb1001 u3001
  • 是否点赞:sismember like:wb1001 u3001
  • 点赞的所有用户:smembers like:t1001
  • 点赞数:scard like:wb1001

商品标签

这个需求本质还是利用 sadd 命令实现, 更多会出现在涉及到分类的场景

好友关系、用户关注、推荐模型

这个场景最开始是是一篇介绍微博 Redis 应用的 PPT 中看到的,其中提到微博的 Redis 主要是用在在计数和好友关系两方面上,当时对好友关系方面的用法不太了解,后来看到《Redis 设计与实现》中介绍到作者最开始去使用 Redis 便是希望能通过set解决传统数据库无法快速计算集合中交集这个功能。后来联想到微博当前的业务场景,确实能够以这种方式实现,所以姑且猜测一下:

对于一个用户 A,将它的关注和粉丝的用户 id 都存放在两个 set 中:

A:follow:存放 A 所有关注的用户 id

A:follower:存放 A 所有粉丝的用户 id

那么通过sinter命令便可以根据A:follow和A:follower的交集得到与 A 互相关注的用户。当 A 进入另一个用户 B 的主页后,A:follow和B:follow的交集便是 A 和 B 的共同专注,A:follow和B:follower的交集便是 A 关注的人也关注了 B。

举例 follow 关注 fans 粉丝

相互关注:

sadd 1:follow 2 sadd 2:fans 1 sadd 1:fans 2 sadd 2:follow 1 我关注的人也关注了他(取交集):

sinter 1:follow 2:fans 可能认识的人:

用户1可能认识的人(差集):sdiff 2:follow 1:follow 用户2可能认识的人:sdiff 1:follow 2:follow

任务调度

流控

消息队列(pub/sub)

而pub/sub功能也可以用作发布者 / 订阅者模型的消息。但是需要注意, 一旦消费者退出, 便只能重新连接后从最新数据开始消费, 无法保证消息的可靠性.

排行榜

使用sorted set(有序set)和一个计算热度的算法便可以轻松打造一个热度排行榜,zrevrangebyscore可以得到以分数倒序排列的序列,zrank可以得到一个成员在该排行榜的位置(是分数正序排列时的位置,如果要获取倒序排列时的位置需要用zcard-zrank)。

id 为6001 的新闻点击数加1:

zincrby hotNews:20190926 1 n6001 1 获取今天点击最多的15条:

zrevrange hotNews:20190926 0 15 withscores 1

倒排索引

倒排索引是构造搜索功能的最常见方式,在 Redis 中也可以通过set进行建立倒排索引,这里以简单的拼音 + 前缀搜索城市功能举例:

假设一个城市北京,通过拼音词库将北京转为beijing,再通过前缀分词将这两个词分为若干个前缀索引,有:北、北京、b、be…beijin和beijing。将这些索引分别作为set的 key(例如:index:北)并存储北京的 id,倒排索引便建立好了。接下来只需要在搜索时通过关键词取出对应的set并得到其中的 id 即可。

基于空间坐标检索

geo 特性

布隆过滤器

防止使用不存在ID反复查询, 导致缓存穿透, 服务压力增大

Released under the MIT License.