资讯详情

WSL 2 Docker Redis 数据备份与迁移实战:从RDB到AOF全解析

📅 2026/9/16 1:38:45 | 华诺云谱 👁 阅读
WSL 2 Docker Redis 数据备份与迁移实战:从RDB到AOF全解析
日常跑在 WSL 里的 Docker Redis很多人用到三个月还是记不清数据目录到底在哪。真正逼我系统整理备份和迁移方案的是之前有一次手滑执行了docker-compose down -v整个 Redis 里的 session 和缓存一夜回到解放前当时线上告警直接炸了。那之后我花了两个周末把 WSL 2 环境下的 Redis 备份、恢复、迁移整套链路全部理清楚也踩了不少文档里根本不会写的坑。这篇就把整个过程和最终沉淀下来的方案完整分享出来适合正在用 WSL Docker 跑 Redis、又担心哪天数据突然没了的开发者参考。1. 环境准备WSL 与 Docker 的搭台1.1 先把 WSL 的“家”搬到数据盘用 WSL 2 跑 Docker 的人十有八九都会遇到 C 盘空间迅速告急的问题。WSL 2 的整个文件系统默认存放在一个名为ext4.vhdx的虚拟磁盘文件中位置通常在C:\Users\用户名\AppData\Local\Packages\CanonicalGroupLimited...\LocalState\ext4.vhdx。这个文件会随着镜像、容器、数据卷的增长越滚越大而且 WSL 的虚拟磁盘有个特性——删了文件之后空间不会自动还给宿主机。我在实际使用中发现与其后期想办法压缩 vhdx不如一开始就把整个发行版迁到 D 盘一劳永逸。操作分几步走wsl --shutdown wsl --export Ubuntu D:\wsl-backup\ubuntu-export.tar wsl --unregister Ubuntu wsl --import Ubuntu D:\WSL\Ubuntu D:\wsl-backup\ubuntu-export.tar --version 2这里有几个细节值得注意。第一--unregister会删除原有的虚拟磁盘所有容器镜像、数据卷全部没了所以执行之前务必确认没有需要保留的数据。第二--import之后默认以 root 身份登录而且默认用户会丢失需要手动改回原来的普通用户。# 进入WSL后修改默认用户 echo -e [user]\ndefault你的用户名 | sudo tee /etc/wsl.conf这个坑我踩过两次——迁移完 WSL 后 Docker 一直在 root 用户下运行导致宿主机和容器之间的文件权限对不上Redis 的持久化文件经常出现权限拒绝告警。所以迁移完 WSL 后第一件事就是确认/etc/wsl.conf里的默认用户配置。1.2 在 WSL 里装 Docker 引擎的方式选择WSL 里跑 Docker 有两条主流路线装 Docker Desktop或者直接在 WSL 发行版里安装原生的 Docker Engine。我的建议是如果你不想在 Windows 上再跑一个常驻后台的桌面程序就直接在 WSL 里装原生引擎。sudo apt update sudo apt install docker.io docker-compose-v2 sudo systemctl enable docker sudo service docker start提示WSL 2 默认没有 systemd如果systemctl命令不可用用sudo service docker start一样能启动。新版 WSL 支持在/etc/wsl.conf里开启 systemd开启后就不需要这个兼容操作了。这里要提一个容易忽略的点原生 Docker Engine 没有图形化面板docker ps看不了容器监控曲线但实际备份迁移场景命令行方式反而更直接、更容易脚本化。对于 Redis 这种轻量应用原生 Docker Engine 的内存占用比 Docker Desktop 少了近一半对开发机性能也更友好。1.3 用 docker-compose 部署 Redis 实例Redis 的部署方式我强烈建议用docker-compose.yml而不是裸docker run。原因很简单compose 文件本身就是环境配置的“文档”换机器迁移时compose 文件 数据目录一拷贝就完成了不用重新敲一遍长达几行的启动命令。# docker-compose.yml services: redis: image: redis:7.2-alpine container_name: app-redis restart: unless-stopped ports: - 6379:6379 volumes: - ./redis-data:/data command: redis-server --appendonly yes --appendfsync everysec --requirepass your-password healthcheck: test: [CMD, redis-cli, -a, your-password, ping] interval: 5s timeout: 3s retries: 5这段配置里我默认开启了 AOF 持久化理由是后面要讲的——对于需要备份迁移的场景AOF 能最大限度减少丢失窗口。数据目录我使用相对路径./redis-data这样整个 Redis 服务就是一个文件夹的事备份的时候直接把目录打压缩包就行。注意./redis-data指宿主机WSL 内的当前目录不是 Windows 的当前目录。如果你是在 Windows 资源管理器里用 VS Code 打开项目再进入 WSL 终端执行docker-compose up -d那么这个目录其实是 WSL 文件系统内的路径。建议统一在 WSL 的文件系统下操作避免跨文件系统带来的性能损耗和路径混乱。2. Redis 备份的核心原理搞懂持久化机制2.1 RDB 快照某一刻的全量内存态Redis 的 RDBRedis DataBase持久化本质是把某个时刻内存中的全部数据生成一份压缩的二进制快照文件默认文件名是dump.rdb。这个文件包含的是那一刻的完整数据所以它天然就是一份“全量备份”。RDB 的触发条件有三种手动执行SAVE或BGSAVE命令满足配置文件中save规则比如save 900 1表示 900 秒内至少有 1 个 key 变化就触发一次快照服务正常关闭时自动生成。讲一个实际细节SAVE是同步阻塞式的Redis 在执行期间不接受任何写命令BGSAVE是异步的通过 fork 子进程完成数据落盘生产环境默认用BGSAVE。但微服务开发环境里数据量小手动备份时直接SAVE也未尝不可因为此时阻塞时间可以忽略不计。有个坑我要提醒默认配置下如果 Redis 异常终止比如kill -9容器进程RDB 文件是不会重新生成的系统上次启动后的数据变更就全部丢失了。所以只用 RDB 做持久化丢失窗口由save策略决定最多可能丢几十秒到几分钟的数据。2.2 AOF 日志命令级别的增量记录AOFAppend Only File的工作机制是每执行一条修改类命令就把这条命令追加写入appendonly.aof文件。恢复时Redis 会从头到尾重放这些命令从而还原出数据。它的本质是一份命令流水账所以它的丢失窗口和刷盘策略强相关。appendfsync有三个取值取值行为丢失窗口always每条命令都同步刷盘最多丢一条命令everysec每秒刷一次盘最多丢 1 秒的数据no由操作系统决定何时落盘不确定开发环境用everysec性价比最高兼顾性能和可靠性。always安全性最高但写入性能下降明显如果不是强一致性的业务不建议。AOF 文件会伴随时间增长越来越大所以 Redis 提供了 AOF 重写bgrewriteaof机制会根据当前数据集生成最小的命令集合替换掉旧文件。在 docker 配置里可以通过auto-aof-rewrite-percentage 100和auto-aof-rewrite-min-size 64mb来控制重写触发条件。2.3 持久化策略选型双开还是单开很多初学者纠结 RDB 和 AOF 到底该开哪个。我的实践经验是关键业务数据两个都开。RDB 提供快速恢复和全量快照AOF 提供精细到秒级的增量保护。Redis 启动时加载数据的优先级是AOF 优先于 RDB。也就是说如果两者同时存在Redis 会用 AOF 文件恢复数据因为 AOF 包含的信息更完整。纯缓存场景比如 session、临时验证码、排行榜缓存可以只开 RDB反正丢了也不致命重新缓存就是了。一旦数据开始承担业务状态比如订单号自增、用户积分、消息队列的待处理任务就必须双开。2.4 备份粒度理解“全量 增量”的组合逻辑Redis 没有像 MySQL 那样的 binlog 回放、也没有 pg_dump 那样的逻辑导出功能它的备份体系其实就是“RDB 全量快照 AOF 增量日志 定期归档”。你做的备份工作本质上就是定期生成一份 RDB 快照保证有一个确定时间点的完整数据副本把 AOF 文件也拷贝走保证从 RDB 快照点到当前时刻的所有增量变化不丢恢复时把 RDB 文件放回数据目录再把 AOF 文件放回数据目录Redis 启动后会自动加载 AOF 并重建数据。理解了这一层后续所有备份迁移操作都会变得非常清晰。所谓迁移本质上就是把“RDB AOF 配置文件”这三件套搬到新环境让新环境把数据重新加载起来。3. 备份实操从手动备份到一键脚本3.1 手动全量备份的完整步骤最开始我先讲手动方式因为理解手动流程是写好脚本的前提。整个过程分三步第一步进入 Redis 容器内部执行手动持久化docker exec -it app-redis redis-cli -a your-password BGSAVE执行后 Redis 会 fork 子进程开始生成 RDB 文件可以用LASTSAVE命令确认最后完成快照的时间是否符合预期。第二步进入数据卷目录把持久化文件复制到宿主机备份目录# 进入项目目录的 redis-data 文件夹 cd /path/to/project/redis-data/ # 查看文件列表确认 dump.rdb 的修改时间刷新了 ls -lh # 复制到宿主机备份目录这里以日期为目录名做区分 mkdir -p /backup/redis/$(date %Y%m%d) cp dump.rdb /backup/redis/$(date %Y%m%d)/ cp appendonly.aof /backup/redis/$(date %Y%m%d)/第三步验证备份文件能否正常识别。这一步很多人忽略但非常重要。用redis-check-rdb工具检查文件完整性redis-check-rdb /backup/redis/$(date %Y%m%d)/dump.rdb输出出现[ok]相关提示就说明 RDB 文件结构没有问题。提示手动备份适合临时做一次、或者在做危险操作之前“留个后手”。如果需要一个持续性的备份方案务必往下看自动化脚本。3.2 写一个定时备份脚本自动化备份脚本的设计目标很简单每天固定时间生成 RDB 快照、拷贝 AOF 文件、压缩归档、保留最近 N 份、清理过期文件。我自己的备份脚本长这样#!/bin/bash # redis-backup.sh set -e REDIS_CONTAINERapp-redis REDIS_PASSWORDyour-password PROJECT_DIR/path/to/project BACKUP_BASE/backup/redis RETENTION_DAYS7 DATE$(date %Y%m%d) BACKUP_DIR${BACKUP_BASE}/${DATE} mkdir -p ${BACKUP_DIR} # 1. 触发 Redis 生成最新 RDB 快照 docker exec ${REDIS_CONTAINER} redis-cli -a ${REDIS_PASSWORD} BGSAVE # 等待快照生成完成轮询 LASTSAVE 时间戳 LASTSAVE_BEFORE$(docker exec ${REDIS_CONTAINER} redis-cli -a ${REDIS_PASSWORD} LASTSAVE) sleep 2 for i in $(seq 1 30); do LASTSAVE_AFTER$(docker exec ${REDIS_CONTAINER} redis-cli -a ${REDIS_PASSWORD} LASTSAVE) if [ ${LASTSAVE_AFTER} -gt ${LASTSAVE_BEFORE} ]; then echo RDB snapshot generated successfully break fi sleep 1 done # 2. 拷贝 RDB 和 AOF 文件到备份目录 cd ${PROJECT_DIR}/redis-data cp dump.rdb ${BACKUP_DIR}/ cp appendonly.aof ${BACKUP_DIR}/ # 3. 压缩归档 tar czf ${BACKUP_DIR}/redis-backup-${DATE}.tar.gz -C ${BACKUP_DIR} dump.rdb appendonly.aof rm ${BACKUP_DIR}/dump.rdb ${BACKUP_DIR}/appendonly.aof # 4. 清理超过保留天数的备份 find ${BACKUP_BASE} -type d -name 20* -mtime ${RETENTION_DAYS} -exec rm -rf {} \; echo Redis backup completed: ${BACKUP_DIR}/redis-backup-${DATE}.tar.gz这个脚本有几个细节值得单独说第一轮询LASTSAVE时间是确保BGSAVE真正完成而不是盲目 sleep 固定秒数。数据量大的时候RDB 生成可能持续好几秒固定 sleep 可能不够或者浪费等待时间。第二先拷贝两份文件再压缩归档是为了在压缩过程中不阻塞 Redis 的数据目录。如果直接在数据目录里 tar万一 Redis 此时正在写 AOF压缩包可能不完整。第三find ... -mtime 7清理逻辑配合目录命名%Y%m%d可以实现简单可靠的保留期管理。这种方式比按备份文件数量控制更直观。3.3 配置 cron 定时任务脚本写好后通过 crontab 注册定时执行crontab -e # 每天凌晨 2 点执行备份 0 2 * * * /bin/bash /path/to/scripts/redis-backup.sh /var/log/redis-backup.log 21注意WSL 的时钟在某些情况下比如 Windows 休眠恢复后会漂移导致 cron 任务不按预期时间运行。稳妥的做法是同时依赖hwclock -s同步时间或者备份任务允许一定的时间偏差。3.4 备份验证的两种有效手段备份这件事最怕的是“你以为备份了实际上文件早就损坏了”。我目前验证备份有效性有两种方式第一种针对单个备份文件用redis-check-rdb检查结构完整性方便快速排查。第二种真正可靠的验证方式临时启动一个 Redis 容器把备份文件加载进去检查关键 key 是否存在。# 用备份包启动一个临时 Redis 容器 mkdir -p /tmp/redis-restore-test tar xzf /backup/redis/20240101/redis-backup-20240101.tar.gz -C /tmp/redis-restore-test/ docker run --rm -d \ -p 6380:6379 \ -v /tmp/redis-restore-test:/data \ --name redis-restore-test \ redis:7.2-alpine \ redis-server --appendonly no # 检查 key 数量 docker exec redis-restore-test redis-cli DBSIZE检查完删掉临时容器这就完成了一次“演练式验证”。只有在真实环境里成功恢复过备份才算是真正可靠的。4. 迁移实操把 Redis 从旧环境搬到新环境4.1 明确迁移目标与场景先说迁移的典型场景开发机换了、公司配了新电脑、Windows 系统重装、或者 WSL 发行版需要重新创建。迁移的本质就是在新环境里构建一个和旧环境等价的 Redis 服务并导入原数据。迁移方案的选择取决于一个关键问题你手里还有没有旧环境的 Docker 容器如果容器还在推荐走“容器方案重组”的路径迁移成本最低如果容器已经没了只剩备份包那就走“纯数据文件恢复”路径。两条路径我都走通过下面分别展开。4.2 模型 ADocker 容器方案整体迁移这套方案的核心思想是把 compose 文件和绑定的数据目录作为一个整体整体搬到新环境再在新环境里重新拉镜像、启动容器。具体步骤第一步在旧环境里停止 Redis 容器保证数据文件的稳定一致docker-compose stop redis第二步打包整个项目目录包含docker-compose.yml和redis-data/cd /path/to/project tar czf redis-project-backup.tar.gz docker-compose.yml redis-data第三步把压缩包拷贝到新环境。拷贝方式有很多局域网可以用scp同机不同 WSL 发行版可以放到共享目录或直接用 Windows 文件系统中转。第四步在新环境解压并启动mkdir -p /path/to/project tar xzf redis-project-backup.tar.gz -C /path/to/project cd /path/to/project docker-compose up -d第五步验证用INFO keyspace查看 key 数量是否和源库一致用redis-cli GET抽查几个业务 key。提示迁移前我一般会在旧环境先做一次BGSAVE确保 RDB 快照是整个迁移过程的“最后一次全量”状态。虽然 Redis 停止时会自动生成 RDB 文件但手动再触发一次更保险。停止容器后再打包可以避免正在写入的文件被一并打包时产生文件顺序问题。4.3 模型 B纯数据文件恢复容器不迁移有些情况你的容器没了或不打算迁移完整项目只有备份档案。这时只需要从备份包中提取dump.rdb和appendonly.aof放到新环境的 Redis 数据目录即可。# 1. 创建新项目目录和 compose 文件 mkdir -p /new/project/redis-data cd /new/project cat docker-compose.yml EOF services: redis: image: redis:7.2-alpine container_name: app-redis restart: unless-stopped ports: - 6379:6379 volumes: - ./redis-data:/data command: redis-server --appendonly yes --appendfsync everysec --requirepass your-password EOF # 2. 解压备份包里的数据文件到 redis-data 目录 tar xzf /backup/redis/20240101/redis-backup-20240101.tar.gz -C ./redis-data/ # 3. 启动容器 docker-compose up -d这里有个关键的恢复顺序问题Redis 启动时如果数据目录下同时存在dump.rdb和appendonly.aof它会优先加载 AOF 文件。所以如果你迁移的数据文件只拷了其中一个要确保另一个不在数据目录中避免恢复时使用了陈旧的数据。4.4 版本兼容性Redis 镜像版本的坑迁移时最容易踩的暗坑是 Redis 版本不匹配。老版本 Redis 生成的 RDB 文件高版本也能读这个向后兼容基本没问题但高版本的 RDB 文件老版本 Redis 是读不了的因为新版本可能使用了老版本不支持的新操作码。我的建议新环境的 Redis 镜像版本不要低于旧环境最好是等于或略高。比如旧环境用redis:6.2-alpine新环境用redis:7.2-alpine没问题反过来从 7.2 迁移到 6.2 就大概率会遇到Bad file format reading the appendonly file或者Failed loading the RDB的错误。另外Redis 7.x 之后 RDB 文件格式发生了变化如果必须做跨大版本迁移有一个稳妥办法在旧环境里用redis-cli把数据通过MIGRATE命令逐个 key 搬运过去而不是直接拷贝数据文件。不过这种操作只适用于数据量不大的场景。4.5 迁移后必须检查的三个要点迁移完成不代表结束要做三项检查才算真正完成第一检查数据完整性。执行DBSIZE对比源库的 key 数量再根据业务特点抽查 3~5 个高频 key 做值比对。docker exec app-redis redis-cli -a your-password DBSIZE第二检查持久化配置是否生效。查看INFO persistence输出docker exec app-redis redis-cli -a your-password INFO persistence重点观察rdb_bgsave_in_progress、rdb_last_bgsave_status、aof_enabled几个字段确保aof_enabled:1且rdb_last_bgsave_status:ok。第三检查外部连通性。从宿主机执行redis-cli -h 127.0.0.1 -p 6379 -a your-password ping确认端口映射、防火墙、密码配置都正确。很多迁移后“连不上”的问题都是因为新环境的 Windows 防火墙拦截了端口或者protected-mode默认开启导致外部访问被拒绝。5. 常见问题与排查技巧实录5.1 WSL 重启后 Redis 数据丢失这是 WSL 用户最典型的问题。WSL 2 在 Windows 重启后不会自动启动 Linux 发行版内的服务所以 Docker 引擎不会自动运行Redis 容器自然也就没有起来。这不代表数据丢了只是你没启动 Docker。解决方案在 WSL 里配置开启 systemd 后可以设置 Docker 开机自启sudo systemctl enable docker设置了restart: unless-stopped的容器会在 Docker 引擎启动后自动拉起。所以数据丢失问题的真正原因通常不是 WSL 重启而是 Docker 引擎没启动。提醒如果你第一次进入 WSL 时发现 docker 服务没跑先执行sudo service docker start再用docker ps查看容器状态别急着重新 pull 镜像重来。5.2 Redis 启动后 dump.rdb 没有加载现象把备份的dump.rdb放到数据目录后启动容器DBSIZE返回 0数据没有恢复。排查思路先确认数据目录映射是否正确。很多人的 compose 文件里把 redis 容器的/data目录映射到宿主机某个目录但 RDB 文件的默认保存路径是 Redis 的启动参数dir指定的目录。如果启动命令里没有显式指定dir /dataRedis 可能把文件写到容器内的/或其他位置并不会主动去读/data下的文件。可以通过这个命令看容器内的实际文件情况docker exec -it app-redis ls -lh /data docker exec -it app-redis sh -c redis-cli -a your-password CONFIG GET dir如果dir不是/data需要在启动命令中加入配置command: redis-server --dir /data --dbfilename dump.rdb --appendonly yes5.3 备份文件损坏无法恢复redis-check-rdb报错或者启动日志里出现Bad file format通常有三种原因备份文件在拷贝过程中不完整比如直接在容器运行期间 copy 了正在写入的 RDB 文件磁盘空间不足导致写入截断不同架构比如 x86 迁移到 ARM环境下文件格式不兼容或字节序问题。应对措施如果dump.rdb无法恢复但 AOF 文件还在可以只保留 AOF 文件进行恢复因为 AOF 是文本协议栈容错能力比二进制格式强一些。如果两个文件都损坏了那就只能接受“备份无效”的现实所以验证备份的有效性必须纳入日常备份流程。5.4 WSL 虚拟磁盘空间不释放这个不是 Redis 本身的问题但经常和 Redis 备份一起出现——数据卷删了很多文件ext4.vhdx文件大小却纹丝不动。WSL 2 的虚拟磁盘只增不减删文件后需要手动压缩。办法是执行wsl --shutdown然后在管理员 PowerShell 里用 diskpart 压缩 vhdx 文件diskpart select vdisk fileD:\WSL\Ubuntu\ext4.vhdx compact vdisk detach vdisk exit注意compact vdisk期间 WSL 完全不可用建议放在迁移或备份操作全部完成之后再进行避免把万一需要恢复的中间数据给顶掉。5.5 迁移后 redis-cli 连接被拒现象容器正常启动了但宿主机连不上127.0.0.1:6379。排查顺序先确认容器端口映射是否生效docker ps --format table {{.Names}}\t{{.Ports}}再看 Windows 防火墙是否拦了 6379 端口最后确认 Redis 的bind配置。默认 Redis 只绑定 127.0.0.1容器内访问没问题但从宿主机访问需要端口映射配合。使用 docker-compose 的ports: 6379:6379一般不会有问题但如果哨兵实例或跨 Docker 网络访问就要仔细检查bind和protected-mode的组合配置。我的推荐做法凡是涉及密码保护的 Redis显式配置--requirepass和--protected-mode yes对外只暴露必要的端口不裸奔。6. 最后再分享一点个人体会这套备份迁移方案运行了将近一年我从最开始的手动备份到后来脚本化、定时化最大感受就是备份这件事最怕的不是技术复杂而是没有形成“验证闭环”。如果只把文件拷贝走了但从不尝试用备份数据启动一次 Redis等到真正需要恢复的那一天你根本不知道那份备份到底能不能用。所以建议你至少每个月做一次恢复演练选一台临时机器或者临时容器用最近期的备份包完整走一遍恢复流程。这个习惯花不了多少时间但能让你在危急时刻从容不迫。另外一个小技巧在备份脚本里加一行redis-check-rdb的检查命令失败时发送告警能让备份有效性得到即时反馈。备份是最后一根救命稻草平时多验证一次关键时刻就多一分保障。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。