redis中AOF 重写机制解析
AOFAppend Only File持久化机制通过记录所有写命令来保证数据安全但随之而来的问题是随着运行时间增长AOF 文件会不断膨胀。假设你反复对一个 key 执行INCR操作 1000 次AOF 文件中会记录 1000 条INCR命令但恢复时只需要一条SET key 1000即可。这就是 AOF 重写的价值所在。AOF 重写的核心目标就是将 AOF 文件重写为包含相同数据集的最小命令集从而减少文件体积加速数据恢复。一、问题背景AOF 文件的膨胀1.1 AOF 持久化回顾AOF 机制以日志形式记录每个写命令。当执行以下操作时127.0.0.1:6379 SET user:1000:name Alice OK 127.0.0.1:6379 SET user:1000:name Bob OK 127.0.0.1:6379 SET user:1000:name Charlie OKAOF 文件会记录三条命令。但实际上只有最后一条SET user:1000:name Charlie是恢复数据所需要的。1.2 膨胀带来的问题问题影响磁盘空间浪费大量冗余命令占用存储数据恢复缓慢启动时需回放所有历史命令主从复制压力传输大文件占用网络带宽二、核心设计思想AOF 重写与直接处理旧 AOF 文件不同它采用了一种巧妙的方式不是“重写旧文件”而是“基于当前内存数据生成新文件”。这种方式相当于定期对数据库做一个“快照”用一系列能够重建当前数据状态的命令替换旧的、冗长的命令序列。2.1 核心原则最小命令集原则只生成重建当前数据集所需的最少命令。后台执行原则通过子进程完成不阻塞主进程。原子替换原则新旧文件切换是原子的不会丢失数据。三、重写工作的三阶段3.1 准备阶段触发与状态检查在redis中无论是手动触发还是自动触发rewriteAppendOnlyFileBackground()函数是入口// 伪代码AOF重写入口 int rewriteAppendOnlyFileBackground() { // 1. 检查是否已有重写进程在运行 if (server.aof_rewrite_child_pid ! -1) { return C_ERR; // 已有重写进程忽略本次请求 } // 2. 检查是否正在执行 RDB 持久化 if (server.rdb_child_pid ! -1) { // 等待 RDB 完成后再执行 server.aof_rewrite_scheduled 1; return C_OK; } // 3. 执行 fork 创建子进程 pid_t child_pid fork(); if (child_pid 0) { // 子进程执行重写 rewriteAppendOnlyFile(); exit(0); } else { // 父进程记录子进程 PID初始化重写缓冲区 server.aof_rewrite_child_pid child_pid; server.aof_rewrite_buf sdsempty(); // 创建重写缓冲区 return C_OK; } }3.2 执行阶段子进程的核心工作这是重写的核心工作子进程遍历整个数据库生成新的 AOF 文件// 伪代码子进程重写 AOF 文件 void rewriteAppendOnlyFile() { // 1. 创建临时文件 FILE* fp createTempFile(temp-rewrite.aof); // 2. 写入 SELECT 命令选择数据库 // Redis 默认有 16 个数据库需要确保恢复时切换到正确的数据库 for (int db_id 0; db_id server.dbnum; db_id) { redisDb* db server.db[db_id]; if (dictSize(db-dict) 0) continue; // 空数据库跳过 // 写入 SELECT db_id 命令 writeSelectCommand(fp, db_id); // 3. 遍历当前数据库的所有键 dictIterator* di dictGetIterator(db-dict); dictEntry* de; while ((de dictNext(di)) ! NULL) { robj* key dictGetKey(de); robj* val dictGetVal(de); // 4. 根据键的类型生成对应的重建命令 if (val-type OBJ_STRING) { // 字符串SET key value writeSetCommand(fp, key, val); } else if (val-type OBJ_LIST) { // 列表RPUSH key value1 value2 ... writeListCommand(fp, key, val); } else if (val-type OBJ_SET) { // 集合SADD key member1 member2 ... writeSetMembersCommand(fp, key, val); } else if (val-type OBJ_ZSET) { // 有序集合ZADD key score1 member1 score2 member2 ... writeZsetCommand(fp, key, val); } else if (val-type OBJ_HASH) { // 哈希HMSET key field1 value1 field2 value2 ... writeHashCommand(fp, key, val); } } dictReleaseIterator(di); } // 5. 写入 EOF 标记和校验和可选 writeEofAndChecksum(fp); // 6. 关闭临时文件 fclose(fp); }子进程遍历的是fork()那一刻的内存快照利用了写时复制技术所以数据是一致的。生成的是RESP协议格式的命令与普通 AOF 文件格式完全兼容。3.3 收尾阶段父进程处理增量数据在子进程工作期间父进程继续处理客户端请求新的写命令被同时写入两个地方旧的 AOF 缓冲区保持旧文件持续更新AOF 重写缓冲区aof_rewrite_buf子进程完成工作后通知父进程进行最后的合并// 伪代码父进程处理重写完成信号 void handleRewriteCompletion(pid_t child_pid) { // 1. 等待子进程结束获取退出状态 int status; waitpid(child_pid, status, 0); // 2. 检查子进程是否成功 if (!WIFEXITED(status) || WEXITSTATUS(status) ! 0) { // 子进程失败清理资源 clearRewriteResources(); return; } // 3. 将重写缓冲区增量数据追加到临时文件 // 这是关键步骤保证新文件包含子进程工作期间的所有新写命令 FILE* temp_fp fopen(temp-rewrite.aof, a); fwrite(server.aof_rewrite_buf, len, 1, temp_fp); fclose(temp_fp); // 4. 重命名临时文件为目标 AOF 文件原子操作 // rename 在 Unix 中是原子的 if (rename(temp-rewrite.aof, appendonly.aof) ! 0) { // 重命名失败记录错误 logError(Failed to rename AOF file); return; } // 5. 清空重写缓冲区重置状态 sdsfree(server.aof_rewrite_buf); server.aof_rewrite_buf NULL; server.aof_rewrite_child_pid -1; // 6. 如果新的 AOF 文件大于旧文件可能需要调整自动重写阈值 updateAofRewriteThreshold(); }收尾阶段的时序图时间线 ────────────────────────────────────────────────────────────── 主进程 │ fork() │ 继续处理请求写入旧AOF 重写缓冲区 │ 信号处理 │ │ │ 子进程 │ │ 遍历内存生成新AOF │ 退出 │ │ │ │───────┤ 重写缓冲区积累增量命令 │ │ │ │ │ │ │ 追加增量 │ │ │ 原子替换四、关键机制深度解析4.1 写时复制Copy-on-Writefork()创建子进程时子进程与父进程共享同一份物理内存只有当某一方修改时才会复制内存页。这使得 AOF 重写几乎不消耗额外内存是高效的异步处理基础。4.2 重写缓冲区的必要性为什么需要单独的重写缓冲区而不能用现有的 AOF 缓冲区因为子进程生成的新 AOF 文件是基于fork()时刻的数据快照。如果在子进程运行期间父进程的新命令只写入旧 AOF 缓冲区而子进程生成的临时文件没有这些命令替换后就会导致增量数据丢失。4.3 为什么重写能减少文件体积场景旧 AOF 记录重写后记录键反复修改SET k 1→SET k 2→ ... →SET k 100SET k 100只保留最终值集合频繁增删SADD s a b→SREM s a→SADD s cSADD s b c只保留最终成员列表大量增删RPUSH l a→LPUSH l b→RPOP lRPUSH l b a只保留最终元素过期键键已过期但旧文件中仍有记录直接忽略不写入新文件键被删除SET k 1→DEL k直接忽略最终状态是不存在4.4 自动触发的条件Redis 配置了两个参数控制自动重写# redis.confauto-aof-rewrite-min-size 64mb # AOF 文件至少达到 64MBauto-aof-rewrite-percentage 100 # 比上次重写后增长 100%触发逻辑的伪代码// 伪代码检查是否需要触发自动重写 void checkAndTriggerAofRewrite() { // 获取当前 AOF 文件大小 long long current_size getAofCurrentSize(); long long base_size server.aof_rewrite_base_size; // 检查条件 if (current_size server.aof_rewrite_min_size current_size base_size * (1 server.aof_rewrite_percentage / 100.0)) { // 触发重写 rewriteAppendOnlyFileBackground(); server.aof_rewrite_base_size current_size; // 更新基准大小 } }4.5 重写对性能的影响方面影响缓解措施CPU子进程遍历数据库CPU 密集后台执行不阻塞主进程内存fork()时复制页表写时复制增加内存控制重写触发频率I/O写入新 AOF 文件可配置aof-rewrite-incremental-fsync降低磁盘压力主线程仅在信号处理时短暂阻塞毫秒级几乎无感知五、总结与最佳实践5.1 AOF 重写本质AOF 重写 后台子进程 × (遍历内存 生成命令) 重写缓冲区 × (记录增量) 原子替换5.2 核心工作清单步骤执行主体关键操作1. 触发重写主进程检查条件fork()2. 生成新 AOF子进程遍历数据库为每个键生成重建命令3. 缓存增量命令主进程新写命令存入aof_rewrite_buf4. 追加增量主进程重写缓冲区数据追加到临时文件5. 原子替换主进程rename()替换旧 AOF 文件AOF重写和生成RDB快照在执行机制上确实很相似都利用了Linux的“写时复制”Copy-On-Write, COW技术来创建一个子进程处理任务避免阻塞主进程。不过它们诞生的目的和最终的结果完全不同。你可以这样理解它们的关系它们就像同一位厨师Redis主进程使用的两种不同菜谱RDB快照是每隔一段时间拍一张厨房全貌的照片存起来。这张照片RDB文件记录的是某个瞬间所有食材数据的最终样子是全量备份。AOF重写则是当记录做菜步骤的本子AOF文件变得太厚时厨师会回顾本子上的所有步骤重新梳理成一份精简版的“最终操作指南”。它只记录让食材变成当前状态所需的最小必要步骤目的是给AOF文件“减肥”。对比维度RDB 快照AOF 重写核心目的全量备份生成一个压缩的二进制文件用于快速恢复数据和灾难备份。日志瘦身压缩AOF文件体积避免其无限膨胀同时不影响持久化的实时性。产出内容数据本身某个时间点的所有键值对按Redis的二进制格式存储。写命令集合能还原当前数据集的最小、最精简的命令集合。数据完整性可能丢失数据因为是定时备份两次快照间的数据在故障时可能会丢失。保证完整性重写期间的新命令会被额外记录重写完成后会追加到新文件中确保数据不丢。恢复速度快直接加载数据文件到内存不执行任何命令。慢需要逐条重新执行文件中的所有写命令来重建数据推荐一个零声教育学习教程个人觉得老师讲得不错分享给大家[LinuxNginxZeroMQMySQLRedisfastdfsMongoDBZK流媒体CDNP2PK8SDockerTCP/IP协程DPDK等技术内容点击立即学习:链接

