美团面试:Redis 除了缓存还能做什么?可以做消息队列吗?


JavaGuide 官方网站javaguide.cn

这是一道面试中常见的 Redis 基础面试题,主要考察求职者对于 Redis 应用场景的了解。

即使不准备面试也建议看看,实际开发中也能够用到。

内容概览:

Redis 除了做缓存,还能做什么?

  • 分布式锁:通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁。关于 Redis 实现分布式锁的详细介绍,可以看我写的这篇文章:如何基于 Redis 实现分布式锁?
  • 限流:一般是通过 Redis + Lua 脚本的方式来实现限流。相关阅读:《我司用了 6 年的 Redis 分布式限流器,可以说是非常厉害了!》
  • 消息队列:Redis 自带的 List 数据结构可以作为一个简单的队列使用。Redis 5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。它比较类似于 Kafka,有主题和消费组的概念,支持消息持久化以及 ACK 机制。
  • 延时队列:Redisson 内置了延时队列(基于 Sorted Set 实现的)。
  • 分布式 Session :利用 String 或者 Hash 数据类型保存 Session 数据,所有的服务器都可以访问。
  • 复杂业务场景:通过 Redis 以及 Redis 扩展(比如 Redisson)提供的数据结构,我们可以很方便地完成很多复杂的业务场景比如通过 Bitmap 统计活跃用户、通过 Sorted Set 维护排行榜。
  • ……

如何基于 Redis 实现分布式锁?

关于 Redis 实现分布式锁的详细介绍,可以看我写的这篇文章:如何基于 Redis 实现分布式锁?

Redis 可以做消息队列么?

实际项目中也没见谁使用 Redis 来做消息队列,对于这部分知识点大家了解就好了。

先说结论:可以是可以,但不建议使用 Redis 来做消息队列。和专业的消息队列相比,还是有很多欠缺的地方。

Redis 2.0 之前,如果想要使用 Redis 来做消息队列的话,只能通过 List 来实现。

通过 RPUSH/LPOP 或者 LPUSH/RPOP即可实现简易版消息队列:

# 生产者生产消息
> RPUSH myList msg1 msg2
(integer) 2
> RPUSH myList msg3
(integer) 3
# 消费者消费消息
> LPOP myList
"msg1"

不过,通过 RPUSH/LPOP 或者 LPUSH/RPOP这样的方式存在性能问题,我们需要不断轮询去调用 RPOPLPOP 来消费消息。当 List 为空时,大部分的轮询的请求都是无效请求,这种方式大量浪费了系统资源。

因此,Redis 还提供了 BLPOPBRPOP 这种阻塞式读取的命令(带 B-Bloking 的都是阻塞式),并且还支持一个超时参数。如果 List 为空,Redis 服务端不会立刻返回结果,它会等待 List 中有新数据后在返回或者是等待最多一个超时时间后返回空。如果将超时时间设置为 0 时,即可无限等待,直到弹出消息

# 超时时间为 10s
# 如果有数据立刻返回,否则最多等待10秒
> BRPOP myList 10
null

List 实现消息队列功能太简单,像消息确认机制等功能还需要我们自己实现,最要命的是没有广播机制,消息也只能被消费一次。

Redis 2.0 引入了发布订阅 (pub/sub) 功能,解决了 List 实现消息队列没有广播机制的问题。

Redis 发布订阅 (pub/sub) 功能

pub/sub 中引入了一个概念叫 channel(频道),发布订阅机制的实现就是基于这个 channel 来做的。

pub/sub 涉及发布者(Publisher)和订阅者(Subscriber,也叫消费者)两个角色:

  • 发布者通过 PUBLISH 投递消息给指定 channel。
  • 订阅者通过SUBSCRIBE订阅它关心的 channel。并且,订阅者可以订阅一个或者多个 channel。

我们这里启动 3 个 Redis 客户端来简单演示一下:

pub/sub 实现消息队列演示

pub/sub 既能单播又能广播,还支持 channel 的简单正则匹配。不过,消息丢失(客户端断开连接或者 Redis 宕机都会导致消息丢失)、消息堆积(发布者发布消息的时候不会管消费者的具体消费能力如何)等问题依然没有一个比较好的解决办法。

为此,Redis 5.0 新增加的一个数据结构 Stream 来做消息队列。Stream 支持:

  • 发布 / 订阅模式
  • 按照消费者组进行消费
  • 消息持久化( RDB 和 AOF)

Stream 使用起来相对要麻烦一些,这里就不演示了。而且,Stream 在实际使用中依然会有一些小问题不太好解决比如在 Redis 发生故障恢复后不能保证消息至少被消费一次。

综上,和专业的消息队列相比,使用 Redis 来实现消息队列还是有很多欠缺的地方比如消息丢失和堆积问题不好解决。因此,我们通常建议不要使用 Redis 来做消息队列,你完全可以选择市面上比较成熟的一些消息队列比如 RocketMQ、Kafka。

相关阅读:Redis 消息队列发展历程 - 阿里开发者 - 2022

更多 Redis 面试问题,大家可以去 JavaGuide(javaguide.cn)上阅读对应的文章。

··············  END  ··············

👉专属面试小册/一对一提问/简历修改/专属求职指南/学习打卡,欢迎加入 JavaGuide 官方知识星球 认真维护接近四年了

准备 Java 面试的小伙伴可以看看《Java面试指北》(已更新完毕),原创内容,质量很高,和 JavaGuide 开源版(javaguide.cn)的内容互补。

👉 近期文章精选

相关推荐

  • Node.js 21发布,升级V8引擎,带来稳定的WebSteams模块和Test Runner
  • 技术与实体加速融合,企业转型的新挑战和新机遇在哪?
  • 11 月 19-20 日,一场真正的金融科技峰会来了 | FCon
  • 是时候基于云重新设计 Kafka 了!AutoMQ 如何实现 Kafka 十倍的降本增效
  • 疯狂马斯克的“极限”计划居然成功了?!“下云”后成本降低 60%,部分功能代码精简 90%,30 天急速迁移服务器
  • 大模型工程与应用
  • 2023“数智杯”创新应用大赛,大数据人才竞技,引领产业创新
  • 抖音云原生向量数据库从“非主流”到“新常态”的演变
  • 写了个爬虫,赚了4w9!
  • 一张老截图,让我老泪纵横。。。
  • 高精地图 为什么从“小甜甜”变成了“牛夫人”?
  • 【深度学习】收藏 | 医学图像开源数据集汇总
  • 明目张胆!高校教授收到陌生邮件“我评审了你的论文,给我挂上名!”
  • 2024年,三维重建方向还能发顶会吗?(赠CV系列课程+书籍)
  • MySQL innoDB 间隙锁产生的死锁问题
  • RecSys'23 谷歌 | 召回负反馈建模
  • 效率提升 100%,一款效果炸裂的白板神器!
  • 被忽略的缓存 -bfcache
  • zSet实现排行榜功能
  • 前OpenAI科学家:走一步看一步,未定目标也有路?!