Redis是否可以作为消息队列?
关于Redis能不能做消息队列,主要是解决以下两个问题
- 能否保证消息不丢失
- 消息是否能够堆积
使用List作为消息队列
如果使用Redis作为消息队列,那么首先会使用List这个数据类型。生产者将数据放入List中,消费者从List中读取数据。
那么会产生一个问题:消费者需要不断地从消息队列中读取数据。如果队列为空,那么就会出现CPU空转的情况。如果解决这个空转的问题呢?有两种方式
- 如果消息队列为空,那么就先让消费者休息一会,然后再尝试读取数据。这样又会引入一个问题,就是新的消息来了,消费者处理消息会存在延迟。
- 如果队列为空,消费者在拉取消息时就「阻塞等待」,一旦有新消息过来,就通知我的消费者立即处理新消息。Redis提供了阻塞式拉取消息的命令:BRPOP/BLPOP
缺点
- 不支持重复消费
- 消息丢失:消费者拉取到消息后,如果发生异常宕机,那这条消息就丢失了
使用发布订阅模型
Redis提供了PUBLISH/SUBSCRIBE 命令,来完成发布、订阅的操作。
Pub/Sub 最大的优势就是,支持多组生产者、消费者处理消息。
缺点
- 可能会导致信息丢失,消费者向队列发布消息,Redis就会转发给消费者的。这个过程是实时的,不存在任何的数据存储。
- 无法处理消息堆积。当消息积压时,有可能会导致消费失败和消息丢失。当生产者发布消息时,Redis先把消息写到对应消费者的缓冲区中。之后,消费者不断地从缓冲区读取消息,处理消息。
Redis新的数据类型Stream
Stream通过XADD和XREAD完成最简单的生产、消费模型:
- XADD:发布消息
- XREAD:读取消息
特点
- 支持「阻塞式」拉取消息
- 支持发布/订阅模式
- 保证消息不丢失,重新消费。当一组消费者处理完消息后,需要执行 XACK 命令告知 Redis,这时 Redis 就会把这条消息标记为「处理完成」。
- Stream 会写入到RDB和AOF做持久化。但是
- 消息堆积时,Stream指定队列的最大长度,防止队列积压导致内存爆炸。当队列长度超过上限后,旧消息会被删除,只保留固定长度的新消息。因此依旧可能会导致丢失消息。