相关新闻

OpenCore Legacy Patcher完全指南:让老旧Mac焕发新生的终极免费工具

OpenCore Legacy Patcher完全指南:让老旧Mac焕发新生的终极免费工具

OpenCore Legacy Patcher完全指南:让老旧Mac焕发新生的终极免费工具 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 还在为老旧Mac无法升级最新ma…

2026/8/9 11:27:15 阅读更多 →
山海万灵 HarmonyOS 文化知识设计续篇(23):发布候选、灰度、回滚与观察期门禁

山海万灵 HarmonyOS 文化知识设计续篇(23):发布候选、灰度、回滚与观察期门禁

一次内容更新可能同时改变图鉴正文、神兽关系、讲解提示词和客户端展示。若这些变化只靠“打一个新包、发布一批内容”分别推进,出现异常时很难判断该停掉应用版本、撤回内容,还是切回讲解策略。更稳妥的做法,是把它们收束为一份可追溯的发布…

2026/8/9 11:26:15 阅读更多 →
后端开发者必知:Airflow任务编排与MWAA实战指南

后端开发者必知:Airflow任务编排与MWAA实战指南

1. 为什么后端开发者需要掌握Airflow? 大数据时代下,后端开发者经常面临这样的困境:凌晨三点被报警短信吵醒,发现昨晚的数据批处理任务又失败了;业务部门抱怨报表数据延迟了6小时;团队里没人能说清楚各个ET…

