Redis 部署运维
商品缓存丢失后可以重新查询数据库;登录会话丢失会让用户重新认证;库存预占或消费进度丢失则可能改变业务结果。同样是 Redis,重启前需要保存什么、恢复后允许怎样补数据,取决于里面保存的数据用途。
先辨认数据用途和实例配置
| Redis 中的内容 | 恢复时的主要任务 | 需要避免的做法 |
|---|---|---|
| 可重建缓存 | 限速回源、逐步预热,检查缓存与数据库的一致性 | 一次清空全部缓存,把流量瞬间压到数据库 |
| 会话与令牌辅助状态 | 判断会话失效是否可接受,核对有效期与撤销状态 | 把已经撤销或过期的认证状态重新放回业务 |
| 计数、额度、预占 | 与持久业务流水核对,明确恢复期间的扣减结果 | 单独恢复旧计数,却继续承认恢复点之后的业务请求 |
| Stream / 消费组 | 核对消息、组位点和 pending 条目,与下游已处理结果去重 | 只比较 Key 总数就恢复消费者 |
| 分布式锁 | 等待租约、核对业务执行和 fencing 机制 | 从旧快照恢复一把锁并相信它仍有排他性 |
Redis 产品主文提供安装、类型与客户端使用。接管已有服务时,先用监控身份查版本、角色和持久化状态。以下命令在有 Redis 客户端的 Linux 管理机执行,主机名、CA 与 ACL 用户替换为真实授权配置:
redis-cli --tls --cacert /etc/redis/ca.pem \
-h cache.example.internal -p 6379 --user ops_reader --askpass在交互会话中:
INFO server
INFO replication
INFO persistence
INFO memory
INFO keyspace记录 redis_version、run_id、role、副本状态和各逻辑库的 Key/过期数量。随后由具有配置读取权限的管理员查询:
CONFIG GET dir dbfilename appendonly appenddirname appendfilename
CONFIG GET maxmemory maxmemory-policy save appendfsync配置文件与运行变量分别核对。某次 CONFIG SET 可能只改变内存中的配置,重启后又恢复旧值;使用配置管理系统的实例应修改受管理文件并走正常发布,不让自动化与 CONFIG REWRITE 互相覆盖。ACL 和 TLS 的配置细节见 Redis 安全说明。
RDB 与 AOF 决定启动加载什么
启动时 appendonly=yes
└─ 加载所配置的 AOF 数据集
└─ Redis 7+ 通常为 manifest + base + incremental 文件集合
启动时 appendonly=no
└─ 按 dir / dbfilename 查找并加载 RDB
└─ 根据对象过期时间跳过已经到期的 Key同时启用 RDB 和 AOF 时,Redis 优先使用 AOF。AOF 出错不会保证自动回退到一份“看上去更新”的 RDB。要单独验证 RDB,建立空的隔离目标并显式禁用 AOF;需要恢复 AOF 时,则保全 manifest 及其引用的文件,不挑一个 appendonly.aof 文件复制。
RDB 记录过期时刻,加载过程不会给每个 Key 重新发放一遍原始 TTL。恢复延迟越久,快照中已经到期的 Key 越多,恢复后的 Key 数量也可能更少。Redis 持久化说明解释了两类文件的恢复方式。
用独立实例验证 RDB 内容和 TTL
实验使用 Linux Bash、Docker 和 Redis 8.10.1,所有 Redis 进程显式使用 UID/GID 10001:10001,不开宿主端口,也不连接外网。源数据放在临时文件系统;目标使用新建卷以观察恢复,两个数据目录互不重叠。
mkdir redis-recovery-lab
cd redis-recovery-lab
umask 077
docker run -d --name ops3-redis-source --network none \
--user 10001:10001 --memory 256m \
--tmpfs /data:rw,uid=10001,gid=10001,mode=0750 \
redis:8.10.1 redis-server --dir /data --save "" --appendonly no
docker exec ops3-redis-source redis-cli PING应返回 PONG。这里通过 docker exec 在容器内部连接本机,没有关闭 protected mode 或公开无认证入口。若尚未就绪,检查该容器日志并再次探测,不向公网开放端口来解决本地访问问题。
取得一份完整快照
docker exec ops3-redis-source redis-cli SET order:102 NEW
docker exec ops3-redis-source redis-cli SET session:demo active EX 600
docker exec ops3-redis-source redis-cli SET transient:demo short EX 30
docker exec ops3-redis-source redis-cli --rdb /data/export.rdb
docker exec ops3-redis-source cat /data/export.rdb > dump.rdb
sha256sum dump.rdb > dump.rdb.sha256
docker exec ops3-redis-source redis-check-rdb /data/export.rdb
docker exec ops3-redis-source redis-cli SET order:102 CANCELLEDredis-cli --rdb 通过复制协议取得一份快照,返回成功后才复制文件。需要允许该复制操作的权限;真实实例上还要评估生成快照造成的 fork、写时复制和网络负载。它不捕获完成之后的后续写入。客户端行为见 redis-cli 的 RDB 模式。
如果采用服务端 BGSAVE,应先确认命令被接受,再等待 rdb_bgsave_in_progress=0,同时核对最近保存成功状态和本次文件确实更新。单独看到“后台不在运行”,也可能意味着保存从未开始或已经失败。远端存储中的备份应连同校验值、版本、模块、ACL 和配置保存,归档时避免正在轮换的文件集合产生不一致。
只让目标加载这份 RDB
目标卷应为全新的实验卷。初始化命令以 root 只修改此卷的目录属主,随后服务仍以 10001 运行:
docker volume create ops3-redis-restore
docker run --rm --network none --user 0 \
-v ops3-redis-restore:/data redis:8.10.1 \
sh -c 'chown 10001:10001 /data'
docker create --name ops3-redis-restore --network none \
--user 10001:10001 --memory 256m -v ops3-redis-restore:/data \
redis:8.10.1 redis-server --dir /data --dbfilename dump.rdb \
--save "" --appendonly no
sha256sum -c dump.rdb.sha256
docker cp dump.rdb ops3-redis-restore:/data/dump.rdb
docker run --rm --network none --user 0 \
-v ops3-redis-restore:/data redis:8.10.1 \
sh -c 'chown 10001:10001 /data/dump.rdb; chmod 0640 /data/dump.rdb'
sleep 31
docker start ops3-redis-restore检查快照时应看到包含三个 Key;若准备耗时导致短 TTL 已在取快照前到期,重新设置实验值并生成快照。sleep 31 用于让快照中的三十秒 TTL 到期。服务启动后执行:
docker exec ops3-redis-restore redis-cli GET order:102
docker exec ops3-redis-source redis-cli GET order:102
docker exec ops3-redis-restore redis-cli GET transient:demo
docker exec ops3-redis-restore redis-cli TTL session:demo
docker exec ops3-redis-restore redis-cli INFO persistence目标订单为 NEW,源订单为 CANCELLED;短 TTL 的 Key 已不存在。会话 TTL 应小于 600 且继续减少;若实际操作耗时超过十分钟,它也会过期,TTL 返回 -2。这项实验检查的是值与时间语义,不要求所有机器恢复后得到同一个 Key 数量。
不能使用较旧 Redis 二进制直接读取较新版本文件而假定兼容。加载失败时先看日志中的格式、模块缺失或权限错误,在保留原备份的前提下修复隔离目标,不对原件执行修复选项。
恢复账号也要限制命令
在目标为应用建立只读实验用户:
docker exec ops3-redis-restore redis-cli ACL SETUSER app_reader \
on '>LabOnly-Redis-83' '~order:*' +get +ping
docker exec -e REDISCLI_AUTH=LabOnly-Redis-83 ops3-redis-restore \
redis-cli --user app_reader GET order:102
docker exec -e REDISCLI_AUTH=LabOnly-Redis-83 ops3-redis-restore \
redis-cli -e --user app_reader SET order:102 PAIDGET 返回 NEW,SET 返回 NOPERM。最后的 -e 使 Redis 错误响应产生非零退出状态;不能只看 TCP 连接已建立。实验用户配置只在内存中,真实实例需要按 ACL 文件或配置管理方式持久化,且所有可能接替服务的节点都要有匹配权限。
检查后执行 docker stop ops3-redis-source ops3-redis-restore。源容器的 tmpfs 随停止释放,目标卷和下载的快照保留;源中的示例数据没有业务用途。
切换之后,应用究竟连到了哪里
Sentinel 需要客户端重新发现主节点
Sentinel 保存主节点发现信息并组织故障转移,业务数据仍由 Redis 主副本保存。一个常见失败是 Sentinel 已完成切换,应用仍使用写死的旧主地址,或者拿到了容器内部不可达的地址。
在已授权的 Sentinel 会话中执行以下只读查询;连接时使用该 Sentinel 的 TLS、端口和 ACL 配置,不能把数据节点凭据当作必然通用:
SENTINEL get-master-addr-by-name cache-main
SENTINEL replicas cache-main
SENTINEL ckquorum cache-maincache-main 替换为真实监控组名。取得地址后,从应用所在网络连接该地址,检查 ROLE 并执行一条受权限保护的业务读写。若 Sentinel 能查到主节点而应用连接失败,优先检查 announce 地址、NAT、TLS 主机名和客户端发现配置。
Sentinel 判断下线所需的 quorum 与授权故障转移所需的 Sentinel 多数派是两道条件。Redis 数据复制是异步的,选举成功后仍可能缺少旧主上已经确认的写入。旧主重新出现时,先确保它无法承接业务写入,再确认已转为副本并完成同步。具体行为见 Sentinel 官方说明。
Cluster 还需要检查槽与重定向
Cluster 把 Key 映射到 16384 个槽,各主节点只保存自己负责的部分;给一个节点做 RDB 备份不能恢复整个 Cluster。每个分片的恢复点与跨分片业务状态需要一起考虑。
在现有节点的授权会话中查询:
CLUSTER INFO
CLUSTER NODES
CLUSTER SHARDS核对槽覆盖、主副本、迁移状态与错误标记。应用必须支持 Cluster 路由,并能访问返回的所有节点地址;只打通种子节点端口仍可能在收到 MOVED 后失败。ASK 是槽迁移中的临时访问提示,处理方式与更新长期槽映射的 MOVED 不同。Cluster 规范说明了这两种重定向。
维护前逐个确认待停节点负责的槽有可用副本,以及其他节点仍满足选举条件。节点返回后看同步与槽状态,再让应用跨多个真实 Key 执行读写。不要用创建新集群或自动修槽命令处理一个身份不明的既有集群。
内存、延迟和持久化怎样一起判断
maxmemory 只约束一部分内存
容器 / 主机内存预算
├─ Redis 数据集和对象开销
├─ 复制及客户端缓冲
├─ allocator 碎片与运行开销
└─ BGSAVE / AOF rewrite 的写时复制峰值maxmemory 不能直接等于容器内存上限。实例在 steady state 很稳定,也可能在后台保存时因大量页面修改触发 COW,随后被 OOM killer 终止。查询 INFO memory、INFO persistence,同时查看容器 OOMKilled 和内存用量,才能区分 Redis 主动拒绝写与宿主强制杀进程。
noeviction 会在达到限制时拒绝需要额外内存的写入;allkeys-lru 等策略会淘汰 Key。会话、额度与缓存共用实例时,不能简单为缓解 OOM 把策略改成全 Key 淘汰。先确认允许失去的内容,必要时分开实例。策略与特殊内存口径见 Key 淘汰说明。
如果流量稳定但 used_memory_rss 持续远高于 used_memory,再分析碎片与分配行为。增加容量应同时留给数据增长、持久化峰值和故障切换后的客户端重连,不能把某个固定百分比当成所有实例通用的余量。
延迟升高,先看耗时落在哪一段
INFO stats
INFO clients
SLOWLOG LEN
SLOWLOG GET 10
LATENCY LATEST慢日志主要记录命令执行耗时,不包含完整客户端排队和网络往返。客户端 P99 高而慢日志安静时,还要看连接池等待、网络、主线程被系统调度暂停、AOF fsync 与持久化 fork。日志中出现命令参数可能暴露业务内容,只在受限环境查看。
大 Key 扫描使用受控速率的 SCAN 或客户端扫描工具,在低峰观察额外 CPU 和网络成本;不要在大库执行 KEYS *。定位到具体 Key 后先查 TYPE、对应长度和 MEMORY USAGE,再决定拆分、调整访问方式或异步删除。删除大对象前还要确认它是否保存消费进度、锁或业务唯一状态。
保存失败需要先修底层条件
rdb_last_bgsave_status:err、aof_last_write_status:err 或 MISCONF 出现时,检查数据挂载空间、inode、属主、只读挂载、持久化峰值内存和最近服务日志。
修复存储后重新触发一次受控保存,等待结束并检查状态,再用备份文件恢复。关闭 stop-writes-on-bgsave-error 只会改变失败时是否拒绝写入,不会修复备份能力。AOF 损坏先停止并复制完整原件;检查工具默认只检查,--fix 可能截断尾部数据,必须在副本上做并明确丢失范围。
恢复缓存时控制回源
空缓存会把原来被 Redis 吸收的读取集中到数据库;恢复旧快照则可能返回过期业务值。选哪条路要根据数据可重建性、TTL、数据库容量和一致性要求判断。
可重建缓存通常先恢复热点查询、限制重建并发,并设置过期分散;需要强约束的状态则从业务流水重建或对账。重新开放流量后,联合观察命中率、回源 QPS、数据库 P99、Redis 错误和淘汰增长。等负载回到稳定区间,再扩大流量或继续预热。
权威资料与规范地址
加载、身份与备份
- Redis 安全:https://redis.io/docs/latest/operate/oss_and_stack/management/security/
- 持久化:https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/
- redis-cli:https://redis.io/docs/latest/develop/tools/cli/
