Redis 数据丢失问题排查

本文讲述了在Redis4.0.2单机环境中,由于服务器过年停机后Redis重启,Java服务连接Redis时发现某个Key丢失的问题。分析发现,Redis配置文件中工作目录为相对路径,导致Redis启动时在不同目录下找不到rdb文件,从而丢失数据。解决方案是修改配置文件中的工作目录为绝对路径或调整启动目录。此案例强调了生产环境中配置细节的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境描述

某客户的生产环境,Redis 4.0.2 单机

问题现象

客户生产环境服务器因过年停机,年后开机后,Redis 重启,Java 服务连接 Redis 提示某个 Key 在 Redis 里不存在。

问题分析

Java 服务从 Redis 读 Key 读失败,说明服务本身是知道读哪个 Key 的,于是梳理了下问题的相关流程:
在这里插入图片描述

  1. Java 服务实际提供了一个 SQL 类型的 API,可以将数据库里的数据通过 API 透出给其他应用程序
  2. 当 HTTP 请求达到 Java 服务后,它会通过自身的业务库查询到当前 API 对应在 Redis 里的 Key
  3. 通过 Key 去 Redis 里查到对应的数据库连接信息以及要执行的查询 SQL
  4. 通过 JDBC 连接数据库,然后执行查询 SQL 查询数据,最后将数据返回给前台

既然读 Key 失败,说明在 Java 服务自身的业务库里是保存了这个 Key 的,于是去 MySQL 中查询,果然存在这个 Key,而 Redis 里确实也不存在这个 Key,说明 Redis 重启后,这个 Key 确实丢了。

继续分析,Java 程序在特定条件下会在 Redis 里写入这个 Key,而且 Redis 配置文件里配置了 SnapShot 的 save 机制:

save 900 1
save 300 10
save 60 10000

这个 Key 是个很早就写入 Redis 的,按照第一条 save 规则,应该是已经从内存写入到 rdb 文件中了,那为什么 Redis 启动的时候没有读到这条数据呢?

继续查看 Redis 配置文件,发现端倪:

# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir ./

Redis 配置文件里,工作目录配置的是 ./ 这种相对路径,也就是说,启动 Redis 时,在哪个目录下运行启动命令,它就会在那个目录下找 rdb 文件并加载,如果目录下没有 rdb 文件,那 Redis 启动后就没有任何数据。

于是排查了 Redis 目录,在 Redis 根目录下发现了一个 rdb 文件,在 src 目录下也有个 rdb 文件,而这次 Redis 启动是在根目录下启动的,上次是在 src 目录启动的,导致这次启动后无法加载上次的 rdb 文件,也就导致了 Key 丢失。

解决方案

由于 Redis 被很多 Java 服务使用,不能随意重启,只好手动在 Redis 里将这个 Key-Value 写进去供程序使用;如果可以重启,只需更换启动目录,再重启下 Redis 就可以了。

不过最好的方式,还是将配置文件中的工作目录 dir 设置成绝对路径,这样无论在哪里启动 Redis,都能读到同一份 rdb 文件。

总结

很多知识是书本上学不到的,只有从一次次生产事故中总结学习…

### 解决 Redis 数据丢失问题的原因及解决方案 #### 原因分析 Redis 是一个基于内存的键值存储系统,虽然提供了多种持久化机制来防止数据丢失,但在特定情况下仍然可能发生数据丢失。主要原因是: - **操作系统层面的影响**:当 Linux 系统重启时,如果没有正确配置某些内核参数,可能会导致 Redis 进程无法正常保存数据到磁盘[^5]。 - **持久化配置不当**:如果未启用 RDB 或 AOF 持久化功能,或者这些功能配置不合理,则在服务器意外停机或重启后,内存中的数据将不会被恢复[^3]。 #### 解决方案 ##### 一、调整内核参数 `vm.overcommit_memory` 为了确保 Redis 能够顺利分配所需内存并完成持久化操作,在 Linux 上可以通过修改系统的虚拟内存管理行为来提高稳定性。具体做法是在 `/etc/sysctl.conf` 文件中添加一行配置项 `vm.overcommit_memory=1` 并使其生效: ```bash echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf && sysctl -p ``` 此设置允许应用程序请求超过物理 RAM 的地址空间,从而减少由于内存不足而引起的 OOM Killer 杀死进程的风险。 ##### 二、合理配置持久化选项 根据业务需求选择合适的持久化方式——RDB 快照或 AOF 日志记录,并对其进行优化调优。两种持久化模式各有特点: - **RDB (Redis Database Backup)** :定期创建整个数据库的状态快照,默认每秒一次增量备份;适合追求性能的应用场景下使用。 ```conf save 900 1 # 如果900秒(15分钟)之后至少有1个key发生变化则触发bgsave ``` - **AOF (Append Only File)** : 记录每次写入命令至日志文件中,支持更细粒度的数据保护;适用于对数据安全性要求较高的场合。 ```conf appendonly yes # 开启aof持久化 appendfsync everysec # 设置为everysec可以兼顾安全性和效率 no-appendfsync-on-rewrite no # rewrite期间也同步刷盘 auto-aof-rewrite-percentage 100 # 当前大小是上次重写的两倍时触发重写 auto-aof-rewrite-min-size 64mb # aof最小体积达到64MB才考虑重写 ``` 另外还可以开启混合持久化(`rdbcompression`)以获得更好的压缩率和更快的速度[^4]。 ##### 三、监控与报警机制建设 建立完善的监控体系实时跟踪 Redis 实例运行状态以及各项指标变化趋势,及时发现潜在风险因素并通过邮件/SMS等方式通知管理员采取相应措施预防事故发生[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值