2026/8/9 11:26:15 阅读更多 →

最新新闻

游戏数值分析实战:从《明日方舟:终末地》难度讨论到Python战斗模拟

游戏数值分析实战:从《明日方舟:终末地》难度讨论到Python战斗模拟

这次我们来看一个关于《明日方舟:终末地》游戏难度讨论的技术分析视角。虽然标题本身更像玩家社区的吐槽,但背后涉及的是游戏关卡设计、数值平衡、角色强度验证等可被技术化分析的问题。对于开发者、测试人员或深度玩家而言,如何量化评估“一…

2026/8/9 12:20:41 阅读更多 →
Spring Boot集成EasyCaptcha实现高效验证码方案

Spring Boot集成EasyCaptcha实现高效验证码方案

1. 项目背景与核心价值 在Web应用开发中,验证码机制是防止机器恶意请求的第一道防线。传统字符验证码存在识别困难、用户体验差的问题,而图片验证码通过图形干扰元素能有效平衡安全性与易用性。Spring Boot作为Java生态的主流框架,与EasyCapt…

2026/8/9 12:20:41 阅读更多 →
从零构建Vue 3.4 UI组件库:实战指南与工程化实践

从零构建Vue 3.4 UI组件库:实战指南与工程化实践

在实际前端项目中,我们经常使用 Element Plus、Ant Design Vue 等成熟的 UI 组件库来快速搭建界面。但你是否想过,这些组件库内部是如何工作的?当业务发展到一定阶段,需要一套符合自身设计规范、技术栈和业务逻辑的专属组件时&…

