大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
Docker 跑 Redis:持久化与生产形态
这一课你将能做到
- 用带数据卷、密码、AOF 的 docker run 命令启动一个「重启不丢数据」的 Redis,并解释每个参数
- 亲手做一次「删容器数据全丢」实验,理解 RDB 快照和 AOF 日志的分工与取舍
- 写出生产形态的 docker-compose 片段,说清容器里 host 为什么写 redis 而不是 127.0.0.1
为什么要学
第 1 课你用一行 docker run 起了 Redis——那是个「一次性玩具」:容器一删,所有 key 蒸发。而本站生产环境里 Redis 存着所有人的登录态:没有持久化,Redis 重启 = 全站用户被踢下线。
这一课补上生产视角的三块拼图:数据怎么不丢(持久化)、进程怎么常驻(restart 策略 + compose)、服务怎么被发现(容器网络里的 host)。学完你就能照着本站生产配置搭出一个像样的 Redis 实例。
先建立图像
持久化的两条路:
RDB(快照):每隔一段时间,把整个内存「拍照」存成 dump.rdb
✔ 文件小、恢复快 ✘ 两次快照之间的数据会丢
AOF(日志):每条写命令追加记录到 appendonly.aof,重启时重放
✔ 丢得少(每秒刷盘) ✘ 文件更大、恢复更慢
生产常见组合:AOF 开(everysec)+ RDB 兜底
本站会话场景:会话丢 = 用户重登 → AOF everysec 的 1 秒丢失窗口可接受
跟着做
步骤 1:复现「数据蒸发」
先确认 restart 不会丢:
docker exec -it redis-dev redis-cli
SET precious "data"
exit
docker restart redis-dev
docker exec redis-dev redis-cli GET precious # "data" 还在(重启前有 RDB 落盘)
再验证「删容器 = 一切归零」:
docker exec redis-dev redis-cli SET precious2 "gone-soon"
docker rm -f redis-dev
docker run -d --name redis-dev -p 6379:6379 redis:7-alpine
docker exec redis-dev redis-cli GET precious2
# (nil) —— 没有数据卷,容器即数据,删了就没了
步骤 2:带卷 + 密码 + AOF 重启
docker rm -f redis-dev
docker run -d --name redis-dev \
-p 6379:6379 \
-v redis-data:/data \
--restart unless-stopped \
redis:7-alpine \
redis-server --requirepass "devpass123" --appendonly yes
参数拆解:-v redis-data:/data 命名卷持久化数据目录;--restart unless-stopped 宿主机重启后容器自动拉起;--requirepass 密码认证(生产必开);--appendonly yes 开 AOF。
从这一步起,本课容器带密码,后面所有 redis-cli 命令都要带 -a devpass123。
步骤 3:验证持久化真的生效
docker exec redis-dev redis-cli -a devpass123 SET persist:test "survived"
docker restart redis-dev
docker exec redis-dev redis-cli -a devpass123 GET persist:test
# "survived" ✅
docker exec redis-dev redis-cli -a devpass123 CONFIG GET appendonly
# appendonly → yes
(-a 会把密码留在 shell 历史里,教学环境无妨;生产脚本用 --askpass 交互输入。)
步骤 4:看 RDB 和 AOF 长什么样
docker exec redis-dev ls -la /data
# dump.rdb、appendonlydir/
docker exec redis-dev sh -c 'ls -la /data/appendonlydir/'
# appendonly.aof.* :里面是 RESP 格式的写命令流
步骤 5:写一段 docker-compose(生产形态缩影)
services:
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru
ports:
- "127.0.0.1:6379:6379" # 只绑本机/内网,不对公网暴露
volumes:
- redis-data:/data
volumes:
redis-data:
注意 127.0.0.1:6379:6379——本站的安全约定是 6379(和 3306 一样)不对 0.0.0.0 暴露,应用走内网/本机访问。
步骤 6:host 写谁?——容器网络的思考题
backend 也在容器里跑时,spring.data.redis.host 应写 compose 里的服务名 redis(Docker 内置 DNS 解析);backend 裸跑在宿主机时才写 127.0.0.1。本站生产通过 REDIS_HOST 环境变量注入,两种形态都只需改环境变量,代码零改动。
讲清楚要点
- restart ≠ 持久化:restart 不删容器,数据可能靠 RDB 捡回来;rm 掉容器没有卷,数据必丢。「卷」才是数据的家。
- AOF everysec 是本站场景的甜点位:最多丢 1 秒写入 = 极端情况少数人重新登录;对缓存无感,对会话可接受。
- requirepass + 不暴露公网是最低安全配置:Redis 未授权访问是经典入侵入口(写 crontab 反弹 shell)。呼应本站「3306/6379 不开 0.0.0.0」的硬约定。
- maxmemory + allkeys-lru 是纯缓存实例标准搭配;含会话的实例容量要给足并监控(会话被挤 = 用户被踢,见第 5 课的分级讨论)。
- CONFIG SET 运行时改,CONFIG REWRITE 落盘;容器里更推荐把参数写进 command/配置文件,重启即生效。
你可能会懵的地方
-
RDB 和 AOF 同时开会冲突吗? 不冲突,互补:恢复优先用 AOF(更全),RDB 做定期快照兜底和快速恢复。
-
为什么默认配置其实也有 RDB? 默认 save 规则(如 3600 秒内 1 次修改就快照)在工作,但它救不了高频写入的实时数据——两次快照间的写入还是会丢。
-
数据卷放在哪?删卷会怎样?
docker volume inspect redis-data看路径;docker volume rm redis-data才是真正删数据,谨慎。 -
生产 Redis 要不要上集群/哨兵? 单实例 + 持久化 + 监控对本站量级足够;集群解决的是单机内存/写瓶颈,别过早设计。
-
maxmemory-policy 对会话实例该设什么? 慎用 allkeys-lru(可能挤会话)。要么容量富余 + 监控,要么会话/缓存分实例——回到「数据分级」思想。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| docker run 不挂卷 | rm 容器数据蒸发 | -v redis-data:/data |
| 6379 映射 0.0.0.0 且无密码 | 未授权访问被入侵 | 127.0.0.1 绑定 + requirepass |
| 只 restart 不持久化还当高可用 | 重启可能丢数据 | AOF + 卷 + 监控 |
| 所有实例 allkeys-lru | 会话被挤用户掉线 | 按数据类型分实例/策略 |
| backend 容器里 host 写 127.0.0.1 | 连的是容器自己 | compose 服务名 redis |
| 密码明文进 shell 历史 | 泄露 | --askpass 或环境变量 |
卡点急救
- NOAUTH Authentication required:设了密码没带。
redis-cli -a 密码或先AUTH。 - --requirepass 后旧连接全断:正常,重新带密码连接即可。
- 想重置数据:
docker volume rm redis-data前确认不再需要——这是真删数据。 - AOF 文件损坏启动失败:
redis-check-aof --fix appendonly.aof.*(先备份)。 - compose 起来 backend 连不上:确认两服务在同一网络、host 用服务名;
docker compose logs redis排查。
面试常问
-
RDB 和 AOF 怎么选? RDB 恢复快、丢窗口大;AOF 丢得少(everysec 最多 1 秒)、文件大恢复慢。生产常 AOF 为主、RDB 兜底。结合会话场景说明选择依据:1 秒丢失 = 少数人重登,可接受。
-
Redis 重启后数据还在吗? 取决于持久化:有 AOF/RDB 就在;纯内存裸跑全丢。还要分数据类型回答:缓存丢了回源重建,会话丢了用户重登,MySQL 权威数据不受影响。
-
你们 Redis 的安全配置? requirepass + 绑定内网/127.0.0.1 不对公网暴露 + 密码走环境变量;呼应本站「3306/6379 不开 0.0.0.0」的硬约定。
自测三问
- restart 和「挂了卷」分别保证了什么?删容器后哪个能救回数据?
- AOF everysec 对本站会话意味着最坏丢多少数据?为什么可接受?
- backend 在容器里时 host 应该写什么?为什么 127.0.0.1 会连错对象?
小结一句话
生产 Redis = 卷(数据的家)+ AOF(少丢)+ 密码与内网(安全)+ restart 策略(常驻),host 由部署形态决定。
延伸
- Redis 持久化官方文档
- 下一课:发布订阅——跨实例广播消息的轻量方案,以及它「不保证送达」的三大陷阱。