内容概览:
Redis 除了做缓存,还能做什么?
分布式锁:通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁。限流:一般是通过 Redis + Lua 脚本的方式来实现限流。消息队列: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这样的方式存在性能问题,我们需要不断轮询去调用 RPOP 或 LPOP 来消费消息。当 List 为空时,大部分的轮询的请求都是无效请求,这种方式大量浪费了系统资源。
因此,Redis 还提供了 BLPOP、BRPOP 这种阻塞式读取的命令(带 B-Bloking 的都是阻塞式),并且还支持一个超时参数。如果 List 为空,Redis 服务端不会立刻返回结果,它会等待 List 中有新数据后在返回或者是等待最多一个超时时间后返回空。如果将超时时间设置为 0 时,即可无限等待,直到弹出消息
# 超时时间为 10s# 如果有数据立刻返回,否则最多等待10秒> BRPOP myList 10nullList 实现消息队列功能太简单,像消息确认机制等功能还需要我们自己实现,最要命的是没有广播机制,消息也只能被消费一次。
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。