redis的save配置是基于lastsave_time和dirty计数的固定窗口机制,非滑动窗口;满足任一save规则即触发bgsave,且仅统计写命令次数。

Redis 的 save 配置不是“每 N 秒检查一次”,而是从上一次成功保存(lastsave)开始计时、累计变更次数的固定窗口机制。 理解错这一点,就容易误判备份是否触发、为什么该触发却没触发、或者为什么在低流量下也频繁生成 RDB 文件。
save 900 1 这类配置到底怎么算时间与次数
Redis 启动或完成一次 RDB 持久化后,会记录 lastsave_time(Unix 时间戳),并重置脏计数器 dirty 为 0。之后每次写命令(如 SET、DEL、HSET)都会让 dirty 加 1;同时 Redis 会周期性(默认每 100ms)检查所有 save 规则是否满足:
- 条件是「
current_time - lastsave_time >= seconds」且「dirty >= changes」两个必须同时成立 - 不是滑动窗口:不看“过去 900 秒内有没有 1 次修改”,而是看“距离上次保存是否过了 900 秒,且这期间总共改了多少次”
- 多个
save行是 OR 关系:只要任意一条满足,立刻触发BGSAVE - 注意:只统计写操作次数,不区分 key 数量——
HMSET k f1 v1 f2 v2 f3 v3算 1 次,SET k v也算 1 次
为什么改了 1 次,15 分钟后也没触发 save 900 1
常见原因不是配置失效,而是 dirty 被意外重置或 lastsave_time 被更新过早:
- 执行过
FLUSHALL或FLUSHDB:如果数据库非空,会强制触发一次BGSAVE,导致lastsave_time更新,dirty归零 - 主从全量同步:主节点在向从节点发送 RDB 时,也会调用
BGSAVE,同样重置计时器 - 手动执行过
SAVE或BGSAVE:哪怕只是调试时跑了一次,也会刷新lastsave_time - 配置被覆盖:确认
redis.conf中没有多处save行互相注释/取消注释,也没有通过CONFIG SET save "900 1"动态覆盖但未持久化到文件
如何验证当前 dirty 和 lastsave 状态
别猜,直接查。连接 Redis 后运行:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
INFO persistence
重点关注这几项:
-
rdb_last_save_time:最后一次成功保存的时间戳(秒级) -
rdb_changes_since_last_save:自上次保存以来的写操作次数(即当前dirty值) -
rdb_bgsave_in_progress:是否正在执行BGSAVE(1 表示是) -
rdb_last_bgsave_status:上一次BGSAVE是否成功(ok或err)
用 redis-cli 实时观察:watch -n 1 'redis-cli INFO persistence | grep -E "(rdb_last_save_time|rdb_changes_since_last_save)"',就能看到计时和计数怎么走。
线上环境调参要注意的三个实际约束
配置不是越敏感越好,得看业务写负载、磁盘 I/O 和内存压力:
- 高频小写场景(如计数器、session 刷新):避免配
save 60 10000这类低延迟高阈值组合——可能每 2 秒就攒满 10000 次,导致每 2 秒一次fork,加重 CPU 和内存压力 - 冷数据或只读服务:可直接禁用自动 RDB:
save ""(空字符串),避免无谓的 fork 和磁盘写入 - 混用 AOF 时:
save和appendfsync everysec可能撞在同一毫秒刷盘,引发 I/O 尖峰;建议错开——比如把save 60 10000改成save 61 10000,避开系统默认的秒级对齐
真正容易被忽略的是:Redis 不会在 dirty 达标但 lastsave_time 还很新时提前触发;它也不保证“刚好在第 900 秒整触发”,而是在下一个检查周期(约 100ms 后)才判断——所以实际延迟可能在 900~900.1 秒之间。










