ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Redis持久化策略全解析:RDB、AOF与混合模式原理及实战

Redis持久化策略全解析:RDB、AOF与混合模式原理及实战 写这篇关于Redis持久化策略的文章起因是前阵子帮朋友排查一起线上事故应用半夜发告警某个核心服务的内存数据在重启后大量丢失紧急恢复时才发现Redis的持久化配置压根没做对。那种凌晨三点对着info persistence一行行看输出、看着AOF文件为空的感觉经历过的人都懂。所以这篇我打算把RDB、AOF、混合持久化这套东西彻底讲透从原理到配置从选型到排障把实战里踩过的坑一并交代清楚。1. 先搞清楚持久化到底在解决什么问题1.1 内存本身的不可靠性Redis之所以快是因为所有数据都活在内存里。但内存是易失性存储进程退出、服务器宕机、kill -9、断电任何一次非正常终止都会让数据灰飞烟灭。更麻烦的是Redis宕机后即使主从复制能接管如果从节点上的数据也依赖内存恢复起来同样无底洞。很多人问“我有主从复制为什么还要持久化”——主从复制只是把数据冗余到了另一台机器但那个机器上如果没开持久化进程照样一死就全没了。即使开了主从全量重同步也需要依赖RDB文件来传输本地没有任何快照连同步的底料都没有。所以持久化不是锦上添花是数据安全的底线。再细想一层缓存场景可能觉得丢了就丢了重新查一次数据库呗。但Redis很多时候承载的并不只是缓存——比如会话数据、分布式锁的元信息、排行榜、秒杀库存、消息队列的延迟队列这些数据一旦丢了轻则用户要重新登录重则超卖、重复支付、任务丢失事故等级直接拉满。我见过一个电商项目把订单号生成器的计数放在Redis里没开持久化重启后计数回退生成了重复订单号那真是灾难级的事故。所以到底要不要持久化、怎么持久化不是拍脑袋决定的得看数据丢了能承受多大损失。1.2 持久化的两条技术路线Redis持久化有三种方案RDB快照、AOF日志、以及Redis 4.0引入的混合持久化。本质上就两种思路RDB是定期给整个数据集拍一张“照片”存成二进制文件AOF是把每一次写操作以日志形式追加记录下来就像记账本。两者各有各的取舍但都可以归结为两个字——恢复。RDB恢复速度快因为直接加载二进制结构就能把全量数据读回内存但照片是定期的两次快照之间写进去的数据丢了就找不回来了。AOF记录更细理论上最多丢一个写回周期内的数据可以做到秒级或者最多一两秒的丢失但日志文件会越来越大恢复时得一条条重放速度慢而且文件体积膨胀后对磁盘和带宽都是负担。开头我在事故现场看到的情况就是典型的“什么持久化都没开干净”主从都只靠RDB且默认的save规则因为写量小很少触发重启后数据恢复到好几天之前的状态那批写进AOF里的操作全部悬空。这类问题最大的麻烦在于它不是马上爆而是埋着等到某一刻重启或故障切换时才炸出来。2. RDB快照机制实战拆解2.1 为什么快照能恢复但会丢数据RDB的原理不复杂按配置的触发条件把当前内存里的全量数据序列化写入一个二进制文件默认叫dump.rdb。加载时直接读文件反序列化回内存所以恢复速度很快几百兆的数据几秒钟就能拉起来。触发的途径有四类。第一类是save指令这是同步操作会阻塞Redis主进程数据量大的时候千万不能用生产环境基本没人拿它手动存快照第二类是bgsave后台异步执行Redis会fork出一个子进程执行快照主进程继续服务客户端这是最常用的方式第三类是配置里的自动触发规则比如save 900 1表示900秒内至少有1次写操作就触发一次bgsave第四类是主从复制时从节点第一次全量同步会要求主节点生成RDB以及Redis正常关闭时会自动生成一次快照。我见过不少人只看默认配置save 900 1、save 300 10、save 60 10000觉得有兜底了。但这里有个非常反直觉的坑自动触发是“按写入次数”计算的如果业务是低写入量但数据重要可能几小时甚至一天都不触发一次快照。你以为有持久化其实持久化是一个空壳恢复点停留在很久以前。所以RDB模式下的数据安全边界取决于触发规则而不是“开了RDB就安全”。2.2 核心配置参数精读先把最常用的配置参数列出来这一段值得你直接保存下来对照参考# 自动快照触发规则seconds changes save 900 1 save 300 10 save 60 10000 # bgsave失败后是否停止写入默认yes stop-writes-on-bgsave-error yes # 是否压缩RDB文件默认yes rdbcompression yes # 是否开启RDB文件校验默认yes rdbchecksum yes # RDB文件名 dbfilename dump.rdb # RDB文件保存目录 dir /var/lib/redisstop-writes-on-bgsave-error这个参数很多人只知道默认值却不知道它的含义。它表示如果子进程快照写盘失败磁盘满了、权限不对、IO错误Redis会拒绝所有写请求。设计目的是防止数据继续变化但永远没有新快照造成更大的恢复空洞。这个参数我建议在有监控告警的环境里改成no让Redis在快照失败时继续服务同时靠监控发现错误并人工介入。因为对多数业务来说拒绝写入的代价远大于暂时丢点持久化能力。但这只是个策略取舍没有标准答案——如果你的场景里“数据绝对不能写失败”那保持默认yes反而是在帮你尽早暴露问题。rdbcompression默认开启用LZF算法压缩。压缩能省磁盘空间快照传输到从节点时也省带宽但代价是CPU开销。数据量几GB以内我建议开着因为IO省下的时间远大于压缩耗掉的时间如果机器CPU本来就吃紧可以关掉从文件磁盘占用上找补偿。rdbchecksum用于在加载时做CRC64校验防止文件损坏导致恢复出一堆错乱数据。它只影响加载和保存时的一点性能建议保持开启。做运维的人都知道一个没有校验的二进制快照一旦中间有几位被写坏恢复出来的数据可能是什么样你根本不敢想。2.3 bgsave里的写时复制原理RDB最容易让人误解的就是“bgsave是不是会阻塞Redis”。表象不阻塞内核里其实有阻塞点。bgsave调用后主进程要做一次fork()创建子进程。fork本身需要复制主进程的页表当Redis占用几个GB甚至几十GB内存时这一下就可能让主进程卡顿几十到几百毫秒。我实测过在32GB数据量的实例上fork阶段主进程的延迟毛刺能飙到200ms以上这对延迟敏感的业务是肉眼可见的抖动。fork之后子进程开始把内存数据写入RDB。这里利用的是操作系统的写时复制机制fork瞬间父子进程共享同一份物理内存页任何一方要修改某个内存页时内核会把该页拷贝一份所以父子进程各自的数据视图不会互相干扰。子进程的内存映射相当于父进程在fork那一刻的“冻结快照”之后主进程继续接收新写入、修改已有key都发生在拷贝出来的新页上不会影响子进程正在序列化的旧页。这就是为什么bgsave既不会让数据不一致又能保证主进程几乎不阻塞。但这个机制有几个隐患一是写时复制意味着fork后如果写入量大Redis的内存占用可能会短期上升那些被修改的页需要重新申请内存所以要给Redis预留足够的内存余量建议maxmemory不要打到物理内存的极限二是如果系统开启了内存超卖fork后触碰新页时可能直接OOM表现为“Cant allocate memory”。所以物理内存规划时Redis实例内存占用最好控制在机器内存的50%-60%以内给操作系统页缓存和其他进程留足够空间。2.4 RDB模式下的实操心得和边界不要让RDB文件落在系统盘快照写入是重IO操作系统盘往往承载了日志、JVM堆转储等各类读写混在一起容易互相拖累。我习惯把RDB和AOF都放到独立的挂载盘最好还是独立磁盘而不是只有独立分区不然IO争抢照样存在。监控RDB文件生成耗时和频率INFO persistence里能看到rdb_last_bgsave_status、rdb_last_bgsave_time_sec等字段。如果发现rdb_changes_since_last_save一直很大、而rdb_last_bgsave_time_sec在几秒以上说明快照生成速度追不上写入速度这时候自动触发规则要考虑调大触发阈值避免频繁bgsave。RDB不适合做长时间的数据安全兜底它最适合的位置是“快速恢复的基础快照”配合AOF做增量补偿或者作为全量备份往对象存储里丢一份。单独拿RDB做唯一持久化策略除非你能接受最多丢失数小时甚至一天的数据。3. AOF日志机制实战拆解3.1 追加日志为什么比快照更“接近实时”AOF的思路很简单每执行一条写命令就把这条命令以Redis协议格式追加到AOF文件的末尾。恢复的时候从头到尾重放这些命令数据就能回到最后一刻。就像记流水账每一笔都记下来对账的时候从第一笔开始过一遍。但这个“记流水账”其实比看起来复杂关键在落盘策略。Redis命令执行后是先写进操作系统缓冲区再由系统刷盘这个刷盘时机直接决定了最多丢多少数据。Redis提供了三个级别由appendfsync参数控制always每个命令执行完都调用fsync强制刷盘最安全最多丢一条命令。但每次写都要等磁盘IO吞吐量惨不忍睹我实际测过在机械盘上连每秒几百次写入都撑不住基本只适合对数据安全极致敏感、写入量很低的场景。everysec每秒刷盘一次妥协方案。极端情况下最多丢1-2秒的写入数据如果进程崩溃但系统还在只丢1秒内缓冲区的数据如果操作系统本身宕机可能丢最近2秒的数据因为还有一个内核缓冲区的存量。no完全交给操作系统决定何时刷盘性能最好但一旦宕机丢多少数据完全无法预估可能丢几十秒甚至几分钟的数据。这个选项我基本不推荐因为持久化能力完全不可控等于把安全交给了运气。生产环境用得最多的就是everysec这是性能和安全的经典平衡点。官方也认为everysec在普通负载下具备很强的容错性我的建议是不要轻易改成no除非你很清楚自己的宕机窗口和数据丢失容忍度。3.2 AOF重写机制是为了治“胖”AOF有一个绕不开的问题文件无限膨胀。比如你设置一个key为1再把它改成2、改成3、改成4AOF里就会记录四条SET命令恢复时重放四次。数据明明只有1KB日志却能写到10KB毫无意义。AOF重写BGREWRITEAOF就是来解决这个问题的它会fork子进程扫描当前内存里的数据生成一组最精简的命令集——比如同一个key只保留最终状态的SET中间的过程全部抛弃。重写后的AOF文件体积可以缩小几个数量级恢复速度快也在这重放的是压缩后的命令。但重写还有一个值得特别关注的细节子进程在生成新AOF期间主进程仍在处理写入。这些新写命令不能丢所以主进程把它们同时写入两个缓冲区一个是AOF日志缓冲区老文件继续追加另一个是重写缓冲区专门给子进程存增量。子进程生成完整文件后会通知主进程主进程把重写缓冲区里的增量命令追加到新文件尾部然后原子替换旧文件。这个过程保证了重写期间一点数据也不丢。配置上有几个参数# 开启AOF appendonly yes # 写回策略 appendfsync everysec # 自动触发重写当前AOF文件大小比上次重写时增长了100%且绝对值超过64MB auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # 重写期间是否禁用fsync默认no no-appendfsync-on-rewrite no # 重写增量刷盘大小超过阈值就fsync一次 aof-rewrite-incremental-fsync 32mbauto-aof-rewrite-percentage和auto-aof-rewrite-min-size需要配合理解设成100和64mb的意思是只有当AOF超过64MB并且比上次重写后的体积又翻了100%即翻倍时才触发重写。如果重写后文件是100MB那增长到200MB才会再次触发。这样避免频繁重写浪费IO。3.3 三类典型坑丢数据、截断、读不出AOF的坑比RDB更隐蔽。第一个就是上面说的everysec丢数据窗口。我见过一个事故系统告警宕机恢复后大家发现最近2秒的写入丢了一开始以为是AOF没开查下来其实开着但落盘策略是everysec进程崩溃时那1-2秒缓冲区的数据还在内存里没来得及刷盘。这台机器用的是阿里云宕机迁移不是服务进程app级重启缓冲全没保住。所以如果你的业务极端不能接受丢数据哪怕everysec也是不够的得上always或者换存储方案。第二个坑是AOF文件被截断。宕机时如果正好写到一半文件尾部的命令可能不完整。Redis在加载时会判断aof-load-truncated参数默认yes表示允许加载时忽略最后的损坏数据只恢复到损坏点之前的状态设成no则直接拒绝启动等你手工修复。我的建议是别轻易改no因为生产环境宕机后最要紧的是尽快恢复服务先让它起来再排查损坏点比卡在启动阶段干着急强。但要注意允许截断加载也就意味着尾部的数据丢了这时候需要评估业务是否可接受。第三个坑是AOF文件损坏导致无法加载。这时Redis提供了一个修复工具redis-check-aof用法是redis-check-aof --fix appendonly.aof。它会把文件里有问题的命令剔除掉让文件重新可用。但修复过程会丢失损坏命令及其之后的所有数据而且涉及混合持久化文件时工具处理RDB头的方式在旧版本上表现不太好处理前要先备份原文件。我遇到过一次修复出来的文件加载后某些key消失了检查才知道是某条LPUSH命令损坏导致整个list都丢了那种数据应该在生产上有冗余否则根本救不回来。3.4 AOF配置清单和实战建议如果决定用AOF作为主要持久化手段这套起步配置可以直接抄appendonly yes appendfilename appendonly.aof appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 256mb aof-load-truncated yes no-appendfsync-on-rewrite no aof-rewrite-incremental-fsync 32mb这里几个参数我解释一下选择逻辑。auto-aof-rewrite-min-size从默认64MB提到256MB是因为线上很多实例的AOF文件轻松涨过64MB如果用默认值小实例可能一小时内触发多次重写徒增IO压力。no-appendfsync-on-rewrite保持no是让重写子进程自己的刷盘也受aof-rewrite-incremental-fsync控制避免大文件写入时大量数据淤积在内存缓冲区导致的内存峰值。如果你对重写期间的短暂抖动有心理预期可以把该项改成yes来降低磁盘负担但副作用是重写期间宕机可能丢失更多增量数据——具体怎么取舍得看业务容忍度。4. AOF和RDB混合持久化怎么结合才合理4.1 单独用AOF就没问题吗有些人觉得既然AOF够实时那就只开AOF干脆关掉RDB。这个想法看似合理实际有两个隐患。第一AOF文件恢复时要逐条重放命令10GB的AOF可能需要几分钟而RDB加载同样体量的数据只要几十秒。恢复速度在大数据量下差距明显对SLA要求高的服务每多卡一分钟都是钱。第二AOF文件每经过一次重写体积虽然能缩小但因为要保留命令语义无法像RDB那样直接用二进制结构存储同样数据的AOF文件会比RDB大不少。如果只开AOF备份和传输的开销都不小。混合持久化就是针对这两个痛点设计的。核心思想是AOF重写时不再是纯命令格式而是先以RDB格式写入全量数据快照再在文件尾部追加重写期间的增量命令。这样加载的时候前半段RDB部分直接反序列化恢复速度接近RDB后半段AOF部分只包含重写后的增量命令数据又能恢复到接近实时的状态。这个方案用一个参数就能开启aof-use-rdb-preamble yes。Redis 4.0后默认开启也就是说从4.0开始所谓“AOF文件”实际上是一个RDB头AOF命令尾的复合体。可以验证一下打开一个混合AOF文件开头会看到REDIS魔数字说明前半段确实是RDB格式。我见过不少老工程师还在按4.0之前的纯命令格式来设计恢复流程拿cat去看AOF文件却看不懂就是因为这个设计变化。4.2 混合持久化的完整工作流程混合持久化的运行逻辑可以拆成几个步骤平时运行所有写命令正常追加进AOF缓冲区并周期性刷入磁盘受appendfsync控制。触发AOF重写时主进程fork出子进程。子进程把当前内存全量数据以RDB格式写入临时文件。重写期间新到来的写命令继续追加到AOF老文件同时进入重写缓冲区。子进程写完RDB部分后通知主进程把重写缓冲区里的增量命令以AOF格式追加到临时文件尾部。临时文件通过rename原子替换旧AOF文件。加载恢复时Redis检测到文件开头的RDB格式先快速载入全量快照再重放末尾的AOF增量完成恢复。这个流程避开了“纯RDB丢失窗口大”和“纯AOF恢复慢”两个短板同时体积也比纯AOF更小。从4.0开始这个方案就是我的默认选择除非有极其特殊的场景需要再权衡。不过要注意一个细节RDB头部分的数据是“重写开始那一刻”的全量数据如果重写耗时很长比如几十GB数据重写要跑几分钟那么AOF尾部积累的增量命令会相当多恢复时重放这些命令也需要时间。所以混合方案虽然比纯AOF快但不是无限快大数据量下该优化还是要优化。4.3 混合模式下的配置建议开启混合持久化的配置很简单重点是把它跟RDB自动快照配合好# 开启混合持久化4.0默认即开启 aof-use-rdb-preamble yes # 同时保留RDB快照作为全量备份 save 900 1 save 300 10 save 60 10000 # RDB和AOF共存 dbfilename dump.rdb appendonly yes appendfilename appendonly.aof需要强调的是RDB快照和AOF文件在这里扮演的角色并不重叠。AOF负责最近几分钟甚至几秒钟的恢复精度RDB负责提供一个稳定的、周期性的全量备份点。RDB可以往对象存储同步AOF则留在本地保证热数据可恢复。两套机制配合起来既不担心丢失窗口过大也不担心恢复耗时失控。混合持久化引入了一个新问题恢复时对RDB头和AOF尾的兼容性。如果Redis从旧版本升级到新版本旧版无法识别新版生成的混合文件可能导致加载失败。跨版本升级前建议先手动执行一次BGREWRITEAOF生成兼容当前版本的AOF文件再执行升级操作然后确认加载正常之后再切换流量。5. 持久化选型怎么落地到不同业务场景5.1 判断数据可丢程度的三个层级持久化方案没有万金油没有哪个方案是“绝对正确”的只有“适合你当前业务”的。我习惯把数据分成三层再做选型第一层纯缓存可丢。比如商品详情页的临时缓存、热点数据的前置缓存丢了就是回源数据库重新查一次成本可控。这类场景甚至可以不开启持久化省掉RDB和AOF的磁盘开销让Redis专注于缓存服务。但注意即使是纯缓存如果你的服务发现缓存雪崩会打垮数据库那还是建议开一个“低频RDB”至少宕机时能快速加载一部分热点而不是全量冷启动。第二层业务数据但有一定容忍窗口。比如用户会话、临时状态、排行榜等丢了会造成一部分用户体验回退但不至于产生资损。这种场景建议开启混合持久化appendfsync everysec允许极端情况下丢一两秒数据恢复速度用RDB头保证。第三层资金、订单、库存等强一致数据。这类数据Redis基本只作为加速层真正的事务性数据应落数据库或消息队列Redis侧可以开appendfsync always甚至对单条关键命令做额外确认。但就算这样也绝不能把Redis当成唯一存储因为再强的持久化也扛不住人工FLUSHALL加BGREWRITEAOF这种组合拳——后面我会讲为什么这种误操作比宕机还可怕。三层场景对应三种配置模板我做了一张表方便对照场景持久化策略appendfsync关键配置纯缓存可丢关闭持久化或低频RDB不适用save 900 1业务数据可容忍秒级丢失混合持久化everysecaof-use-rdb-preamble yes强一致数据加速层混合持久化主从always主从同步备用快照需要注意的是第二层和第三层在Redis侧只是“加速层”底层数据兜底必须靠数据库。Redis持久化是为了减少数据丢失的窗口和恢复的时间但不要把它当成终极保险。5.2 一个可抄的通用配置模板很多项目一开始并没有清晰的持久化规划我到了现场通常先按这套模板落地再根据业务调整# 启用AOF和RDB混合持久化 appendonly yes appendfilename appendonly.aof appendfsync everysec aof-use-rdb-preamble yes auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 256mb aof-load-truncated yes no-appendfsync-on-rewrite no aof-rewrite-incremental-fsync 32mb # RDB基础快照 save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error no # 通用配置 dir /data/redis dbfilename dump.rdb rdbcompression yes rdbchecksum yes maxmemory 20gb maxmemory-policy allkeys-lru这套模板兼顾了恢复速度、数据精度、磁盘开销和运维便利。maxmemory按机器物理内存的50%-60%来设避免fork时写时复制导致的内存峰值挤爆进程。maxmemory-policy先按LRU兜底防止写入超限时Redis直接崩溃具体淘汰策略再按业务调整。这里特别提醒一句dir建议设到独立磁盘分区的挂载点比如/data/redis而不是默认的/var/lib/redis。因为RDB和AOF的写入量都不小如果和系统日志抢IO快照耗时和AOF刷新延迟都会起来长此以往会产生“持久化拖垮主线程”的错觉实际上只是磁盘兄弟互相打架。5.3 监控、备份和灾备三板斧持久化不是配好就一劳永逸了后续运维和巡检才是关键。监控方面至少盯这几个指标INFO persistence里的rdb_last_bgsave_status和aof_last_bgrewrite_status这俩直接反映上次快照或重写是否成功rdb_changes_since_last_save如果一直增长但快照频率很低说明数据积压越来越严重aof_current_size增长速率是否异常如果短时间内暴涨要检查是不是有某个大key在频繁更新。这些都可以用Prometheus抓取配合Alertmanager做告警。另一个容易忽略的指标是INFO stats里的latest_fork_usec这个数字是最近一次fork的耗时单位微秒。如果这个值持续在几十毫秒以上说明Redis内存页表庞大fork时对主进程的阻塞相当可观。这时候要么考虑给Redis瘦身、上分片要么接受周期性毛刺的出现。备份方面建议每天在业务低峰期手动执行一次BGSAVE把生成的RDB文件用rsync或对象存储上传到异地保留最近7-14天的版本。很多人觉得既然有AOF了RDB备份没必要其实RDB是全量恢复的基础AOF只是增量异地备份的RDB能让你在整机损毁时快速拉起一个可用的数据副本。灾备方面我强烈建议做一次“恢复演练”。就像消防演习一样从备份里拉一个全新的Redis实例加载RDBAOF确认数据完整性和recovery时间。别等真的挂机时才发现备份文件写坏了、恢复脚本路径不对、加载超时。这一条每次说都觉得啰嗦但每次出事故都能验证它的价值——最近一次演练我们就发现备份RDB文件只有几十KB查下来是定时任务中BGSAVE执行前连接串配到了错误的端口备份作业一直在拿空快照覆盖正常快照。6. 常见故障排查与实操经验6.1 排查工具和命令速查遇到持久化相关的问题先别慌按下面这个路径一步步排查大部分问题能在几分钟内定位redis-cli info persistence看RDB和AOF最近一次的状态包括rdb_last_bgsave_status、aof_last_bgrewrite_status、aof_enabled等。redis-cli info stats看latest_fork_usec判断fork阻塞的风险。redis-cli config get save、config get appendfsync确认实际生效的配置。redis-check-rdb dump.rdb检查RDB文件完整性。redis-check-aof --fix appendonly.aof修复AOF文件。ls -lh /data/redis确认文件大小和时间戳判断文件是否最新、是否异常膨胀。日志方面Redis的启动日志会详细打印快照和AOF加载过程。启动时如果看到DB loaded from append only file或者DB loaded from disk后面跟着耗时就知道走了哪条恢复路径。失败时的报错通常也会把原因说得很直接比如Bad file format reading the append only file——这种情况九成是文件损坏需要redis-check-aof --fix来修复。6.2 生产环境典型的五个问题实录问题一重启后数据大面积丢失。排查顺序是先config get appendonly确认AOF有没有开确认aof_last_write_status是否为ok看AOF文件最后修改时间是不是在写操作之后。如果AOF没开RDB的触发频率又低丢了大量数据就是必然结果。这种问题没有快速修复路径只能从备份恢复或者重构数据但之后一定要把持久化配置补齐。问题二启动卡住很久。常见原因是加载太大的AOF或者RDB文件。如果看到启动日志停留在某个阶段检查文件大小和当前机器的磁盘IO。混合持久化模式下AOF文件里的RDB头部分加载很快但尾部增量如果很大比如重写期间写入量巨大重放也需要时间。建议从机子层面加大磁盘吞吐同时优化重写触发阈值别让文件积累到夸张的大小。问题三fork操作导致延迟毛刺。现象是latest_fork_usec飙高业务侧偶尔出现几百毫秒的响应超时。解决思路三个方向给机器加内存降低内存页表大小治标不治本用多实例分片减少单个实例的内存占用推荐业务侧接受毛刺并用熔断策略兜底无奈之举。不要尝试关掉bgsave来治这个那是因噎废食。问题四Cant allocate memory。fork时申请内存失败多半是机器物理内存被写时复制耗尽。处理方法是立即调低maxmemory先让Redis停止接收新写入如果配置了maxmemory-policy则自动淘汰然后重启实例。重启后要复查内存规划给写时复制留足余量。问题五误操作FLUSHALL然后AOF重写。这是持久化最恐怖的一环管理员清空了所有数据同时BGREWRITEAOF把空数据集写进了新AOF原本能恢复的数据被彻底覆盖。标准应对如果刚发生立刻停掉Redis主进程把AOF文件备份尽量别触发任何写操作和重写然后拿着备份找数据恢复方案。但从根上防范的办法只有一个——给生产环境配好权限管控FLUSHALL、FLUSHDB、CONFIG SET这类危险命令要么禁用要么走审批流程。我曾经一建了一个服务器端命令黑名单把这类命令全部挡在来源IP之外从那之后再没出过这种事故。6.3 操作细节上的独家避坑清单这几个细节是常规文档不会写的但实际部署中非常容易出现连带故障第一AOF重写和RDB快照不能同时跑。虽然Redis本身会做互斥但人为手动触发BGSAVE和BGREWRITEAOF时如果数据量大两者会争抢fork资源和磁盘IO造成比平时更严重的阻塞。建议把定时任务里的快照和重写错开比如重写安排在业务低峰快照再往前提半小时。第二及时清理旧的RDB备份。磁盘写满是持久化故障里最常见但最容易被忽视的根因。stop-writes-on-bgsave-error yes时RDB失败会直接拒绝写入而大量团队根本没意识到是磁盘空间的问题。备份策略里要加入保留周期和压缩至少留出RDB文件大小的两倍空闲空间。第三混合持久化的AOF文件不能直接用纯AOF命令工具处理。因为文件头是RDB格式redis-check-aof --fix在旧版本上对混合文件的处理效果不可控。如果需要手动修复先复制一份文件然后确认Redis版本支持最好在测试环境试跑一遍修复再看加载结果别在线上直接赌。第四特别注意跨版本升级时的持久化兼容性。Redis每次大版本升级RDB格式和AOF协议理论上都有变化虽然Redis官方做了向后兼容但任何一次升级前都要准备好回滚方案。我习惯升级前手动执行一次BGREWRITEAOF同时保留升级前的RDB和AOF文件的完整副本确保升级失败时还能回到旧版本环境加载旧文件。7. Redis重启数据丢失的应急复盘思路最后想分享一个比较完整的应急复盘思路是从我之前凌晨处理事故积累下来的你完全可以把它当成一个操作手册来用。第一先确认事实现在Redis的数据是从哪个文件恢复的文件是什么时间生成的恢复耗时多少。这一步用INFO persistence和查看文件时间戳就能搞定。第二评估丢失窗口对比恢复后的数据量、最新写日志的时间、文件生成时间估算出丢失了多长窗口的数据。第三看备份昨天、前天的RDB文件还在不在能不能通过合并应用AOF增量来补全数据。第四查根因是配置没开持久化还是开了但触发条件不合理还是文件损坏没被发现。第五定改进根据根因改配置、加监控、补演练。这个五步法我在好几次事故里用过虽然不能挽回已经丢的数据但能把“数据丢了”快速转化为“为什么丢了、以后怎么不丢”让一次事故变成一次系统能力的跃升。另外有个值得说的小习惯每次发布涉及Redis的配置变更时花一分钟在变更单里附上“数据恢复方案”——如果这台实例挂了怎么拉起新实例RDB从哪来AOF怎么重建预估恢复多久。哪怕只是一个简单的checklist也能在大半夜出故障的时候帮你省下半小时的慌张时间。
返回列表