当前位置:首页 > 问答 > 正文

Redis消息队列为啥会丢数据到底是系统问题还是配置没弄好导致的?

Redis消息队列丢数据,这个问题不能简单地归结为纯粹的系统问题或者单纯的配置没弄好,它更像是一个“系统提供了多种可能性,而配置和用法决定了哪种可能性会变成现实”的问题,换句话说,Redis本身在特定场景下存在丢数据的风险,但一个设计良好、配置得当的系统可以极大程度地避免这些风险,丢数据通常发生在以下几个关键环节。

最经典也最常见的原因是Redis自身的持久化策略没有配置好,Redis的数据是放在内存里的,如果服务器突然断电或者崩溃,内存里的数据就全没了,包括消息队列里的消息,Redis提供了两种主要的持久化机制来应对这个问题:RDB和AOF,根据开源社区像Redis官网文档和许多技术博客中的普遍观点,如果这两者都没配置好,那丢数据几乎是必然的。

RDB可以理解为给内存数据拍个快照,隔一段时间拍一张,如果你配置成每小时保存一次RDB快照,那么服务器如果在第59分钟崩溃,就会丢失将近一个小时的数据,这显然是配置问题,你需要根据业务对数据丢失的容忍度来调整快照的频率,比如设置为每分钟甚至每几秒钟一次,但这会对性能有影响。

Redis消息队列为啥会丢数据到底是系统问题还是配置没弄好导致的?

AOF则是记录下每一个写操作命令,像写日志一样,这样即使服务器宕机,重启后重新执行一遍AOF文件里的命令,就能恢复数据,听起来很安全对吧?但AOF有个配置项叫appendfsync,它决定了写操作的同步频率,如果设置成no,让操作系统自己决定什么时候把数据刷到磁盘上,万一服务器断电,操作系统缓存里还没来及写入磁盘的命令就丢了,如果设置成everysec,每秒同步一次,这是个折衷方案,但理论上还是会丢失最后一秒钟的数据,只有设置成always,每次写命令都立刻刷盘,才是最安全的,但性能损耗也最大,这里又是一个典型的权衡:要性能还是要可靠性?配置没选对,就可能丢数据。

丢数据还可能发生在消息的生产和消费环节,这更多是使用模式的问题,一个常见的误区是,生产者以为把消息塞进Redis的List或者Pub/Sub频道就万事大吉了,生产者成功把消息发给了Redis服务器,但还没来得及收到Redis的确认回复,网络就断开了,生产者可能以为消息发送失败,会尝试重发,这可能导致消息重复;但也可能生产者直接就报错退出了,这条消息就“幽灵”般地存在于Redis中,但生产者认为它丢了。

Redis消息队列为啥会丢数据到底是系统问题还是配置没弄好导致的?

在消费端,问题更突出,如果用简单的LPOP命令去List里取消息,消息一旦被弹出,就从Redis里删除了,如果消费者刚拿到消息,还没处理完就崩溃了,这条消息就彻底丢失了,因为没有其他地方存着,这正是更高级的Stream数据类型被引入的重要原因之一,Stream支持“消费者组”模式,消息被消费者读取后,并不会立即删除,而是处于“待处理”状态,消费者必须显式地发送确认命令,Redis才会将这条消息标记为已处理,这样,即使消费者中途挂掉,重启后它还可以去查看哪些消息是“待处理”的,然后重新处理,如果只是用了简单的List而没有这种确认机制,那丢数据就是消费模型本身的缺陷。

Redis本身的内存限制也可能导致丢数据,Redis是内存数据库,如果消息堆积太多,超过了设置的最大内存上限,就会触发内存淘汰策略,如果淘汰策略配置的是noeviction(不淘汰,新写入操作会报错),那生产者就无法写入新消息,相当于业务中断,但如果配置的是allkeys-lru之类的策略,Redis就会开始淘汰一些键来释放空间,这其中很可能就包括你消息队列里的消息,导致旧消息被直接删除,这显然是系统和配置共同作用的结果:系统有内存限制的特性,而配置决定了超过限制后是拒绝服务还是丢数据。

还有一些运维层面的问题,比如不规范的重启操作,如果没有正确使用SHUTDOWN命令来关闭Redis(比如直接kill -9强杀进程),并且AOF日志配置又不是最严格的,也可能导致数据丢失,或者是在做数据迁移、主从切换时,操作不当导致部分数据未能同步过去。

Redis消息队列丢数据,不能怪Redis这个系统一无是处,因为它本身就定位是一个高性能的内存数据存储,在持久化和数据可靠性上需要使用者去做出权衡和配置,绝大多数丢数据的情况,根源在于:第一,持久化配置(RDB/AOF)没有根据业务的可靠性要求进行细化设置,在性能和可靠性之间选择了偏向性能的一方;第二,在消息队列的技术选型和使用模式上,选择了像简单List这种不具备消息确认机制的简单结构,而不是更适合消息队列场景的Stream类型;第三,对Redis的内存管理和运维操作缺乏足够的重视和规范,可以说,丢数据是潜在的“系统特性”,而是否真的会丢,则完全取决于“配置和使用是否得当”,要保证消息不丢,就需要围绕持久化、生产消费确认机制、资源监控等方面做一个全方位的加固。