写Redis做了这么多年,几乎每个刚接触它的人都会问同一个问题:数据全在内存里,断电了怎么办?Redis持久化就是为了解决这个问题的。RDB和AOF这两套机制,一个是快照、一个是追加日志,原理完全不同,取舍方向也不一样。网上讲这两个东西的文章一抓一大把,但大多数要么就是把官方文档翻译一遍,要么只讲个概念对比,真正能把这些细节串起来、告诉你生产环境里怎么选怎么配、出了问题怎么排查的内容,确实不多。这篇我把自己折腾Redis持久化的经验完整梳理一遍,从底层机制到配置调优,再到故障排查,尽量用大白话讲透,给正在做缓存治理、高并发设计、分布式锁这类场景的同学一份可以照做的参考。
先说个结论帮大家稳住预期:如果你只是把Redis当纯缓存,数据丢了可以从数据库重建,那开不开持久化都无所谓;只要Redis里放了不能随便丢的业务数据,我建议默认组合就是开AOF、把appendfsync设成everysec、同时开启混合持久化。这个结论背后是什么逻辑,为什么不是无脑选RDB,也不是无脑选always刷盘,下面展开细聊。
1. 为什么Redis需要持久化:先搞清楚问题本身
1.1 内存的快,是Redis最大的优点也是最大的软肋
Redis的所有读写操作都在内存里完成,所以单实例轻松扛住十万级QPS不在话下,这在绝大多数业务场景里已经够用了。但内存有一个天然的短板:它是易失性存储,断电、进程崩溃、系统重启,数据都会没掉。一台装了8GB数据的Redis,进程一挂,这8GB数据就没了,如果这些数据没有从其他渠道恢复的概率,那就是事故。
很多人最开始学Redis的时候,会有一种错觉:Redis不是有缓存功能吗,缓存丢了重新从数据库查一遍不就行了?这话对一半。纯缓存场景确实可以这样,但Redis的实际定位早就超出了"缓存"这两个字。现在大家用它做分布式锁、排行榜、限流计数器、秒杀库存、用户会话、甚至当部分业务的数据库在用。这些场景里的数据一旦丢失,损失的不只是"缓存命中率",而是直接的业务错误或者用户数据丢失。我之前遇到一个团队,用Redis存秒杀活动的预扣库存,没开持久化,一次服务器重启,库存数据全没了,活动直接全场免费,这个教训是非常惨痛的。
1.2 持久化到底解决了哪三个问题
第一个是宕机恢复。进程崩溃或者机器重启之后,Redis能通过持久化文件把自己之前的数据重新加载回来,不需要从上游数据库或者日志里慢慢回放。恢复速度直接决定了系统瘫痪时间。
第二个是容灾与迁移。做机房迁移、实例扩缩容、故障演练的时候,有持久化文件就相当于有了一份"数据快照",拷贝过去就能在新环境里恢复服务。没有持久化,搞迁移的时候只能先切流量再慢慢预热,整个过程又慢又揪心。
第三个是主从复制的基础。Redis主从全量同步的时候,主节点会把内存数据做成RDB快照发给从节点,这个动作本身就是持久化机制的一部分。所以即使你的业务"完全不怕数据丢",只要用了主从复制、哨兵、集群这些高可用架构,就绕不开持久化相关的话题。后面我会单独展开讲。
所以说,持久化不是Redis的一个可有可无的加分项,而是从单机工具走向生产级基础设施的关键一步。理解RDB和AOF,不是面试前背两个名词解释就完事的问题,而是运维、调优、排障时实打实要用到的基本功。
2. RDB持久化:定时拍一张全量数据的"合影"
2.1 RDB的底层工作方式
RDB的全称是Redis DataBase,本质上就是给Redis内存里的数据拍一张"快照",然后以二进制格式写入磁盘,生成一个dump.rdb文件。触发方式分两种:SAVE和BGSAVE。
SAVE是同步的,直接在主进程里执行数据写入操作,期间Redis完全阻塞,不处理任何请求。这种方式只有胆子特别大或者数据量特别小的时候才敢碰,正常生产环境下线上用SAVE等于自杀,大家千万别试。
BGSAVE是异步的,Redis会fork出一个子进程来执行快照写入,父进程继续处理客户端请求。这是生产环境里实际使用的方案。触发BGSAVE的方式有很多,后面详说。子进程写快照的时候,父进程还在不断接收写请求,这里就涉及RDB最核心的技术点:写时复制(Copy On Write,COW)。
2.2 fork子进程与写时复制的原理
COW这个机制值得单独拎出来讲清楚,因为很多线上故障都跟对它的理解不到位有关。
当BGSAVE触发时,Redis主进程会调用fork创建一个子进程。fork这个操作在Linux上的成本不是复制全部内存数据,而是复制父进程的页表,然后把父子进程指向同一批物理内存页面。创建的这个子进程看到的是一份"内存视图",这个视图的内容定格在fork发生的那一刻。子进程开始往磁盘上写RDB文件的时候,实际上就是在顺序读取这个内存视图,将其编码成RDB格式。
关键的问题来了:fork之后,如果父进程没有任何写操作发生,那大家都共享同一份物理内存,整个过程又轻又快。但如果父进程这时收到了写请求,比如一个SET命令,那么这块即将被修改的内存页就不能再共享了,否则子进程看到的视图也被改了,快照就不一致了。所以操作系统会把这页内存复制一份,父进程往复制出来的新页上写,子进程仍然读原来的旧页。这个机制就是写时复制。
用生活化的方式理解:RDB快照就像给一家人拍了张全家福,按下快门之后就定格了。拍摄期间有人打了个喷嚏、换了件衣服,照片里依然是快门那一刻的模样。COW保证的就是"快门时刻"的一致性,代价是,如果拍照期间家人不停乱动,那需要复制的"新照片底片"就越多,消耗的内存和磁盘IO也就越大。
这里就引出一个实操经验:Redis实例占用内存越大,一次BGSAVE期间发生写入越多,COW就需要复制越多的内存页,额外的内存开销也就越大。如果因为大量写入导致COW复制量过大,加上fork时瞬间复制页表的开销,主进程是有可能被阻塞的。我遇到过一台内存用在6GB左右的Redis,配置了频繁的自动RDB,高峰期每秒写入量很大,结果BGSAVE期间出现主进程延迟飙升的告警。排查了半天,最后定位是COW复制造成的额外内存和CPU压力。这也是我后来在关键业务上倾向使用AOF的原因之一。
2.3 RDB的触发方式全集
RDB这玩意儿不是你只能手动敲BGSAVE才生成的。梳理一下所有可能触发RDB生成的场景,方便排查"为什么磁盘上突然多了个rdb文件"之类的问题:
- SAVE命令:同步生成,线上禁用。
- BGSAVE命令:手动触发异步快照,用于备份时很常见。
- 配置了save m n自动触发:只要在m秒内有n次以上写入,就会触发一次BGSAVE。
- 主从全量复制的场景:主节点在同步给从节点之前,会主动做一次BGSAVE生成RDB文件发给从节点。
- 执行SHUTDOWN关闭Redis且没开启AOF时:系统会尝试做一次RDB快照再退出。
- 执行DEBUG RELOAD类操作时:会触发一次热重启并重新加载数据。
默认的save配置一般是这样的:
save 3600 1 save 300 100 save 60 10000意思是:3600秒内至少有1次写入,或者300秒内至少有100次写入,或者60秒内至少有一万次写入,满足任意一条就触发一次快照。这套默认配置其实比较保守,只在写入频率很高时才会频繁快照。但对很多业务来说,如果60秒内有1万次写入就触发一次RDB,那么最坏情况下可能丢一分钟数据,这对某些场景是不可接受的,也是我建议走AOF的原因。
2.4 RDB方案的优势和坑
RDB的优点很明确:第一,恢复速度极快。RDB文件是二进制格式,加载时直接顺序读入内存重建数据,对大实例来说比AOF重放一堆命令快得多。第二,文件体积紧凑,适合做备份和传输。第三,对写性能影响相对较小,毕竟真正的写入动作在子进程里。
但它的缺点同样明显:一是数据丢失窗口大,默认配置下可能丢十几分钟甚至更久的数据。二是fork阻塞问题,实例内存越大,fork瞬间的耗时和COW压力越容易让主进程抖一下。三是全量快照模式在数据量大的时候并不优雅,每次都是把整个内存写一遍,对IO和磁盘空间的要求都不低。所以RDB更适合作为"数据备份"手段,而不是唯一的数据安全兜底方式。
3. AOF持久化:把每一次数据变更都记成"流水账"
3.1 AOF的完整写入链路
AOF的全称是Append Only File,思路和RDB完全不同。它不拍快照,而是把每一条"可能修改数据"的写命令记录下来,追加到文件末尾。你可以把它理解成记账:每花一笔钱就记一行,账本完整记录所有流水。以后要恢复数据,不需要找旧账本,直接重新"过一遍账"就行。
一条写命令从客户端发过来到真正落盘,大致经过这几个环节:
- 客户端发送SET之类的写命令给Redis。
- Redis执行命令,修改内存数据。
- 同时将这条命令追加到内存中的aof_buf缓冲区。
- 在事件循环中,根据appendfsync策略决定何时把aof_buf里的内容写到操作系统PageCache。
- 操作系统PageCache中的数据,什么时候真正刷到磁盘文件,同样受策略控制。
关键点在于,命令先落到PageCache这一步,并不代表数据已经安全落盘了。PageCache是操作系统管理的内存级缓存,如果这一刻机器断电,PageCache里还没刷盘的数据照样会丢。真正决定数据安全性的是后面那个fsync动作,也就是强制把PageCache刷新到磁盘。
这就像你在手机上记了一个备注,第一步存在手机内存里(PageCache),稍后系统才同步到云端(磁盘)。如果这中间手机突然坏了,云端没同步上的内容就没了。所以AOF的策略核心,就是控制"从内存到磁盘"这一步的节奏。
3.2 appendfsync的三种策略:always、everysec、no
appendfsync这个配置直接决定了AOF的安全性等级和性能损耗,是AOF方案里最需要认真权衡的参数。
| 配置项 | 触发时机 | 数据安全性 | 性能影响 | 最坏丢失窗口 |
|---|---|---|---|---|
| always | 每条写命令执行后立即fsync | 极高,基本只丢该命令本身未成功写入的情况 | 最差,每次写都要等磁盘IO完成,吞吐大打折扣 | 近似0,实际最多一条命令 |
| everysec | 每秒刷一次磁盘 | 高,极端情况丢1秒内的写入 | 很好,聚合刷盘开销可接受 | 最多1秒数据 |
| no | 完全交给操作系统决定刷盘时机 | 最低,可能丢几十秒甚至更多数据 | 最好,几乎没有额外等待 | 由系统缓存刷新策略决定,通常较大 |
如果你对Redis有一点了解,肯定知道网上普遍推荐everysec。这个策略的性价比确实是最高的:性能上,把fsync频率压缩到每秒一次,避免每条命令都同步等待磁盘;安全上,最坏情况只丢1秒数据。绝大多数业务能接受"崩溃时丢1秒内的写入"这个代价。
always不是不能用,但要清楚代价。一旦开启,每一笔写请求都要等待真正的落盘,高并发下Redis的QPS会明显下降,而且磁盘性能会成为绝对瓶颈。实测下来,同样一台机器,从everysec改成always,写入吞吐可能掉一个数量级。所以除非是那种绝对不能丢任何一条数据的强一致场景,否则我不建议全员always。
no这种策略就有点赌徒心态了,把命运交给操作系统。操作系统PageCache攒够一批数据才会刷到磁盘,一旦宕机,丢失的数据量可能非常可观。这个选项我基本只在测试环境里见过,生产环境尽量别碰。
3.3 AOF重写机制与混合持久化
日志文件一直往里追加,文件会无限增长,时间一长磁盘空间扛不住,而且恢复时要重放大量命令,启动会越来越慢。为了解决这个问题,Redis引入了AOF重写机制。
重写不是对原AOF文件做压缩修改,而是基于当前内存里的数据,重新生成一份"最精简"的写命令集合。举个例子,你的key从初始值0执行了10万次INCR,最终值100000。原AOF文件里会累积10万条INCR命令,重写后只需要一条SET key 100000就能表达当前状态。子进程在重写期间,父进程仍然在接收新的写命令,这部分增量会同时进入一个重写缓冲区。子进程生成完新文件后,把重写缓冲区的增量命令追加进去,最后原子替换掉旧AOF文件,整个过程对客户端基本无感。
Redis 4.0之后,官方又引入了混合持久化方案,配置项是aof-use-rdb-preamble。开启之后,AOF重写生成的文件不再是纯文本命令,而是以RDB二进制格式保存当前全量数据放在文件开头,后面再追加重写期间产生的增量AOF命令。这个设计非常聪明:加载时先快速读取RDB部分完成全量恢复,再回放少量AOF增量补齐最新数据,恢复速度和数据安全性都照顾到了。这也是我前面说"默认组合就是AOF+混合持久化"的原因。
3.4 AOF方案的优缺点
AOF最大的优势是数据安全性和灵活性。everysec策略下最多丢1秒数据,always下基本不丢数据,比RDB那个动辄丢几分钟数据的窗口强太多了。而且纯AOF文件是文本格式,虽然混合模式下开头是二进制块,但整体上可以用工具去分析,甚至手动删掉一些有问题的危险命令,这对应急修复很有价值。
代价就是文件体积天然比RDB大,写放大问题更明显,纯AOF模式下恢复速度也远不如RDB。想象一下,从几百MB的AOF文件里一条条重放命令,和直接从几十MB的RDB二进制文件里加载,差距是数量级的。这也是为什么生产中都不太用纯AOF,而是开启混合持久化来弥补这个短板。
4. RDB vs AOF终极对比:到底怎么选
4.1 一张表看清两者的本质差异
| 对比维度 | RDB | AOF |
|---|---|---|
| 存储内容 | 全量数据二进制快照 | 写命令追加日志 |
| 恢复速度 | 极快 | 慢,开启混合持久化后明显改善 |
| 数据安全性 | 差,可能丢最后一次快照之后的所有数据 | 高,everysec最多丢1秒,always几乎不丢 |
| 文件大小 | 紧凑 | 大,天然膨胀,依赖重写去瘦身 |
| 对写性能影响 | 低,fork+COW在极端情况有阻塞风险 | 中等,取决于appendfsync策略 |
| 对磁盘占用 | 较低 | 较高,存在写放大 |
| 备份与传输 | 方便,直接拷贝rdb文件 | 麻烦,文件大,备份成本高 |
| 运维复杂度 | 低,配置简单 | 中,重写、刷盘策略都需要关注 |
| 适用场景 | 备份、容灾、快速迁移 | 数据安全要求高的业务数据 |
这张表是我自己的经验总结,不是单纯翻文档抄来的。核心差异可以浓缩成一句话:RDB赌的是"机器不会突然死",AOF赌的是"最多丢一秒数据"。前者换来的是又快又省,后者换来的是安全可控。
4.2 不同业务场景的选型建议
纯缓存场景,数据可重建、丢失无感。这种情况下,很多人会直接关掉持久化,换取最高性能。我只提醒一句:如果这个实例还要承担主从复制的角色,关闭持久化会让从节点同步也变得脆弱,至少保留RDB兜底。
常规业务缓存场景,比如用户会话、临时标记、最新榜单这类。推荐AOF+everysec+混合持久化。恢复速度不会太差,数据安全也有保障,是我最常用的一套组合。
强一致、金融级业务场景,比如账户余额、交易流水、分布式锁等。AOF+always是更稳妥的选择,但务必提前做好性能压测。这里的逻辑不是让Redis替代数据库,而是在数据库之外多一层保护。
数据库替代场景,Redis作为主存储直接扛业务,请假想最坏情况。我的建议是"AOF+定期RDB+从节点+定期远程备份"四件套都上。AOF保证崩溃后最多丢1秒数据,RDB用于快速恢复和容灾,从节点用于高可用切换,远程备份防止机房本身出问题。
4.3 主从复制与集群环境下必须注意的持久化细节
很多人在单机场景下纠结半天,一到主从、哨兵、集群架构下反而容易忽视持久化。这里有几个非常关键的点希望大家重视。
第一,主节点如果关了持久化,全量同步给从节点的数据就完全依赖从节点的RDB快照。一旦主节点崩了,哨兵切换从节点,这个从节点可能还停留在很久以前的数据状态,或者干脆就没有数据。你以为是高可用,实际上一切换就是一次大范围数据丢失。
第二,哨兵在选主时,会优先选择复制偏移量最大的从节点,也就是数据最新的从节点。但如果所有节点都没持久化,那么这个"最新"也只是内存里的最新,重启之后大家都可能变成"没有数据"。这就是典型的"高可用架构扛得住节点故障,扛不住所有节点同时重启"的场景。
第三,用Redis做分布式锁的朋友尤其要注意。很多人用Redisson或者自己封装SET NX实现锁,把锁的key放在Redis里,觉得集群部署了就很稳。可如果Redis没有持久化,实例重启后锁信息全没。一个线程刚拿到锁还没执行完,另一个线程同样能拿到锁,两个线程同时进入临界区操作共享资源,后果可能比锁失效更严重。我在生产环境就实际遇到过一次,后面排障章节详细讲。
5. 生产环境配置与运维实操
5.1 redis.conf核心配置逐项说明
以下是生产环境中我常用的持久化相关配置,配合注释说明每一项的意义:
# RDB相关配置 # 自动快照触发条件 save 3600 1 save 300 100 save 60 10000 # 快照出错后是否拒绝写入 # yes表示bgsave失败时拒绝新写入,宁可先停下来,也不要让系统带病运行 stop-writes-on-bgsave-error yes # RDB文件是否压缩 rdbcompression yes # RDB文件与日志文件所在目录 dir /var/lib/redis # RDB文件名 dbfilename dump.rdb # AOF相关配置 # 开启AOF appendonly yes # AOF文件名 appendfilename "appendonly.aof" # 刷盘策略:每秒刷一次 appendfsync everysec # 重写期间是否暂停fsync # 默认no,即正常执行fsync,避免重写导致AOF落后太多 no-appendfsync-on-rewrite no # 触发自动重写:文件比上次重写后增长了100%,且至少64MB auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # AOF文件加载时遇到截断是否自动恢复 aof-load-truncated yes # 混合持久化开关 aof-use-rdb-preamble yes几个容易踩坑的配置点多说一句。
stop-writes-on-bgsave-error这个配置,默认是yes。它的意思是,如果RDB快照写入失败(比如磁盘满了),Redis会拒绝新的写入请求。这个设计看着很激进,但逻辑是:既然快照已经写不进去了,继续写入只会让内存数据和磁盘数据差距越来越大,后面更难恢复。它在关键时刻能保护你,也可能会在磁盘故障时突然导致线上写入失败,所以平时要重点监控磁盘状态。
auto-aof-rewrite-percentage 100和auto-aof-rewrite-min-size 64mb决定了AOF自动重写的频率。若AOF文件增长到上一次重写后大小的两倍且超过64MB,就会自动触发重写。如果你发现重写太频繁,可以调大百分比;如果发现AOF文件一直膨胀不重写,通常是重写期间子进程持续出问题,需要手动检查。
5.2 Redis启动时的数据加载顺序
很多人以为Redis启动后先加载RDB,再加载AOF,其实不是。Redis启动时,如果appendonly是开启状态,它会优先加载AOF文件来恢复数据,哪怕磁盘上同时存在RDB文件也忽略RDB;只有当AOF完全关闭时,才会走RDB加载流程。
为什么这么做?因为AOF文件通常包含Redis宕机之前的所有写命令,数据更新,用它恢复的数据更接近崩溃时的状态。而RDB文件可能是十几分钟前甚至更久之前的快照,用它恢复会丢掉快照之后的所有修改。所以在混合持久化开启的情况下,一个AOF文件内部就带着RDB格式的全量数据和AOF增量,加载效率和数据新鲜度都是最优的。
启动过程中,可以通过Redis日志确认到底加载了哪个文件。比如看到类似DB loaded from append only file或者DB loaded from disk这样的日志,就明白是从哪个持久化渠道恢复的了。排查"为什么重启后数据是旧的"这个问题时,第一步就是看这条日志。
5.3 手动备份与恢复的标准操作
持久化文件的好处之一,是可以做离线备份。我通常的做法是,先执行一次BGSAVE,等待RDB快照生成完毕后,把RDB文件拷贝到备份目录或者异地存储。AOF文件如果开启了Append操作,不能直接拷贝带写入状态的文件,最好先执行一次BGREWRITEAOF,让文件处于一个比较干净的状态,再拷贝。
# 手动触发RDB快照 redis-cli bgsave # 等待完成后拷贝文件 cp /var/lib/redis/dump.rdb /backup/redis/dump-20250117.rdb # 手动触发AOF重写,优化文件大小 redis-cli bgrewriteaof # 参考:在线导出RDB快照 redis-cli --rdb /backup/redis/dump-online.rdb恢复的时候更简单,把RDB文件或AOF文件放到Redis配置的dir目录下,文件命名和dbfilename或appendfilename保持一致,直接启动Redis,它会自动加载。恢复前建议先备份原文件,防止当前生产环境的文件被意外覆盖。
5.4 监控持久化状态
我在线上排查持久化问题时,最常用的命令是INFO persistence,它能输出RDB和AOF最近一次执行的状态信息,包括最近一次RDB是否成功、AOF重写是否在运行、AOF缓冲区大小等。这套输出是判断持久化是否健康的第一手依据。
redis-cli info persistence输出里重点看几个字段:
rdb_last_bgsave_time_sec:最近一次RDB快照耗时,如果数值异常大,说明磁盘压力大或者COW开销高。rdb_last_bgsave_status:最近一次BGSAVE是否ok。aof_last_bgrewrite_status:最近一次AOF重写是否ok。aof_last_write_status:上次AOF落盘是否成功,这里如果失败要立即排查磁盘。
另外,日志也是重要的信息来源。AOF写入失败、RDB快照失败这类错误通常都会打日志。日志里反复出现写盘失败相关的关键词,基本可以判定持久化链路有问题。
6. 常见故障与排查实录
6.1 问题速查表
根据我平时维护Redis的实战经验,整理了一份高频问题的快速排查表,方便大家遇到问题时直接对照处理。
| 现象 | 可能原因 | 处理建议 |
|---|---|---|
| 重启后数据是旧数据 | 加载了RDB而不是AOF,或AOF文件日期比RDB旧 | 确认appendonly是否为yes,优先加载AOF |
| 重启后直接丢大量数据 | AOF文件损坏,Redis启动时默认忽略截断部分 | 手动用redis-check-aof修复,检查日志里truncated提示 |
| 启动直接失败,AOF加载报错 | 混合文件头部损坏、版本不一致 | 备份原文件后,尝试用redis-check-aof --fix修复 |
| 客户端大量写入报错 | 磁盘满,stop-writes-on-bgsave-error生效 | 清理磁盘、扩容、修复快照失败原因 |
| 频繁RDB快照阻塞主线程 | 实例内存过大,fork和COW开销高 | 关闭THP,降低save频率,拆大key,或者切换AOF |
| AOF文件暴涨不自动重写 | 重写条件没满足,或重写过程不断失败 | 手动BGREWRITEAOF,检查子进程日志和磁盘空间 |
| 持久化文件与内存数据不一致 | 混合持久化未开启,AOF丢失了崩溃前最后一小段时间 | 开启混合持久化,考虑提升appendfsync级别 |
6.2 一次分布式锁失效的故障复盘
前面提到分布式锁的场景,这里详细说说我碰到过的一次真实故障。某服务的业务代码依赖Redis分布式锁来防止多个实例同时处理同一笔订单。锁的实现就是在Redis里写入一个带过期时间的key。当时这套Redis是主从架构,主节点没有开启任何持久化,从节点倒是开着AOF,但不承担读写。
某天机房短暂断电,主节点和从节点几乎同时重启。因为主节点没有持久化文件,启动后是空库;从节点靠AOF恢复了大部分数据,但哨兵最终把主节点切换到了那台重启后无数据的主节点上。结果就是,锁key全部丢失,所有业务实例同时成功获取到分布式锁,多个线程同时进入唯一的资源处理逻辑,大量订单被重复处理,还有一部分数据因为并发写产生了脏数据。
复盘的时候,核心教训有两条。一条是:分布式锁这种要求"只要我没释放,别人一定拿不到"的语义,光靠Redis单机持久化都不够稳,至少要从两个维度去加强,一是持久化配置强制打开且可靠,二是锁的获取要配合fencing token之类的机制去防止长GC后锁过期导致的重入问题。另一条是:不要在主节点上为了性能关掉持久化,尤其是在分布式锁这种对一致性敏感的场景里,Redis持久化不先保住,高可用架构就是纸糊的。从那之后,我这边凡是承接分布式锁的Redis实例,一律开启混合持久化,appendfsync至少everysec,条件允许就用always。
6.3 实用排障修复命令
遇到持久化文件损坏的问题,Redis自带两个修复工具,我用过多次,效果不错。
# 修复AOF文件,会移除损坏的尾部数据 redis-check-aof --fix appendonly.aof # 检查RDB文件完整性和内容 redis-check-rdb dump.rdb用redis-check-aof修复完文件之后,一定要先备份原文件再启动Redis。修复过程会裁剪掉AOF尾部无法解析的部分,虽然在绝大多数情况下丢失的只是最后几秒的增量数据,但这个操作本身是不可逆的。
另外还有一个很好用的技巧:如果AOF文件已经完全损坏无法修复,但RDB文件还是好的,可以临时关闭AOF,用RDB恢复数据,等实例起来之后再重新开启AOF。这需要操作顺序严谨,避免启动时又去加载坏掉的AOF导致失败。
排查"持久化为什么失败"这类问题时,日志是最高优先级的线索。Redis在启动和运行过程中会把加载状态、刷盘失败、快照失败这些信息都记录在日志里,定位时先看日志最省时间。
最后再聊一点个人体会。做了这么多年Redis运维,我最大的感觉是,持久化选型没有银弹,关键是在安全、性能、恢复速度之间找到自己业务能接受的最小损失窗口。与其背一堆概念,不如自己动手做一次恢复演练:把RDB和AOF文件拷走,直接kill -9把Redis杀掉,再换个新目录启动,看看数据能恢复到什么程度。这个测试做一次,你就能切身体会到两种方案的真实差距,也能真正理解该怎么选、怎么配。