这是一道面试中常见的 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 实现消息队列没有广播机制的问题。

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

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

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

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

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

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

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

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

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

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

美团面试:Redis 除了缓存还能做什么?可以做消息队列吗?的更多相关文章

  1. Java+Redis 通过Lua 完成库存扣减,创建消息队列,异步处理消息--实战

    需要完成功能 借助redis Stream 数据结构实现消息队列,异步完成订单创建,其中涉及到了缓存(击穿,穿透,雪崩),锁(Redisson),并发处理,异步处理,Lua脚本 IDE:IDEA 20 ...

  2. 什么鬼,面试官竟然让我用Redis实现一个消息队列!!?

    GitHub 9.4k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 9.4k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 9.4k Star 的 ...

  3. 四、NOSQL之Redis持久化缓存服务基础实战第三部

    1.NOSQL的理解 NOSQL是不仅仅是SQL,说的就是sql的补充,但是不能替代SQL. nosql库:memcached.memcachedb.redis 2.redis 简介 Redis是一个 ...

  4. 使用Redis做消息队列

    基于内存的单线程数据库,使Redis的线程安全性极高.而Redis的双向链表数据类型(List)天生就可作为消息队列存储消息. 在这里就不说消息队列的等等一些优点.但是补充一下Redis的List类型 ...

  5. 用redis实现支持优先级的消息队列

    http://www.cnblogs.com/tianqiq/p/4309791.html http://www.cnblogs.com/it-cen/p/4312098.html http://ww ...

  6. [.NET领域驱动设计实战系列]专题八:DDD案例:网上书店分布式消息队列和分布式缓存的实现

    一.引言 在上一专题中,商家发货和用户确认收货功能引入了消息队列来实现的,引入消息队列的好处可以保证消息的顺序处理,并且具有良好的可扩展性.但是上一专题消息队列是基于内存中队列对象来实现,这样实现有一 ...

  7. Redis使用ZSET实现消息队列使用总结一

    转载请注明出处: 目录 1.zset为什么可以做消息队列 2.zset实现消息队列的步骤 3.使用jedis实现消息队列示例 4.+inf与-inf 5.redis使用list与zset做消息队列有什 ...

  8. Redis系列(五):消息队列

    消息队列已经成为现在互联网服务端的标配组件,现在比较常用的消息中间件有RabbitMQ.Kafka.RocketMQ.ActiveMQ.说出来你可能不信,Redis作为一个缓存中间件,居然也提供了消息 ...

  9. 别再用 Redis List 实现消息队列了,Stream 专为队列而生

    上回说到使用 Redis 的 List 实现消息队列有很多局限性,比如: 没有良好的 ACK 机制: 没有 ConsumerGroup 消费组概念: 消息堆积. List 是线性结构,想要查询指定数据 ...

  10. Redis笔记(七)Java实现Redis消息队列

    这里我使用Redis的发布.订阅功能实现简单的消息队列,基本的命令有publish.subscribe等. 在Jedis中,有对应的java方法,但是只能发布字符串消息.为了传输对象,需要将对象进行序 ...

随机推荐

  1. 基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发1-通用框架

    基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发1-通用框架 Avalonia简介: Avalonia是.NET的一个跨平台UI框架,提供了一个灵活的样式系统,支持广泛的操作 ...

  2. pycharm:插件translation 更新TTK失败

    解决方案 1.修改C:\Windows\System32\drivers\etc 下hosts文件, 添加 203.208.40.66 translate.google.com 203.208.40. ...

  3. ubuntu 安装sublime

    Install the GPG key: wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key ad ...

  4. js中的函数式编程

    函数是javascript中非常重要的一部分,用途也非常的多,可作为参数.返回值.回调等等,下面有一些函数式编程的重要概念和定义 纯函数 纯函数属于程序设计的名词,其它语言中也是存在的,而在javas ...

  5. MIT6.s081/6.828 lectrue4:page tables 以及 Lab3 心得

    不管是计算机组成还是操作系统,虚拟内存都是其中的重要内容,所以这一节我会结合 CSAPP 第九章:虚拟内存 来一起复习(顺便一说,CSAPP 这一节的 lab 是要求设计一个内存分配器,也是很有意思的 ...

  6. Programming abstractions in C阅读笔记p111-p113: boilerplate

    <Programming Abstractions In C>学习第47天,p111-p113,总结如下: 一.技术总结 1.boilerplate /* * File: random.h ...

  7. nlp入门(五)隐马尔科夫模型

    源码请到:自然语言处理练习: 学习自然语言处理时候写的一些代码 (gitee.com) 一.马尔科夫模型概念 1.1 马尔科夫模型:具有马尔可夫性质并以随机过程为基础的模型 1.2 马尔科夫性质:过去 ...

  8. 解放生产力orm并发更新下应该这么处理求求你别再用UpdateById了

    解放生产力orm并发更新下应该这么处理求求你别再用UpdateById了 背景 很多时候为了方便我们都采用实体对象进行前后端的数据交互,然后为了便捷开发我们都会采用DTO对象进行转换为数据库对象,然后 ...

  9. [远程Call]32位远程多参数带返回调用

    [远程Call]32位远程多参数带返回调用 引子 在Windows上可以使用CreateRemoteThread实现远程Call,但是有不带返回值且只能传递一个参数的限制. 解决思路 将多个参数利用V ...

  10. 线段树hdu-4027

    Smiling & Weeping   ---- 姑娘,倘若,我双手合十的愿望里有你呢 Problem Description A lot of battleships of evil are ...