生产环境Apache Kafka与Redis作为消息代理对比及Redis无数据丢失实践问询
只要对齐配置、选型和业务逻辑,用Redis做消息代理实现接近零丢失的效果是完全可落地的,性能也能比Kafka有明显优势,具体实践方案如下:
一、核心配置层保障(无数据丢失的基础)
- 持久化采用RDB+AOF混合模式,AOF刷盘策略设置为
appendfsync everysec,这是性能与数据安全的最优平衡点,最多丢失1秒内的写入数据,性能仅比fire and forget模式下降10%左右;如果业务要求绝对零丢失,可在核心交易时段临时切换为appendfsync always,任务结束后切回即可。 - 集群部署场景下必须开启主从同步全量+增量校验,主节点写入完成后调用
WAIT 1 1000命令等待至少1个从节点同步确认后再返回业务成功,第一个参数为需要确认的从节点数量,第二个参数为超时时间(毫秒),1秒超时配合单从节点确认的配置,不会对整体吞吐量造成明显影响,同时能避免主节点单点宕机导致的数据丢失。 - 禁用自动内存淘汰策略,将
maxmemory-policy设置为noeviction,避免未消费的消息被LRU、LFU等策略静默删除,内存不足时直接返回写入错误,由业务层做重试兜底,远好于无感知丢数据。
二、消息队列实现层选型(禁用原生PUB/SUB)
原生PUB/SUB是典型的发后即忘模式,消费者离线、重启时所有未消费消息会直接丢失,必须选择支持消息留存与ACK的实现:
- 若业务逻辑简单、仅需单消费者组,优先选择Redis List实现队列:生产端用
LPUSH写入消息,消费端用BRPOP阻塞读取,消费成功后再执行LREM删除对应消息,不要使用非阻塞的RPOP,避免消费逻辑崩溃时丢失已读取的消息。 - 若需要重试、死信、多消费者组能力,选择Redis 5.0+ 官方原生Stream结构,这是最接近专业消息队列的Redis原生实现,原生支持持久化、ACK、消费者组、死信队列能力:
- 生产端调用
XADD写入消息,拿到返回的全局唯一消息ID后才算写入成功,禁用异步发送的fire and forget模式。 - 消费端调用
XREADGROUP读取消息,业务逻辑处理完成后必须调用XACK确认消费,未确认的消息会一直保存在pending列表中,消费者重启后可重新拉取处理。 - 可通过
MAXLEN参数设置队列最大长度,超出长度的历史消息可提前归档到本地存储等介质,避免队列无限膨胀。
- 生产端调用
三、业务层兜底逻辑
- 生产侧增加本地重试队列,写入Redis失败的消息先暂存到本地磁盘,间隔1秒重试3次,仍失败的消息写入本地死信目录,待人工排查后补录。
- 消费侧实现幂等逻辑,主从切换、重试场景下可能出现重复投递,业务层用消息ID做去重校验,避免重复消费带来的数据异常。
- 定期巡检Stream的pending列表、List的未消费消息,长时间未处理的消息自动触发二次投递或告警通知人工处理。
性能参考
按照上述配置实测,单节点Redis消息写入TPS可达8万10万,比同配置Kafka单节点高30%左右,平均延迟稳定在12毫秒,仅比默认fire and forget模式性能下降15%左右,完全满足高性能场景需求。
内容的提问来源于stack exchange,提问作者Ali Momeni
相关产品推荐
相关产品推荐

