Redis作为消息队列的优劣

Redis缓存问题

Redis作为消息队列的优劣

Redis集群模式下保证可迁移和高可用——一致性算法

Redis热Key问题解决方案汇总


Redis基于内存,高性能并且提供多种数据结构供使用,那么对于Redis能不能作为消息队列?以及与专业的消息队列,如RocketMQ,Kafka等差距又在哪里?

Redis提供多种方式实现消息队列,基于List,基于Pub/Sub等,如今基本广泛使用的是Redis5.0之后推出的Stream流格式,其具有支持持久化,支持消息的多播、分组消费,支持消息的有序性,支持消费者组等特点,考虑到和专业消息队列之间的区别,这里主要从以下三个角度考虑Redis作为消息队列的利弊:

生产者:

当生产者在发布消息时,可能发生以下异常情况:

  • 消息未发送:网络故障或其它问题导致发布失败,中间件直接返回失败

  • 发送状态不确定:网络问题导致发布超时,可能数据已发送成功,但读取响应结果超时了

这两种情况都可以通过重发消息解决,生产者一般会设定一个最大重试次数,超过上限依旧失败,需要记录日志报警处理。也就是说,生产者为了避免消息丢失,只能采用失败重试的方式来处理。这也意味着消息可能会重复发送。根据实际情况,需要在消费者端考虑幂等性。

所以,无论是 Redis 还是专业的队列中间件,生产者在这一点上都是可以保证消息不丢的。

消费者

当消费者拿到消息后,还没处理完成,就异常宕机了,那消费者还能否重新消费失败的消息?

要解决这个问题,消费者在处理完消息后,需要向中间件发送一个ACK, Redis也是可以做到的。

Redis本身

Redis 在以下 2 个场景下,都会导致数据丢失

  • AOF 持久化配置为每秒写盘,但这个写盘过程是异步的,Redis 宕机时会存在数据丢失的可能

  • 主从复制也是异步的,主从切换时,也存在丢失数据的可能(从库还未同步完成主库发来的数据,就被提成主库)

像 RabbitMQ 或 Kafka 这类专业的队列中间件,在使用时,一般是部署一个集群,生产者在发布消息时,队列中间件通常会写「多个节点」,以此保证消息的完整性。这样一来,即便其中一个节点挂了,也能保证集群的数据不丢失。

消息积压

因为 Redis 的数据都存储在内存中,这就意味着一旦发生消息积压,则会导致 Redis 的内存持续增长,如果超过机器内存上限,就会面临被 OOM 的风险。Redis 的 Stream 提供了可以指定队列最大长度的功能,就是为了避免这种情况发生。

但 Kafka、RabbitMQ 这类消息队列就不一样了,它们的数据都会存储在磁盘上,磁盘的成本要比内存小得多,当消息积压时,无非就是多占用一些磁盘空间,相比于内存,在面对积压时也会更加「坦然」。

综上,可以看到,把 Redis 当作队列来使用时,面临以下 2 个问题:

  • Redis 本身可能会丢数据

  • 面对消息积压,Redis 内存资源紧张

然而,Redis也并不是没有优点,如果你的业务场景足够简单,对于数据丢失不敏感,而且消息积压概率比较小的情况下,把 Redis 当作队列是完全可以的。而且,Redis 相比于 Kafka、RabbitMQ,部署和运维也更加轻量。

如果你的业务场景对于数据丢失非常敏感,而且写入量非常大,消息积压时会占用很多的机器资源,那么我建议你使用专业的消息队列中间件。

总结

大部分使用消息队列的场景都可以使用stream替代。基于redis的高性能和使用内存的机制使得其的性能优于大部分消息队列。在小规模场景会有更出色的表现。但是针对大流量的场景不推荐使用Redis,毕竟内存的大小是有限的,并且Redis也是不可靠的,这也是所有redis实现的消息队列的局限之处。

你可能感兴趣的:(数据库,Redis,redis,中间件,java)