2026/8/9 12:20:41 阅读更多 →
B站视频下载器终极指南:免费解锁4K大会员专属内容

B站视频下载器终极指南:免费解锁4K大会员专属内容

B站视频下载器终极指南:免费解锁4K大会员专属内容 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 你是否曾为无法下载B站大…

2026/8/9 12:20:41 阅读更多 →
《热江绿色版》手游官方网站下载渠道,2026年8月最新下载域名,认准本站三九联合运营,干净复古武侠生态,慢节奏历练才是真江湖

《热江绿色版》手游官方网站下载渠道,2026年8月最新下载域名,认准本站三九联合运营,干净复古武侠生态,慢节奏历练才是真江湖

当下多数复古武侠品类,普遍陷入快餐滚服、数值膨胀、氪金内卷的怪圈。层出不穷的付费礼包、强化直购、专属增益道具,不断拉高养成门槛,让原本主打休闲历练、自由探索的武侠体验彻底变味。很多偏爱复古画风、传统武学体系、自由江湖氛围的玩家…

2026/8/9 12:20:41 阅读更多 →
AI行业范式转移:从研究突破到工程化落地的技术趋势与工程师应对策略

AI行业范式转移:从研究突破到工程化落地的技术趋势与工程师应对策略

最近科技圈有个消息让不少人感到意外:Google DeepMind 的联合创始人兼CEO德米斯哈萨比斯(Demis Hassabis)即将卸任。如果你只是把它看作一次普通的高管变动,那可能就错过了背后更重要的信号。这不仅仅是DeepMind或谷歌一家公司的人…

2026/8/9 12:19:40 阅读更多 →

日新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/9 0:01:47 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/9 0:01:47 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/9 0:03:48 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/8 17:02:44 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/9 0:45:04 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/8 17:02:44 阅读更多 →