Redis 部署方式、架构选型与提效工具手册
先判断 Redis 在系统里承担什么状态
Redis 不是“能 PING 就行”的缓存。它是高并发链路里最容易被低估的状态组件:没有 schema,key 写入成本极低,误删和误连也极快;同时它又承担缓存、会话、限流、排行榜、分布式锁、队列、流式数据、向量和搜索等多种角色。
先给每类 key 标记角色:可回源缓存、不可丢会话、限流计数、锁、队列或事实数据。这个标记会直接决定 TTL、淘汰策略、持久化、复制、备份和故障降级方式。可回源缓存可以接受淘汰,不可丢状态却不能与它共享 allkeys-lru;单个热 key 也不会因为上了 Cluster 自动分散。
当需求进入搜索、JSON、向量、Stream 或概率数据结构时,应重新评估数据模型、客户端和容量,而不是把普通缓存配置原样套上去。考虑 Valkey 或 Memcached 时,也要分别验证命令、客户端、持久化、高可用与许可证,不能把“协议大体兼容”当成可直接替换。
在隔离环境里准备第一次启动
开始操作需要:
Docker Engine 或 Docker Desktop,并确认 docker compose version 可用。一个只用于实验的项目目录,例如 your-project/。本机端口 6379 预留给实验。如果本机已经有 Redis,后续用 .env 改成 6380 或其他端口。
redis-cli。可以使用本机安装的 CLI,也可以使用容器里的 CLI。Java 项目如果要验证 Spring 接入,准备 JDK、Maven / Gradle 和 Spring Boot 本地 profile。不要把生产 Redis 地址、真实密码、云厂商连接串、内网域名、真实 key 前缀写进项目模板和截图。
先确认 Docker、端口和现有容器:
docker version
docker compose version
docker ps --format "table {{.Names}}\t{{.Ports}}"Windows 可以查端口:
netstat -ano | findstr 6379Linux / macOS 可以查端口:
lsof -i :6379如果端口已经被占用,不要把项目临时连到共享 Redis 或生产 Redis。先换本机端口,或者停掉确认无用的旧容器。
先冻结版本、镜像和许可选择
Redis Open Source 8.8 已发布,下面的开发模板固定使用 redis:8.8.0,避免 latest 在重建时悄悄改变二进制和持久化格式。升级前应同时检查 release notes、Docker 镜像标签、安全公告和客户端兼容矩阵,并把镜像 digest 写入环境清单。
版本选择还会改变许可路径:
Redis 8 起可在 RSALv2、SSPLv1、AGPLv3 中选择一种;Redis 7.2.x 及更早版本是 BSD-3-Clause;Redis Community Edition 7.4.x 到 7.8.x 是 RSALv2 / SSPLv1。涉及再分发、客户现场交付或托管服务时,由法务或合规 owner 针对交付方式确认选择,不能沿用“Redis 一直是 BSD”的旧印象。
官方 Docker 文档说明可以用 redis:<version> 启动容器,配置文件常见挂载路径是 /usr/local/etc/redis/redis.conf,持久化数据目录是 /data。Docker Official Image 为了容器网络易用,默认关闭 protected mode。如果你把端口发布到宿主机外部,而且没有密码或 ACL,风险会被放大。Redis 官方安全文档强调 Redis 端口应只暴露给可信客户端;外部不可信访问必须通过防火墙、ACL、认证和应用层控制。
Redis 6 之后推荐用 ACL,ACL 可以限制命令和 key 访问范围;requirepass 仍能用,但本质上是在设置 default 用户密码,不适合作为团队共享环境的长期治理模型。redis-cli -a 会把密码放进命令历史和进程参数里。官方 CLI 文档建议用 REDISCLI_AUTH 自动提供密码;URI 支持 redis://user:password@host:port/db,TLS 使用 rediss://。
KEYS 的复杂度是 O(N),并且属于 @dangerous 类命令;日常排查和清理应使用 SCAN 分批迭代。Spring Boot 使用 spring.data.redis.* 属性配置 Redis;spring.data.redis.url 会覆盖 host、port、username、password 和 database 等分散配置。不要同时写 URL 和分散字段却不知道谁生效。
Spring Data Redis 抽象了 RedisConnectionFactory、RedisTemplate 等入口,但底层连接和驱动仍有线程安全、池化、阻塞命令和事务语义差异,不能把“能连上”当成“团队可长期稳定使用”。Redis 持久化不是单一开关。官方文档把持久化分为 RDB、AOF、无持久化以及 RDB + AOF 组合;RDB 更适合备份和灾难恢复,AOF 更适合降低数据丢失窗口,但会带来 rewrite、磁盘和恢复时间取舍。
Redis 复制默认是异步复制。WAIT 可以作为更强确认的辅助工具,但不能把 Redis 改造成强一致 CP 系统;故障切换仍可能丢失刚确认不久的写入。Redis Sentinel 面向非 Cluster Redis 的高可用,负责监控、通知、故障转移和给客户端提供主库发现,不负责数据分片。Redis Cluster 通过多个节点自动分片并提供一定可用性,但不是“无限扩容”。多数 master 不可用时集群不可用;客户端必须正确处理 MOVED、ASK、拓扑刷新和连接池。
Redis Cluster 的 key space 是 16384 个 hash slots;多 key 操作只有在 key 落到同一个 slot 时才稳定可用,常见做法是使用 hash tag,例如 {user:1000}:profile 和 {user:1000}:cart。Redis Cluster 只支持 DB 0,不能用 SELECT 1 这类 DB index 做环境隔离。准备上 Cluster 的项目必须提前把 DB index 依赖清掉。
RedisInsight 可以作为 GUI/CLI 排障工具,但连接模板、许可口径、生产只读账号和截图脱敏必须单独治理,不能默认让开发者保存生产写权限连接。
这些版本事实最终要落进模板:固定镜像 tag 和 digest;用配置、ACL 文件或启动参数启用认证,因为官方镜像不会自动解释 REDIS_PASSWORD;不用 DB index 代替账号、网络和清理隔离;从日常账号权限中移除 KEYS、FLUSHDB 与 FLUSHALL。
Redis 的入口分两层:开发者先解决“怎么安全跑起来”,架构师还要解决“团队和生产到底该选哪种形态”。先看开发入口,再看生产形态,不要把单容器命令误认为架构方案。
开发入口选择建议:
| 方式 | 适合场景 | 不适合 |
|---|---|---|
| 本机安装 | 需要 redis-cli、调客户端、调系统服务或验证本机包行为 | 新人快速清理、多版本并存、项目依赖复现 |
| Docker 单容器 | 临时验证 Redis 命令、复现连接问题、写最小 Demo | 团队长期模板、多服务联调 |
| Docker Compose | 项目级联调、CI 本地复现、新人一键启动 | 完整生产部署 |
| 共享开发实例 | 多服务共用测试数据、低配置电脑无法跑本地依赖 | 无 owner、无 ACL、无 key prefix、无清理窗口的团队 |
生产和团队共享形态的选择建议:
| 形态 | 架构组成 | 适合 | 核心短板 |
|---|---|---|---|
| 单机单实例 | 一个 Redis 进程,一个数据目录 | 本机开发、小工具、低价值缓存、临时环境 | 单点故障、容量受单机限制、无自动切换 |
| 单机多实例 | 一台机器多个 Redis 进程,端口和数据目录隔离 | 测试环境、多项目轻量隔离、低成本联调 | 共享硬件故障域,资源抢占明显 |
| 主从复制 | 一主多从,读写分工或备份读 | 中小业务、读多写少、需要副本 | 默认异步复制,存在延迟和故障切换窗口 |
| Sentinel 高可用 | 主从 + 多个 Sentinel + Sentinel-aware 客户端 | 非分片 Redis 的自动故障转移 | 不解决分片,客户端发现和脑裂防护要验证 |
| Redis Cluster | 多 master 分片 + replica,客户端支持 Cluster | 数据量和吞吐超过单机,需要水平扩展 | 多 key、事务、DB index、reshard、热点 slot 都会影响应用设计 |
| K8S / Operator | StatefulSet 或 Operator 管理 Redis / Sentinel / Cluster | 平台团队统一托管、弹性资源和标准化交付 | 存储、网络、Pod 调度、升级和故障演练复杂 |
| 云化托管 | 云 Redis / 兼容 Redis 服务 | 中小团队、快速生产、少运维 | 成本、规格、兼容性、网络、权限和厂商能力边界要持续复核 |
这些形态解决的是不同问题:单机负责低延迟,主从负责副本,Sentinel 负责非分片高可用,Cluster 负责分片扩容,托管云负责降低运维负担。把它们混成“Redis 集群”四个字,会让后续排障和容量规划从一开始就站错地方。
本机安装边界
本机安装可选择 Docker、APT、RPM、Snap、Homebrew、Windows Docker 或源码构建。包管理安装适合固定开发机,Docker 更适合项目级隔离和重置,源码构建适合验证编译选项与补丁,不应成为普通团队的默认分发方式:
如果只是为了拿 redis-cli,优先安装 CLI 或使用容器内 CLI,不一定要在本机启动 Redis 服务。Windows 开发机优先使用 Docker 或 WSL 方式验证 Redis 服务端,避免每个人本机服务差异过大。本机安装必须记录来源、版本、服务名、端口、配置文件位置、数据目录、升级方式和卸载方式。
新项目默认不要依赖“每个人机器上都装了 Redis”。团队默认入口应放在 Compose 或测试支撑工具里。
本机安装后至少验证:
redis-cli --version
redis-cli -h 127.0.0.1 -p 6379 PING如果这一步失败,先排查端口、服务状态、protected mode 和密码,不要直接修改应用代码。
Docker 单容器入口
个人快速验证可以用单容器:
docker run --rm --name redis-smoke -p 127.0.0.1:6379:6379 redis:8.8.0另开一个终端验证:
docker exec -it redis-smoke redis-cli PING单容器入口只适合临时验证。它没有团队 ACL、key prefix、.env.example、健康检查、持久化目录和清理脚本,所以不要把这条命令当成项目模板。
推荐把 Redis 开发依赖收进项目目录,而不是散落在每个人机器上。
your-project/
compose.yaml
.env.example
cache/
redis/
redis.conf
verify/
verify.redis
docs/
dependency-setup.md
scripts/
cache-scan.sh
cache-reset.sh.env.example
REDIS_IMAGE=redis:8.8.0
REDIS_HOST_PORT=6379
REDIS_KEY_PREFIX=dev:your-project:
REDIS_DATABASE=0
REDIS_MAXMEMORY=256mb
REDIS_MAXMEMORY_POLICY=noeviction
REDIS_APP_USER=app_dev
REDIS_APP_PASSWORD=YOUR_REDIS_APP_PASSWORD
REDIS_READONLY_USER=cache_readonly
REDIS_READONLY_PASSWORD=YOUR_REDIS_READONLY_PASSWORD
REDIS_OPS_USER=cache_ops
REDIS_OPS_PASSWORD=YOUR_REDIS_OPS_PASSWORD真实 .env 不提交。.env.example 只告诉团队需要哪些变量。
REDIS_KEY_PREFIX 必须带环境、项目和模块语义,例如:
dev:your-project:
dev:your-project:billing:
local:<developer>:your-project:不要用 test:、demo:、cache: 这类太宽的前缀。共享环境里它们很快会变成没人敢删的公共垃圾堆。
compose.yaml
services:
redis:
image: ${REDIS_IMAGE:-redis:8.8.0}
container_name: your-project-redis
ports:
- "127.0.0.1:${REDIS_HOST_PORT:-6379}:6379"
environment:
REDIS_APP_USER: ${REDIS_APP_USER:-app_dev}
REDIS_APP_PASSWORD: ${REDIS_APP_PASSWORD}
REDIS_READONLY_USER: ${REDIS_READONLY_USER:-cache_readonly}
REDIS_READONLY_PASSWORD: ${REDIS_READONLY_PASSWORD}
REDIS_OPS_USER: ${REDIS_OPS_USER:-cache_ops}
REDIS_OPS_PASSWORD: ${REDIS_OPS_PASSWORD}
REDIS_KEY_PREFIX: ${REDIS_KEY_PREFIX:-dev:your-project:}
command:
- sh
- -lc
- |
set -eu
: "$${REDIS_APP_PASSWORD:?REDIS_APP_PASSWORD is required}"
: "$${REDIS_READONLY_PASSWORD:?REDIS_READONLY_PASSWORD is required}"
: "$${REDIS_OPS_PASSWORD:?REDIS_OPS_PASSWORD is required}"
cat > /tmp/users.acl <<EOF
user default off
user $${REDIS_APP_USER} on >$${REDIS_APP_PASSWORD} ~$${REDIS_KEY_PREFIX}* +@read +@write +@connection +ping -@dangerous +acl|whoami
user $${REDIS_READONLY_USER} on >$${REDIS_READONLY_PASSWORD} ~$${REDIS_KEY_PREFIX}* +@read +@connection +ping -@dangerous +acl|whoami
user $${REDIS_OPS_USER} on >$${REDIS_OPS_PASSWORD} ~$${REDIS_KEY_PREFIX}* +@read +@connection +ping -@dangerous +acl|whoami +acl|list +config|get +info +slowlog|get +client|list
EOF
exec redis-server /usr/local/etc/redis/redis.conf --aclfile /tmp/users.acl
volumes:
- redis-data:/data
- ./cache/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
- ./cache/redis/verify:/verify:ro
healthcheck:
test: ["CMD-SHELL", "REDISCLI_AUTH=\"$${REDIS_APP_PASSWORD}\" redis-cli --user \"$${REDIS_APP_USER}\" PING | grep PONG"]
interval: 10s
timeout: 5s
retries: 12
restart: unless-stopped
volumes:
redis-data:
name: your-project-redis-data这里有几件事是故意写清楚的:
宿主机端口绑定到 127.0.0.1,不是 0.0.0.0。个人本机开发默认不把 Redis 暴露给局域网。Redis 官方镜像不会自动读取 REDIS_PASSWORD。下面的启动命令先生成 ACL 文件,再通过 --aclfile 启动 Redis。default 用户关闭,应用账号只能访问 REDIS_KEY_PREFIX 前缀下的 key。
readonly 账号只能读,ops 账号用于排障查看 INFO、SLOWLOG GET、CLIENT LIST 这类状态。共享环境里排障账号也要有 owner。-@dangerous 放在授权规则后面,确保 FLUSHALL、FLUSHDB、KEYS 这类危险命令不被日常账号拿到。volume 明确命名为 your-project-redis-data,方便排障和清理。
healthcheck 只证明 Redis 认证和 PING 可用,不证明 prefix、TTL、写入和清理都正确,所以后面还要跑完整验证脚本。
这里的 ~dev:your-project:* 是命令访问约束,不是租户级数据隔离。它会阻止应用账号读取或修改其他前缀的 value,但不会替 SCAN 过滤返回结果;由于 +@read 包含 SCAN,同一实例中的账号仍可能枚举其他项目的 key 名。key 名只要含用户标识、订单号或业务事件,就已经构成元数据泄漏。这个 Compose 适合本机和可信团队联调;互不信任的项目、客户数据或需要隐藏 key 名的环境必须拆实例或使用具备独立数据平面的托管边界,不能只靠 ACL pattern。
如果团队要扩展 cache_ops 权限,不要直接加 +@admin,也不要为了查看 key 就直接加 +@keyspace。@keyspace 会把部分 key 生命周期命令一起带进来,排障账号很容易从“只读观察”变成“能改 TTL、能删 key”。先列出排障命令,再用 ACL DRYRUN 验证每条命令是否只覆盖预期范围。
cache/redis/redis.conf
bind 0.0.0.0
protected-mode no
port 6379
dir /data
appendonly yes
appendfilename "appendonly.aof"
save 60 1
databases 16
maxmemory 256mb
maxmemory-policy noeviction
loglevel notice为什么开发容器使用 protected-mode no?
容器内要允许同一个 Compose 网络里的应用服务访问 Redis。宿主机端口已经绑定到 127.0.0.1,不是对局域网开放。ACL 已经关闭 default 用户并要求认证。
如果你要做小团队共享 Redis,不要直接复制这个本机配置到内网机器。共享实例必须额外确认防火墙、内网访问范围、TLS、ACL 用户、审计和清理窗口。
cache/redis/verify/verify.redis
PING
ACL WHOAMI
SET dev:your-project:smoke ok EX 60
GET dev:your-project:smoke
TTL dev:your-project:smoke
DEL dev:your-project:smoke
SCAN 0 MATCH dev:your-project:* COUNT 20这份文件是阅读辅助。实际执行时不要把 prefix 写死在脚本里,要从 REDIS_KEY_PREFIX 读取。
凭证更安全的变体
本地开发可以用 .env,但 .env 里的值会进入 Compose 环境变量和部分本机工具上下文。对共享开发实例或更严格团队,建议改成 Compose secrets 或团队密码管理器注入。
Compose secrets 的本质是把文件挂载到容器里,不是 Redis 会自动识别这些文件。你仍然需要在启动脚本里读取 /run/secrets/...,再生成 ACL 文件或配置文件。
示意:
secrets:
redis_app_password:
file: ./secrets/redis_app_password.txt启动脚本里读取:
REDIS_APP_PASSWORD="$(cat /run/secrets/redis_app_password)"不管用 .env 还是 secrets,仓库里只能保留占位符和变量名,不能保留真实密码。
先把 .env.example 复制成 .env,填入只用于本地开发的长随机密码。密码尽量使用字母、数字、下划线、横线这类 CLI 友好的字符;如果必须包含空格、引号或 shell 特殊字符,要额外验证 ACL 文件生成和 URI 编码。
启动 Redis:
docker compose up -d redis
docker compose ps redis看日志:
docker compose logs redis --tail 120容器健康后,用容器内 redis-cli 验证。这里故意使用 REDISCLI_AUTH,避免把密码写在命令参数里。
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" PING
redis-cli --user "$REDIS_APP_USER" ACL WHOAMI
redis-cli --user "$REDIS_APP_USER" SET "${REDIS_KEY_PREFIX}smoke" ok EX 60
redis-cli --user "$REDIS_APP_USER" GET "${REDIS_KEY_PREFIX}smoke"
redis-cli --user "$REDIS_APP_USER" TTL "${REDIS_KEY_PREFIX}smoke"
redis-cli --user "$REDIS_APP_USER" DEL "${REDIS_KEY_PREFIX}smoke"
redis-cli --user "$REDIS_APP_USER" SCAN 0 MATCH "${REDIS_KEY_PREFIX}*" COUNT 20
'预期结果至少能看到:
PONG
app_dev
OK
ok
60 到 1 之间的整数
1再做 ACL 反向验证。应用账号只能访问本项目 prefix,下列命令应该失败:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" SET "other-project:smoke" bad EX 60
'预期结果:
NOPERM this user has no permissions to access one of the keys used as arguments再验证危险命令被禁:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" KEYS "*"
redis-cli --user "$REDIS_APP_USER" FLUSHDB
'预期结果是 NOPERM。如果这里返回了真实 key 列表或 OK,说明 ACL 规则有严重问题,不能进入共享环境。
再验证只读和排障账号不会写入、改 TTL 或删除 key:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_READONLY_PASSWORD"
redis-cli --user "$REDIS_READONLY_USER" GET "${REDIS_KEY_PREFIX}smoke"
redis-cli --user "$REDIS_READONLY_USER" DEL "${REDIS_KEY_PREFIX}smoke"
redis-cli --user "$REDIS_READONLY_USER" EXPIRE "${REDIS_KEY_PREFIX}smoke" 10
redis-cli --user "$REDIS_READONLY_USER" UNLINK "${REDIS_KEY_PREFIX}smoke"
export REDISCLI_AUTH="$REDIS_OPS_PASSWORD"
redis-cli --user "$REDIS_OPS_USER" INFO memory | sed -n "1,10p"
redis-cli --user "$REDIS_OPS_USER" SLOWLOG GET 5
redis-cli --user "$REDIS_OPS_USER" DEL "${REDIS_KEY_PREFIX}smoke"
'预期结果:只读账号可以 GET,但 DEL、EXPIRE、UNLINK 返回 NOPERM;ops 账号可以看状态,但删除同样返回 NOPERM。如果 ops 账号能删 key,它就不是排障账号,而是高风险运维账号,不能默认下发给开发和测试。
最后从宿主机验证端口映射。不要把密码写进命令历史:
PowerShell:
$env:REDISCLI_AUTH = "YOUR_REDIS_APP_PASSWORD"
redis-cli -h 127.0.0.1 -p 6379 --user app_dev PING
Remove-Item Env:\REDISCLI_AUTHBash / Zsh:
REDISCLI_AUTH='YOUR_REDIS_APP_PASSWORD' \
redis-cli -h 127.0.0.1 -p 6379 --user app_dev PING如果宿主机没有 redis-cli,继续使用容器内 CLI,不要为了验证临时把密码写进应用配置。
项目接入最容易犯三个错:容器内外 host 写错、key 没有统一 prefix、TTL 只靠业务同学“记得设置”。
连接地址
宿主机运行应用时:
redis://app_dev:YOUR_REDIS_APP_PASSWORD@127.0.0.1:6379/0应用和 Redis 同在一个 Compose 网络里时:
redis://app_dev:YOUR_REDIS_APP_PASSWORD@redis:6379/0这里的差异很重要:
127.0.0.1:6379 是宿主机访问容器映射端口。redis:6379 是 Compose 网络内通过 service name 访问容器端口。密码里如果有 @、:、/、#、空格等 URI 特殊字符,要 URL encode;否则优先用分散属性注入,不把密码拼进 URI。
如果共享环境启用 TLS,URI scheme 要用 rediss://,并配置 CA 证书或 SSL bundle。
Spring Boot 本地 profile
当前 Spring Boot 文档使用 spring.data.redis.* 作为 Redis 配置入口;项目如果还在 Spring Boot 3.x,要按本项目依赖版本确认属性名和默认客户端:
spring:
data:
redis:
host: 127.0.0.1
port: 6379
username: ${REDIS_APP_USER:app_dev}
password: ${REDIS_APP_PASSWORD}
database: ${REDIS_DATABASE:0}
timeout: 3s
connect-timeout: 3s
client-type: lettuce
client-name: your-project-local
lettuce:
pool:
enabled: true
max-active: 8
max-idle: 4
min-idle: 1
max-wait: 2s
app:
cache:
key-prefix: ${REDIS_KEY_PREFIX:dev:your-project:}
default-ttl: 10m如果你改用 URL:
spring:
data:
redis:
url: redis://app_dev:YOUR_REDIS_APP_PASSWORD@127.0.0.1:6379/0要记住:spring.data.redis.url 会覆盖 host、port、username、password 和 database。团队模板不要同时给两套配置却不说明优先级。
最小启动自检
Spring 项目可以在本地 profile 加一个只在开发环境启用的自检。关键是 key 要带统一 prefix,并且写入时设置 TTL。
import java.time.Duration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@Component
@Profile("local")
class RedisLocalVerifier implements ApplicationRunner {
private final StringRedisTemplate redis;
private final String keyPrefix;
RedisLocalVerifier(
StringRedisTemplate redis,
@Value("${app.cache.key-prefix}") String keyPrefix) {
this.redis = redis;
this.keyPrefix = keyPrefix;
}
@Override
public void run(ApplicationArguments args) {
String key = keyPrefix + "startup-smoke";
redis.opsForValue().set(key, "ok", Duration.ofSeconds(60));
String value = redis.opsForValue().get(key);
Long ttl = redis.getExpire(key);
redis.delete(key);
if (!"ok".equals(value) || ttl == null || ttl <= 0) {
throw new IllegalStateException("Redis local verifier failed");
}
}
}这个自检不是业务逻辑,只证明本地 Redis 连接、写入、读取、TTL 和删除都可用。共享环境可以保留同类自检,但 key 必须带环境和项目 prefix,不能写进生产 profile。
序列化和 TTL 边界
开发环境也要固定三件事:
key 命名:{env}:{project}:{module}:{business-key}。value 序列化:字符串、JSON、JDK 序列化、MessagePack 等必须由项目模板决定,不能每个模块自己猜。TTL 默认值:缓存类 key 必须有默认 TTL;没有 TTL 的 key 必须登记 owner 和清理策略。
项目接入模板必须给缓存写入设置默认 TTL,避免“永不过期测试 key”长期污染共享 Redis;确需永久保存的 key 要登记 owner、容量预算和删除流程。
Redis 解决的核心架构问题
从工具效率角度看,Redis 首先解决三类开发现场问题:
让高频读取绕开慢数据源:例如配置、会话、商品详情、权限缓存和短期计算结果。让瞬时状态有低延迟共享位置:例如限流计数、验证码、登录态、排行榜、任务状态。让本地开发能复现“有状态中间件”:项目不用连生产或共享环境,也能验证缓存命名、TTL、序列化、连接池和清理。
但架构师不能只看到“快”。Redis 的核心瓶颈也很清楚:
| 瓶颈 | 典型现象 | 架构判断 |
|---|---|---|
| 单线程命令执行 | 慢命令拖住所有请求 | 控制单命令耗时,禁大 key 阻塞操作 |
| 单机内存上限 | used_memory 持续增长、OOM、驱逐 | 先做 key/TTL 治理,再判断扩容或 Cluster |
| 热 key | 单 key QPS 过高,CPU 或网卡集中 | 拆 key、局部缓存、读写合并、业务降级 |
| 大 key | GET / HGETALL / 删除卡顿 | 拆分结构、分页访问、UNLINK 异步删除 |
| 复制延迟 | 读从库读到旧值,切换丢最新写 | 核心读走主库,监控 master_link_status 和 offset 差 |
| 持久化开销 | AOF rewrite、RDB fork、磁盘写满 | 给磁盘、内存和恢复时间留预算 |
| 客户端连接膨胀 | maxclients、连接等待、连接风暴 | 连接池上限、超时、重试和熔断要进模板 |
因此 Redis 的落地判断必须同时覆盖两个层次:开发者怎样安全使用;架构师怎样判断单机、主从 / Sentinel、Cluster 的切换时机,以及何时应改变数据与流量设计,而不是继续堆叠 Redis 节点。
主流生产架构
单机实例
单机架构由一个 Redis 进程、一个数据目录和一组客户端组成。它的价值是简单、低延迟、便宜,适合本地开发、内部系统、低价值缓存和可重建数据。
短板也非常直接:
进程、机器、磁盘任一故障都会导致服务不可用。内存容量、CPU 和网卡都受单机限制。没有自动故障转移。
备份和恢复需要单独设计。
单机能不能进生产,不取决于 Redis 多快,而取决于数据是否可丢、业务是否可降级、恢复时间是否可接受。若缓存可以完全从数据库回源重建,且短时不可用可降级,单机或托管基础版可能够用;若承载会话、限流、库存状态、支付风控状态,就不能用“缓存而已”降低要求。
主从复制
主从架构由 1 个主库和 N 个副本组成。主库负责写,副本复制数据,可用于读扩展、备份读取或故障切换候选。
核心能力:
有副本,主库故障后具备切换基础。可把部分读流量放到副本,但要接受延迟。可从副本做备份,降低主库压力。
核心问题:
Redis 默认异步复制,主库写入确认不代表副本已经持久收到。主从延迟会导致读旧值,尤其是写后立刻读从库。手动切换容易遗漏客户端配置、DNS、连接池和旧主隔离。
复制不能替代备份,错误写入和误删会被复制到副本。
验证入口:
redis-cli INFO replication
redis-cli ROLE重点看:
role:master / role:slave
connected_slaves
master_link_status
master_repl_offset
slave_repl_offset
master_replid如果业务依赖读写一致性,读写分离不能简单“读请求都走副本”。核心读、写后读、幂等校验、支付状态和权限状态要走主库或业务兜底。
Sentinel 高可用
Sentinel 架构是在主从复制之上增加多个 Sentinel 进程。Sentinel 负责监控主库、投票判断故障、选举新主库、通知客户端和提供当前主库发现。
它适合不需要分片、但需要自动故障转移的 Redis。典型组成:
client -> sentinel set -> current master
-> replicas落地注意:
Sentinel 不负责分片,也不让单个 Redis 变成多写。客户端必须支持 Sentinel 发现,不能写死旧主库地址。Sentinel 节点数量、quorum、网络分区和旧主隔离要演练。
故障切换后连接池要能刷新主库,不要继续写旧主。Sentinel 只解决“谁是主”,不解决误删、容量、慢命令和大 key。
最小验证入口:
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli INFO replication团队真正要验证的是切换链路:主库停止后,Sentinel 是否完成选主,客户端是否发现新主,旧主恢复后是否变成副本,写入是否仍然落到正确节点。
Redis Cluster 分片架构
Redis Cluster 由多个 master 分片和各自 replica 组成。它把 key 分布到 16384 个 hash slots 上,客户端根据 slot 找到对应节点。它解决的是单机容量和吞吐瓶颈,同时提供一定可用性。
Redis Cluster 的架构约束要提前告诉开发:
不是一致性哈希,而是 16384 slots。不是代理集中转发,客户端会收到 MOVED / ASK 并刷新拓扑。多 key 操作必须落到同一个 slot;需要用 hash tag,例如 {order:1001}:base 和 {order:1001}:items。
只支持 DB 0,SELECT 不可用。reshard 会移动 slot,big key 会让迁移和延迟变得很难看。多数 master 不可用时,Cluster 也会不可用。
最小验证入口:
redis-cli -c -h <cluster-host> -p <cluster-port> CLUSTER INFO
redis-cli -c -h <cluster-host> -p <cluster-port> CLUSTER NODES
redis-cli -c -h <cluster-host> -p <cluster-port> CLUSTER KEYSLOT '{user:1000}:profile'项目准备上 Cluster 前,至少先做四个检查:
是否依赖非 0 DB。是否有大量多 key 命令、Lua、事务或 pipeline 假设所有 key 在同一节点。客户端和连接池是否支持 Cluster 拓扑刷新。
key 设计是否能接受 hash tag 约束。
托管云和云原生 Redis
云 Redis、兼容 Redis 服务和 K8S Operator 的共同价值是降低自建运维成本。它们通常提供备份、监控、只读节点、自动切换、规格扩缩、审计和控制台。
架构师要看的不是“云厂商有 Redis”,而是这些边界:
| 问题 | 检查方式 |
|---|---|
| 是否兼容 Redis 8、Redis 7.2、Valkey 或自研协议 | 看官方兼容矩阵,不用社区经验替代 |
| 是否支持 ACL、TLS、Sentinel、Cluster、读写分离 | 用最小账号和客户端验证 |
| 备份 RPO/RTO 是多少 | 创建测试实例,做一次恢复演练 |
| 扩容是否阻塞、是否重启、是否有连接闪断 | 看变更说明,并在非生产实例验证 |
| 费用如何增长 | 按内存、连接、带宽、备份、跨区流量和日志审计拆开算 |
| 客户端连接地址是否会变 | 验证 DNS、代理 endpoint、故障切换后的连接刷新 |
云化不等于不用治理。真实团队最常见的问题是临时实例长期运行、测试数据进入云、只读账号变成写账号、跨环境连接串被复制、备份恢复从未演练。
架构对比与选型标准
Redis 选型不要从“想不想高可用”开始,而要从业务状态的价值和失败后果开始。
| 业务状态 | 推荐起点 | 取舍 |
|---|---|---|
| 可完全回源的页面缓存 | 单机或托管基础版 | 重点是 TTL、限流和回源保护 |
| 登录态、验证码、临时授权 | 主从 + Sentinel 或托管 HA | 重点是故障切换、RPO、会话降级 |
| 高 QPS 热点缓存 | 主从读扩展或应用侧本地缓存配合 | 重点是热 key、读写一致性和限流 |
| 大规模 keyspace | Redis Cluster 或云分片版 | 重点是 slot、hash tag、多 key 限制和迁移 |
| 强一致状态、金融记账、不可丢核心数据 | 先评估关系数据库、事务日志或专用存储 | Redis 可做旁路加速,不应承担唯一事实源 |
| 队列或流式事件 | Redis Stream 可验证,但要对比 MQ | 重点是 ack、积压、重放、持久化和监控 |
按规模选:
本机和联调:Compose 单实例,固定 ACL、prefix、TTL、清理脚本。小团队共享:单机或托管基础版,但必须有 owner、账号分层、备份和清理窗口。中小生产:主从 + Sentinel 或云托管 HA,验证客户端发现和切换。
单机容量到顶:先治理 TTL、大 key、热 key、序列化和过期策略,再评估 Cluster。跨区域和金融级要求:不要只靠 Redis;需要架构工程和部署运维共同设计数据源、降级、回滚和演练。
按一致性选:
普通缓存允许短时旧值:可以读副本。写后必须读到最新值:读主库或业务侧使用版本校验。故障切换不能丢确认写:Redis 默认异步复制不满足,需要重新评估事实源。
多 key 原子性强依赖:Cluster 会带来 slot 限制,先改 key 模型。
按运维成本选:
团队没有 Redis 运维经验:优先托管云或平台组统一服务。有合规或离线交付要求:自建主从/Sentinel/Cluster,但要写 runbook 和演练。只为本地开发:Compose 足够,别把生产复杂度塞进每个开发机。
核心底层架构
一次 SET / GET 怎么走
把 Redis 看成一个请求流水线更容易排障:
线上现象可以按这条链反推:
| 现象 | 优先排查 |
|---|---|
| 连接不上 | host、port、TLS、ACL、连接池、网络策略 |
| 单个命令慢 | SLOWLOG、big key、阻塞命令、Lua |
| 整体延迟抖动 | AOF rewrite、RDB fork、CPU、磁盘、网络 |
| 读到旧值 | 读副本、复制延迟、客户端路由 |
| key 丢失 | TTL、淘汰策略、误删、过期扫描、清理脚本 |
| 内存持续涨 | 无 TTL、big key、碎片、过期策略、泄漏写入 |
单线程事件循环与阻塞命令
Redis 命令执行主路径是单线程事件循环。优势是模型简单、无锁开销低;代价是一个慢命令会影响后面的请求。
高风险操作:
KEYS *、大范围 SMEMBERS、HGETALL、LRANGE 0 -1。大 key 删除用 DEL,同步释放内存导致卡顿。Lua 脚本执行时间过长。
AOF rewrite、RDB fork 叠加内存压力。客户端 pipeline 一次塞入过大批量。
排查入口:
redis-cli SLOWLOG GET 20
redis-cli INFO commandstats
redis-cli INFO clients
redis-cli LATENCY DOCTOR治理原则:日常账号禁危险命令;批量删除用 UNLINK;扫描用 SCAN;大集合按分页或分桶设计;慢命令进入评审清单。
内存模型、过期和淘汰
Redis 的主要成本是内存。架构师需要把 key 数量、value 大小、TTL 和淘汰策略一起看,而不是只看 used_memory。
常用检查:
redis-cli INFO memory
redis-cli INFO keyspace
redis-cli DBSIZE
redis-cli MEMORY USAGE dev:your-project:some-key
redis-cli OBJECT ENCODING dev:your-project:some-keymaxmemory-policy 是架构决策,不是随便配:
| 策略 | 适合 | 风险 |
|---|---|---|
noeviction | 不希望 Redis 自动丢 key | 写入会失败,应用必须处理 OOM |
allkeys-lru / allkeys-lfu | 纯缓存、任何 key 都可淘汰 | 业务如果混入状态 key,会被误淘汰 |
volatile-lru / volatile-ttl | 只淘汰带 TTL 的 key | 无 TTL key 会挤压内存 |
allkeys-random / volatile-random | 极少数简单场景 | 可预测性差,不推荐作为团队默认 |
开发模板默认 noeviction 是为了让错误尽早暴露。生产缓存可以选择 LRU/LFU,但必须确认没有把不可丢状态也放进同一个实例。
持久化、AOF rewrite 和恢复时间
Redis 持久化有四种常见选择:
| 方式 | 适合 | 代价 |
|---|---|---|
| 无持久化 | 纯可重建缓存 | 重启即丢,不能承载状态 |
| RDB | 备份、灾难恢复、快速重启 | 快照间隔内的数据可能丢 |
| AOF | 降低写入丢失窗口 | 文件增长、rewrite、磁盘写入和恢复时间 |
| RDB + AOF | 兼顾恢复和较小 RPO | 配置和演练成本更高 |
AOF rewrite 和 RDB fork 都会消耗额外内存和 I/O。机器内存只按 Redis 数据量配满,rewrite 时就容易出现抖动甚至 OOM。
排查入口:
redis-cli INFO persistence
redis-cli CONFIG GET appendonly
redis-cli CONFIG GET appendfsync
redis-cli CONFIG GET save备份不是“打开持久化”。备份必须能恢复到临时实例并完成应用侧校验,否则只是磁盘上多了一个文件。
复制链路和延迟
主从复制链路要看三类状态:
连接是否正常:master_link_status。offset 差距是否扩大:主从复制 offset。backlog 是否足够支撑短暂断线后的部分同步。
检查:
redis-cli INFO replication
redis-cli ROLE判断标准:
master_link_status:up 只是基础,不能说明无延迟。offset 差持续扩大,说明副本追不上。网络抖动、磁盘慢、从库 CPU 高、主库写入太快都会导致延迟。
读从库要有延迟兜底:核心读走主库、业务版本校验、读旧值容忍窗口。
Cluster slot、hash tag 和客户端拓扑
Redis Cluster 最大的应用侧改造点是 key 分布。单机时代可以随便 MGET a b c,Cluster 时代多个 key 不在同一 slot 就会失败。
示例:
redis-cli -c CLUSTER KEYSLOT '{user:1000}:profile'
redis-cli -c CLUSTER KEYSLOT '{user:1000}:cart'
redis-cli -c CLUSTER KEYSLOT 'user:1000:profile'
redis-cli -c CLUSTER KEYSLOT 'user:1000:cart'前两个使用 {user:1000} hash tag,会落到同一个 slot;后两个不保证同 slot。
客户端必须具备:
自动处理 MOVED 和 ASK。拓扑刷新。每个节点的连接池上限。
reshard 期间的重试策略。对 TRYAGAIN、READONLY、超时的分层处理。
key、TTL 与容量治理
Redis 容量治理不是等内存满了再扩容。项目接入时就要有 key 规范。
key 设计
推荐格式:
{env}:{project}:{module}:{object}:{id}Cluster 场景需要同 slot 的多 key 操作时:
{env}:{project}:{module}:{object-id}:profile
{env}:{project}:{module}:{object-id}:quota注意:hash tag 不是为了好看,是为了保证相关 key 落到同一个 slot。滥用 hash tag 会让大量 key 堆到同一 slot,反而形成热点。
TTL 设计
| key 类型 | TTL 建议 | 说明 |
|---|---|---|
| 页面 / 查询缓存 | 分钟到小时 | 配合回源限流和主动失效 |
| 会话 / token | 按安全策略 | TTL 是安全边界的一部分 |
| 验证码 / 短信状态 | 秒到分钟 | 必须短 TTL,避免泄漏和复用 |
| 分布式锁 | 秒级,且必须有 owner 和 token | 释放时必须校验 token,超时按业务最长执行时间与续租策略确定 |
| 永久状态 | 原则上不建议放 Redis | 必须登记 owner、备份和恢复策略 |
日常巡检:
redis-cli --scan --pattern 'dev:your-project:*' | head -50
redis-cli TTL dev:your-project:some-key
redis-cli MEMORY USAGE dev:your-project:some-key大 key 和热 key
大 key 判断不只看字节,还要看操作成本。一个 5MB 字符串、一个百万成员 set、一个超长 list 都会让命令执行、网络传输、复制、AOF 和 Cluster reshard 变慢。
排查入口:
redis-cli --bigkeys
redis-cli --hotkeys
redis-cli MEMORY USAGE <key>
redis-cli SLOWLOG GET 20治理取舍:
大 hash / set / zset 拆分为分桶 key。批量读取改分页。删除大 key 用 UNLINK。
热 key 通过本地缓存、分片 key、读写合并或业务降级处理。Cluster 中避免把过多热点 key 用同一个 hash tag 绑到同一 slot。
复制、高可用与扩容体系
主从延迟治理
主从延迟的常见原因:
主库写入过快。副本网络慢。副本 CPU 或磁盘慢。
AOF / RDB 持久化和复制同时争资源。大 key 导致同步和重放耗时。
工程判断:
redis-cli INFO replication
redis-cli INFO stats
redis-cli INFO persistence如果 offset 差持续扩大,先不要扩读副本。要先判断写入峰值、网络、磁盘、AOF rewrite 和 big key,再决定是否加副本或分片。
Sentinel 切换演练
Sentinel 的验收不是看进程在跑,而是看故障切换是否闭环。
演练步骤:
记录当前 master。停止 master。观察 Sentinel 选主。
用客户端重新发现 master。写入一个带 TTL 的 smoke key。恢复旧 master,确认它成为 replica。
验证命令:
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli INFO replication不合格现象:
客户端仍写旧主。旧主恢复后出现双主。Sentinel quorum 太低,网络抖动导致误切换。
应用连接池不刷新,直到重启才恢复。
Cluster 扩容和迁移
Cluster 扩容不是“加机器就完了”。扩容涉及 slot 迁移,slot 迁移涉及 key 移动,big key 会拖慢迁移。
上线前要确认:
客户端支持 Cluster。所有环境都用 DB 0。多 key 操作有 hash tag 或已改造。
迁移窗口有延迟预算。big key 巡检先完成。回滚方案明确:迁移失败后 slot、节点、客户端配置怎么恢复。
常用观察:
redis-cli -c CLUSTER INFO
redis-cli -c CLUSTER NODES
redis-cli -c CLUSTER SLOTS生产 reshard 必须进入正式变更流程:扩容前确认 big key、跨 slot 多 key 操作、客户端拓扑刷新和可回退节点,迁移中持续观察 slot 状态、延迟与错误率,失败时停止继续迁移并按已迁 slot 清单处置。
性能诊断体系
Redis 性能诊断不能只看平均耗时。要把客户端、网络、命令、内存、持久化和复制一起看。
第一层:客户端和连接
redis-cli INFO clients
redis-cli CLIENT LIST看:
连接数是否异常增长。是否有长时间 idle 的连接。是否有 blocked clients。
客户端名称是否能定位到服务。
项目模板里建议设置 client-name,否则排障时很难知道哪个服务制造了连接风暴。
第二层:慢命令和命令分布
redis-cli SLOWLOG GET 20
redis-cli INFO commandstats判断:
是否出现 KEYS、HGETALL、SMEMBERS、大范围 LRANGE。是否某类命令调用量异常。慢命令是否集中在某个模块 prefix。
修复不是简单加机器。先改命令、key 结构、分页、TTL 和 ACL,再评估扩容。
第三层:内存、持久化和延迟
redis-cli INFO memory
redis-cli INFO persistence
redis-cli LATENCY DOCTOR看:
used_memory、maxmemory、碎片率。AOF rewrite 是否正在进行。RDB fork 是否频繁。
latency doctor 是否指出 fork、command、expire、eviction 相关事件。
第四层:复制和 Cluster
redis-cli INFO replication
redis-cli -c CLUSTER INFO
redis-cli -c CLUSTER NODES看:
副本是否在线。offset 差是否持续扩大。Cluster slot 是否稳定。
是否有 fail、pfail、migrating、importing 状态。
容灾、备份、恢复与运维工具
Redis 容灾要先回答两个问题:这个数据能不能丢,丢多少能接受。
| 目标 | Redis 侧手段 | 不足 |
|---|---|---|
| 重启后恢复 | AOF / RDB | 不能防误删和错误写入 |
| 灾难恢复 | RDB 归档、云快照、异地备份 | 有 RPO,恢复要演练 |
| 降低主库故障影响 | 主从 + Sentinel / 托管 HA | 异步复制仍可能丢最近写 |
| 容量扩展 | Cluster / 云分片 | 应用要适配 slot 和多 key 限制 |
备份验证
备份必须能恢复到临时实例:
docker run --rm --name redis-restore-test \
-p 127.0.0.1:6380:6379 \
-v redis-restore-data:/data \
redis:8.8.0恢复后至少验证:
redis-cli -h 127.0.0.1 -p 6380 PING
redis-cli -h 127.0.0.1 -p 6380 DBSIZE
redis-cli -h 127.0.0.1 -p 6380 --scan --pattern 'dev:your-project:*' | head -20恢复步骤必须写进受控 runbook 并定期演练。只有备份能恢复到隔离实例、业务校验通过且实际耗时满足 RTO,它才是可用备份。
RPO / RTO 判断
| 场景 | RPO | RTO | 结论 |
|---|---|---|---|
| 纯缓存 | 可丢全部 | 分钟级 | 重点是回源保护和限流 |
| 会话状态 | 秒到分钟 | 分钟级 | 需要 HA、降级和用户重登策略 |
| 限流计数 | 秒级 | 秒级 | 需要业务兜底,不能只靠恢复 |
| 事实源数据 | 接近 0 | 严格 | Redis 不应是唯一事实源 |
运维工具入口
常用工具:
redis-cli:最基础、最可审查。RedisInsight:GUI 排障和可视化,但生产连接要只读。云控制台:备份、监控、审计、规格和连接信息。
Prometheus exporter / 云监控:指标和告警入口。日志和审计:ACL、连接、慢命令和变更记录。
工具选型原则:能脚本化的验收用 CLI;需要观察结构和趋势用 GUI / Dashboard;生产变更用平台 runbook。
架构演进趋势
Redis 在团队里的演进通常不是一步上 Cluster,而是这样走:
本地 Compose -> 共享开发实例 -> 托管单实例 / 主从 -> Sentinel 或云 HA -> Cluster / 云分片 -> 按业务拆缓存域每一步都要问:
当前瓶颈是内存、CPU、网络、连接、持久化、复制,还是 key 模型本身。是否能通过 TTL、big key、hot key、序列化和命令治理解决。扩容会不会让客户端、事务、多 key、Lua 和清理脚本失效。
团队是否有 owner、演练和恢复能力。成本是否来自真实业务增长,还是测试数据、无 TTL key 和过宽日志造成的浪费。
架构师的取舍结论:Redis 很适合做低延迟状态和缓存,但不适合把所有“需要快”的问题都塞进去。真正高质量的 Redis 落地,是让开发者能安全跑通,让项目能清晰接入,让团队能知道什么时候该用、什么时候该拆、什么时候该换。
查看容器状态
docker compose ps redis
docker compose logs redis --tail 120
docker volume inspect your-project-redis-data查看 Redis 状态
状态类命令使用 ops 账号:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_OPS_PASSWORD"
redis-cli --user "$REDIS_OPS_USER" INFO server
redis-cli --user "$REDIS_OPS_USER" INFO clients
redis-cli --user "$REDIS_OPS_USER" INFO memory
redis-cli --user "$REDIS_OPS_USER" INFO keyspace
'扫描本项目 key
不要用 KEYS *。用 SCAN 或 redis-cli --scan:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" --raw --scan --pattern "${REDIS_KEY_PREFIX}*" | head -50
'如果镜像里没有 head,直接去掉管道,或把输出重定向到文件后人工查看前几行。
查看 key 类型和 TTL
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
key="${REDIS_KEY_PREFIX}smoke"
redis-cli --user "$REDIS_APP_USER" TYPE "$key"
redis-cli --user "$REDIS_APP_USER" TTL "$key"
'TTL 结果要这样判断:
| 结果 | 含义 | 处理 |
|---|---|---|
| 正整数 | key 存在且会过期 | 正常 |
-1 | key 存在但没有 TTL | 缓存 key 要补过期时间,永久 key 登记 owner |
-2 | key 不存在 | 确认是否被清理或从未写入 |
清理本项目测试 key
安全清理脚本只按 prefix 清理,并先 dry run:
docker compose exec redis sh -lc '
set -eu
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
echo "dry run: keys under $REDIS_KEY_PREFIX"
redis-cli --user "$REDIS_APP_USER" --raw --scan --pattern "${REDIS_KEY_PREFIX}*" > /tmp/redis-keys.txt
wc -l /tmp/redis-keys.txt
sed -n "1,20p" /tmp/redis-keys.txt
'确认后再删除:
docker compose exec redis sh -lc '
set -eu
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" --raw --scan --pattern "${REDIS_KEY_PREFIX}*" > /tmp/redis-keys.txt
while IFS= read -r key; do
[ -n "$key" ] && redis-cli --user "$REDIS_APP_USER" UNLINK "$key"
done < /tmp/redis-keys.txt
rm -f /tmp/redis-keys.txt
'这里故意不用 xargs -r,因为不同系统和工具链行为不一致。脚本在容器内执行,PowerShell、Bash、Zsh 都只是把命令交给容器。
停止和重置
停止但保留数据:
docker compose stop redis删除容器但保留 volume:
docker compose rm -sf redis个人本机重置 Redis 数据:
docker compose down
docker volume rm your-project-redis-data
docker compose up -d redis共享开发实例不能这么重置。共享环境清理必须按 prefix、owner、清理窗口和变更记录执行。
端口已经被占用
现象:
Bind for 127.0.0.1:6379 failed: port is already allocated判断:
docker ps --format "table {{.Names}}\t{{.Ports}}"Windows:
netstat -ano | findstr 6379原因:
本机已有 Redis 服务。旧容器还在占用端口。另一个项目也映射了 6379。
修复:
修改 .env 里的 REDIS_HOST_PORT,例如改成 6380。重新启动 Redis。宿主机应用连接端口同步改成新端口。
Compose 网络内应用仍然使用 redis:6379,不要把内部端口也改乱。
再验证:
docker compose up -d redis
docker compose ps redisNOAUTH 或 WRONGPASS
现象:
NOAUTH Authentication required.
WRONGPASS invalid username-password pair or user is disabled.判断:
docker compose exec redis sh -lc '
echo "$REDIS_APP_USER"
test -n "$REDIS_APP_PASSWORD"
REDISCLI_AUTH="$REDIS_APP_PASSWORD" redis-cli --user "$REDIS_APP_USER" ACL WHOAMI
'原因:
应用没有带 username / password。密码换了,但旧容器还没重启。密码包含 URI 特殊字符,连接串没有 URL encode。
你以为 REDIS_PASSWORD 会自动生效,但官方镜像没有这样做。
修复:
统一使用 REDIS_APP_USER 和 REDIS_APP_PASSWORD 注入。用 REDISCLI_AUTH 做 CLI 验证。URI 中的密码做 URL encode,或改成分散字段配置。
重启容器,确认 ACL 文件重新生成。
再验证:
docker compose exec redis sh -lc '
REDISCLI_AUTH="$REDIS_APP_PASSWORD" redis-cli --user "$REDIS_APP_USER" PING
'NOPERM 权限不足
现象:
NOPERM this user has no permissions to access one of the keys used as arguments判断:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" ACL WHOAMI
echo "expected prefix=$REDIS_KEY_PREFIX"
'原因:
key 没有带 REDIS_KEY_PREFIX。应用用错账号,比如只读账号执行写入。ACL 里 ~prefix* 写错。
命令被 -@dangerous 或最小权限规则排除了。
修复:
统一项目 key builder,不允许业务代码手写散乱 prefix。分清 app、readonly、ops 三类账号。修改 ACL 后重启 Redis,再跑正向和反向验证。
再验证:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" SET "${REDIS_KEY_PREFIX}acl-check" ok EX 60
redis-cli --user "$REDIS_APP_USER" SET "other-project:acl-check" bad EX 60
'第一条应返回 OK,第二条应返回 NOPERM。
protected mode 或网络暴露问题
现象:
容器内能连,宿主机连不上。宿主机能连,局域网其他机器也能连,且没有认证。连接返回 protected mode 相关错误。
判断:
docker port your-project-redis
docker compose exec redis sh -lc '
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" CONFIG GET protected-mode
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" CONFIG GET bind
'原因:
端口绑定到了 0.0.0.0。自定义配置改了 bind 或 protected-mode,但没有相应的网络和 ACL 防护。Docker Official Image 默认关闭 protected mode,你以为 Redis 会自动保护所有暴露端口。
修复:
个人本机端口绑定 127.0.0.1:${REDIS_HOST_PORT}:6379。共享环境通过内网、安全组、防火墙、VPN、ACL 和 TLS 控制访问。禁止无密码、无 ACL 的 Redis 对外暴露。
再验证:
docker compose ps redis
redis-cli -h 127.0.0.1 -p 6379 PING未认证的 PING 应该失败;带 app 用户认证的 PING 应该成功。
旧 volume、AOF 或 RDB 让配置看起来不生效
现象:
改了 maxmemory、AOF、ACL 或 key prefix 后,旧 key 还在。重启容器后,之前的测试 key 又回来了。你以为缓存是临时的,但验证结果一直被旧数据污染。
判断:
docker volume inspect your-project-redis-data
docker compose exec redis sh -lc '
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" INFO persistence
'原因:
named volume 保留了 /data。AOF / RDB 持久化把旧 key 带回来了。清理脚本只删了一部分 prefix。
个人本机修复:
docker compose down
docker volume rm your-project-redis-data
docker compose up -d redis共享环境修复:
不删 volume。先由 owner dry run 扫描 prefix。只清理确认属于本项目和本环境的 key。
留下清理记录和再验证结果。
容器内应用连 127.0.0.1 失败
现象:
Connection refused: /127.0.0.1:6379判断:
docker compose exec app sh -lc 'getent hosts redis || nslookup redis'
docker compose exec app sh -lc 'nc -vz redis 6379'原因:应用容器里的 127.0.0.1 是应用容器自己,不是 Redis 容器,也不是宿主机。
修复:
同一个 Compose 网络里使用 redis:6379。宿主机运行应用才使用 127.0.0.1:${REDIS_HOST_PORT}。访问宿主机服务时使用受控 host 入口,不要随便写平台相关魔法地址进团队模板。
KEYS * 或大扫描拖慢 Redis
现象:
CLI 卡住。应用响应突然变慢。共享 Redis 在某个同事排查后出现短暂阻塞。
判断:
docker compose exec redis sh -lc '
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" SLOWLOG GET 10
'原因:KEYS 是 O(N) 且属于 @dangerous,大 keyspace 下会阻塞 Redis。
修复:
ACL 禁掉 KEYS。日常使用 SCAN、--scan、MATCH 和小 COUNT 分批迭代。清理脚本先 dry run,再按 prefix 执行 UNLINK。
再验证:应用账号执行 KEYS "*" 应返回 NOPERM。
TTL 缺失导致测试数据污染
现象:
DBSIZE 长期增长。本地测试偶尔读到旧值。TTL key 返回 -1。
判断:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" TTL "${REDIS_KEY_PREFIX}some-key"
'原因:
业务写入没有设置过期时间。key builder 没有统一默认 TTL。测试数据清理不完整。
修复:
缓存 key 默认设置 TTL。永久 key 必须登记 owner、用途和清理条件。CI 或本地测试结束后按 prefix 清理。
OOM command not allowed 或 key 被异常淘汰
现象:
OOM command not allowed when used memory > 'maxmemory'或者应用没有报 OOM,但某些 key 莫名消失。
判断:
docker compose exec redis sh -lc '
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" INFO memory
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" CONFIG GET maxmemory
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" CONFIG GET maxmemory-policy
'原因:
maxmemory 太小,写入超过限制。maxmemory-policy 是 noeviction,Redis 拒绝新写入。选择了 LRU / LFU 淘汰,但业务把不可丢状态也放在同一实例。
无 TTL key 或大 key 持续累积。
修复:
先用 INFO memory、DBSIZE、MEMORY USAGE 找增长来源。清理无 owner、无 TTL、过期测试 key。纯缓存实例可以评估 allkeys-lru 或 allkeys-lfu,但状态型 key 必须拆出去。
调整 maxmemory 前确认宿主机或容器资源上限,不能只改 Redis 配置。
再验证:
docker compose exec redis sh -lc '
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" INFO memory | sed -n "1,40p"
'主从延迟导致读到旧值
现象:
写入后立刻读取,偶尔读不到新值。故障切换后少量最新写入丢失。副本读性能下降,master_link_status 间歇异常。
判断:
redis-cli INFO replication
redis-cli ROLE原因:
Redis 默认异步复制。主库写入过快,副本追不上。网络、磁盘、AOF rewrite 或 big key 影响复制。
业务把强一致读放到了副本。
修复:
写后读、权限校验、支付状态、库存状态走主库或做业务版本校验。对副本延迟做监控,不把副本只当“免费读扩展”。排查 big key、慢命令和 AOF rewrite。
需要更强确认时可以评估 WAIT,但不能把它当成强一致保证。
再验证:
redis-cli INFO replication
redis-cli SET dev:your-project:replication-check ok EX 60
redis-cli GET dev:your-project:replication-checkSentinel 切换后客户端还在写旧主
现象:
Sentinel 已经选出新主,但应用仍连接旧地址。写入返回 READONLY 或连接超时。重启应用后才恢复。
判断:
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli INFO replication原因:
客户端没有使用 Sentinel 模式,仍写死主库地址。连接池没有刷新 master。旧主恢复后没有被隔离或降级为副本。
Sentinel quorum 和网络分区策略没有演练。
修复:
应用配置使用 Sentinel master name 和 Sentinel 节点列表。验证客户端库支持自动发现新主。故障演练必须包含旧主恢复后的角色确认。
生产切换细节进入部署运维 runbook,工具文档保留验证入口和失败现象。
再验证:
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL replicas mymasterCluster 返回 MOVED、ASK 或 TRYAGAIN
现象:
MOVED 12182 <cluster-node-a>:6379
ASK 12182 <cluster-node-b>:6379
TRYAGAIN Multiple keys request during rehashing of slot判断:
redis-cli -c CLUSTER INFO
redis-cli -c CLUSTER NODES
redis-cli -c CLUSTER KEYSLOT '{user:1000}:profile'原因:
客户端不是 Cluster 模式,无法处理重定向。Cluster 正在 reshard 或故障切换。多 key 操作跨 slot。
key 没有按 hash tag 设计。
修复:
使用支持 Cluster 的客户端和连接池。多 key 操作用 hash tag 保证同 slot,或改成应用侧拆分。reshard 期间降低批量操作和大 key 操作。
统一禁止在准备上 Cluster 的项目中依赖非 0 DB。
再验证:
redis-cli -c CLUSTER KEYSLOT '{user:1000}:profile'
redis-cli -c CLUSTER KEYSLOT '{user:1000}:cart'两个 key 应落在同一个 slot。
AOF rewrite 或 RDB fork 期间延迟抖动
现象:
Redis 周期性延迟升高。INFO persistence 显示 rewrite 或 bgsave 正在进行。容器或主机内存突然升高。
判断:
redis-cli INFO persistence
redis-cli INFO memory
redis-cli LATENCY DOCTOR原因:
RDB 和 AOF rewrite 都需要 fork 子进程。数据集大、写入多、内存余量不足时,copy-on-write 成本明显。磁盘慢或空间不足导致 AOF 写入和 rewrite 卡顿。
修复:
给内存留 rewrite 余量,不按 used_memory 配满机器。避免备份、rewrite、压测和大批量写入同时发生。监控磁盘空间、AOF 大小、rewrite 状态和 fork 耗时。
备份恢复策略按 RPO/RTO 重新评估,不盲目打开所有持久化。
再验证:
redis-cli INFO persistence
redis-cli SLOWLOG GET 10Redis 本身不是 HTTP 工具,不会因为你设置了系统代理就自动“能连”。真正受代理影响的是镜像拉取、包下载、客户端依赖下载、云控制台和内网访问。
代理和网络
常见检查:
docker pull redis:8.8.0
redis-cli -h 127.0.0.1 -p 6379 PINGJava 依赖下载:
mvn -q dependency:get -Dartifact=org.springframework.boot:spring-boot-starter-data-redis如果失败,按顺序查:
Docker 代理和镜像源。Maven / Gradle 私服和企业根证书。公司 VPN、DNS、安全软件和端口策略。
Redis host 是否应该是 127.0.0.1、redis、内网域名还是云厂商 endpoint。
账号分层
| 账号 | 用途 | 权限边界 |
|---|---|---|
default | 兼容旧客户端的默认用户 | 开发模板里关闭,不给团队长期使用 |
app_dev | 应用本地运行 | 只访问本项目 prefix,可读写,不允许危险命令 |
cache_readonly | 查询和排障 | 只读本项目 prefix,不写入,不执行危险命令 |
cache_ops | 状态查看和排障 | 查看 INFO、SLOWLOG GET、CLIENT LIST,不执行 FLUSH / KEYS / DEL / EXPIRE / UNLINK |
共享环境不要发“万能密码”。每个项目至少有独立 app 用户和 key pattern,排障账号要有 owner 和使用记录。
凭证落地规则
.env 不提交。.env.example 只写变量名和占位值。CLI 优先用 REDISCLI_AUTH,不用 -a <password>。
连接 URI 中的密码要 URL encode;截图和日志里不能出现完整 URI。RedisInsight、DataGrip、DBeaver 等 GUI 客户端不得保存生产写权限账号。CI Secret、共享开发实例密码和个人本机密码分开。
离职、项目交接、owner 变更、泄漏疑似发生时,轮换共享密码并清理旧连接模板。
GUI 客户端边界
RedisInsight 或通用数据库客户端很适合观察 key、TTL、类型和内存,但 GUI 也是误连生产的高风险入口。
团队要求:
生产连接默认只读。连接名称必须带环境,例如 PROD-readonly-your-project、DEV-your-project。截图前隐藏 host、账号、真实 key、value 和连接名里的组织信息。
GUI 不执行批量删除。批量清理走受控脚本和 dry run。
团队能否稳定使用 Redis,取决于模板、责任、权限和清理是否固定下来。
项目模板必须保留
compose.yaml
.env.example
cache/redis/redis.conf
cache/redis/verify/verify.redis
docs/dependency-setup.md
scripts/cache-scan.sh
scripts/cache-reset.sh模板里要写清:
镜像 tag、digest 和升级复核人。宿主机端口和容器端口。volume 名称和重置命令。
ACL 用户、key pattern 和危险命令限制。REDIS_KEY_PREFIX 命名规则。最小验证脚本和预期结果。
共享环境禁止事项。
命名规则
| 对象 | 建议命名 |
|---|---|
| Compose service | redis |
| container | your-project-redis |
| volume | your-project-redis-data |
| app user | app_dev |
| readonly user | cache_readonly |
| ops user | cache_ops |
| key prefix | dev:your-project: |
共享实例规则
必须有 owner。必须有项目级 key prefix。必须关闭 default 用户或至少禁用无密码 default 用户。
应用账号、只读账号、排障账号分开。FLUSHALL、FLUSHDB、KEYS 默认禁用。清理脚本必须先 dry run,输出目标 host、端口、user、prefix 和 key 数量。
默认 TTL 由项目模板提供;永久 key 登记 owner。生产连接不得进入本地 .env、截图、示例代码和 GUI 默认连接。
key 冲突会让缓存问题像业务问题
现象:接口偶发读到别人写的值,或者值结构和当前代码不匹配。
判断:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" --raw --scan --pattern "${REDIS_KEY_PREFIX}*" | head -50
'结论:Redis 没有 schema,key 就是命名空间。prefix 太短、环境不清、模块不清时,缓存污染会伪装成业务随机失败。
治理:
key 至少包含环境、项目和模块。value 结构升级时加版本,例如 v2。共享实例里个人实验 key 带人名或工号缩写,但不要带真实邮箱。
key builder 进入公共库,不让业务代码手写散乱前缀。
FLUSH 误伤是共享 Redis 的一票否决风险
现象:共享环境所有服务缓存突然清空,或者测试数据全部消失。
判断:
docker compose exec redis sh -lc '
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" ACL LIST
'结论:只靠“大家小心”挡不住误操作。FLUSHALL 和 FLUSHDB 必须从权限层禁掉。
治理:
日常账号使用 -@dangerous。清理脚本只按 prefix,禁止无条件清空 DB。共享环境破坏性操作必须由 owner 执行并记录。
生产环境清理走正式变更,不能复用开发脚本。
旧 volume 会让“缓存”变成历史数据仓库
现象:重启容器后旧 key 回来了;改了配置后验证仍然读到旧状态。
判断:
docker volume inspect your-project-redis-data
docker compose exec redis sh -lc '
REDISCLI_AUTH="$REDIS_OPS_PASSWORD" redis-cli --user "$REDIS_OPS_USER" INFO persistence
'取舍:个人本机可以 docker volume rm 重建;共享环境只能按 prefix 和 owner 清理。不要因为“Redis 是缓存”就把共享实例当成随便删的临时目录。
DB index 不是隔离方案
现象:团队约定 A 项目用 DB 1、B 项目用 DB 2,但还是有人误选 DB、误扫 key、误清理。
判断:
redis-cli -n 1 DBSIZE
redis-cli -n 2 DBSIZE结论:DB index 只是同一个实例内的逻辑编号,不提供账号、网络、审计、清理和成本边界。项目级 ACL key pattern 和 prefix 能约束数据命令,却不能把共享实例变成强租户边界;只要账号拥有 SCAN,key 名仍可能跨前缀可见。共享环境只能承载可信项目,存在客户隔离、敏感 key 名、独立审计或独立成本要求时必须拆实例。
可以用两个账号做一次反向实验。先由实例 owner 写入 project-b:order:1001,再让只允许 ~project-a:*、但拥有 +scan 的账号执行:
redis-cli --user project_a SCAN 0 MATCH '*' COUNT 100
redis-cli --user project_a GET project-b:order:1001前一条可能返回 project-b:order:1001,后一条应返回 NOPERM。这组结果说明 value 访问被拦住了,但 key 名没有被隐藏。治理动作不是把 key 名改得更隐晦,而是减少普通账号的 SCAN 权限、通过受控排障入口执行扫描,并在元数据也敏感时拆分实例。
Docker 网络误判会导致“本机能连、容器不能连”
现象:宿主机应用连得上,应用容器启动后连不上。
判断:
docker compose exec app sh -lc 'getent hosts redis && nc -vz redis 6379'结论:容器里的 localhost 不是宿主机,也不是 Redis 容器。团队模板必须分别写清宿主机连接和 Compose 网络连接。
TTL 缺失会把测试污染留到下一轮迭代
现象:测试偶尔失败,清理后又恢复;TTL 返回 -1。
判断:
docker compose exec redis sh -lc '
export REDISCLI_AUTH="$REDIS_APP_PASSWORD"
redis-cli --user "$REDIS_APP_USER" TTL "${REDIS_KEY_PREFIX}some-key"
'治理:
缓存写入必须有默认 TTL。永久 key 需要登记 owner。测试框架结束后按 prefix 清理。
共享环境每周或每迭代输出一次 key 数量和无 TTL 样本。
大 key 和热 key 会把扩容计划拖垮
现象:Redis CPU 不一定高,但接口延迟突然变长;Cluster reshard 迁移很慢;某个副本同步时间异常;删除一个 key 后服务抖动。
判断:
redis-cli --bigkeys
redis-cli --hotkeys
redis-cli MEMORY USAGE <key>
redis-cli SLOWLOG GET 20redis-cli --hotkeys 依赖 LFU 相关统计,只有实例使用 LFU 淘汰策略时才有诊断价值。非 LFU 场景先从 SLOWLOG、INFO commandstats、应用访问日志、网关指标和业务埋点反推热点 key。
取舍:
大 key 不是只占内存,还会放大网络传输、复制、AOF、RDB、删除和 slot 迁移成本。热 key 不一定靠 Cluster 解决。Cluster 只能把不同 key 分到不同 slot,单个热点 key 仍然打到同一个 master。大集合要拆桶、分页和异步删除;热点读要配合本地缓存、请求合并、限流或业务降级。
Sentinel 不是数据安全方案
现象:团队上了 Sentinel,就默认 Redis “高可用且不丢数据”;故障切换后发现最新写入不见了,或者客户端还在写旧主。
判断:
redis-cli -p 26379 SENTINEL masters
redis-cli INFO replication结论:Sentinel 解决的是非 Cluster Redis 的主库发现和自动故障转移,不解决异步复制丢写、误删复制、备份恢复、容量上限和业务降级。
治理:
关键状态不要把 Redis 当唯一事实源。故障演练必须验证客户端发现新主。旧主恢复后的角色必须确认。
Sentinel 切换记录、客户端版本、连接池行为和配置模板要统一。
Cluster 会把 key 设计问题放大
现象:单机 Redis 正常,上 Cluster 后多 key 命令失败、事务失败、Lua 脚本失败,或者 SELECT 1 直接不可用。
判断:
redis-cli -c CLUSTER KEYSLOT '{order:1001}:base'
redis-cli -c CLUSTER KEYSLOT '{order:1001}:items'
redis-cli -c SELECT 1结论:Cluster 是扩容方案,不是无痛兼容层。准备上 Cluster 的项目必须先清理 DB index 依赖、多 key 跨 slot、超大 key 和客户端不支持 Cluster 的问题。
治理:
新项目 key 设计默认考虑 hash tag。项目模板不要依赖 database: 1 这类隔离方式。CI 可以增加一组 Cluster 兼容性用例,至少覆盖多 key、Lua、pipeline 和连接池。
扩容前做 big key 巡检和 reshard 演练。
备份没有恢复演练就是心理安慰
现象:控制台显示有快照,或磁盘上有 RDB / AOF 文件,但真正故障时不知道恢复到哪里、恢复多久、恢复后业务怎么校验。
判断:
redis-cli INFO persistence
redis-cli DBSIZE
redis-cli --scan --pattern 'dev:your-project:*' | head -20结论:Redis 备份要以恢复验证为准。RDB、AOF、云快照、对象存储归档都只是备份介质;只有恢复到临时实例并跑过业务校验,才算具备恢复能力。
治理:
每个共享或生产 Redis 明确 RPO/RTO。备份恢复演练固定到季度或重要版本前。恢复脚本不能默认连生产 endpoint。
恢复后用 prefix、样本 key、业务自检和只读查询确认数据质量。
内存策略混用会导致状态被误淘汰
现象:缓存 key 可以丢,但同实例里的会话、锁、限流状态也被淘汰;业务以为 Redis 丢数据。
判断:
redis-cli CONFIG GET maxmemory-policy
redis-cli INFO stats
redis-cli INFO keyspace结论:allkeys-lru、allkeys-lfu 适合纯缓存实例;如果同一个实例混入不可丢状态,就会把架构边界变成概率事件。
治理:
按数据价值拆实例或拆 DB / prefix,生产优先拆实例。可淘汰缓存和不可淘汰状态不要混用同一 maxmemory 策略。限流、锁、会话和业务状态要有独立 owner、TTL 和降级策略。
淘汰次数、OOM、无 TTL key 数量进入巡检。
凭证泄漏往往来自“临时方便”
现象:命令历史、截图、.env、GUI 配置或日志里出现 Redis URI。
判断:
rg -n "redis://|REDISCLI_AUTH|REDIS_APP_PASSWORD|PRIVATE KEY|AWS_ACCESS_KEY_ID|GITHUB_TOKEN|OPENAI_API_KEY" .治理:
CLI 用 REDISCLI_AUTH,不要用 -a。.env 不提交,.env.example 只保留占位符。GUI 截图先脱敏 host、账号、key 和 value。
发现泄漏后轮换密码,不只是在 Git 里删一行。
Redis 8 许可和 Valkey 边界不能口头带过
现象:团队模板升级到 Redis 8,但内部工具、客户现场包或托管服务没有做许可复核。
判断:
交付清单里是否写明 Redis 版本、镜像 digest 和许可选择。是否涉及再分发、商业托管、客户现场交付或竞争性服务。是否有人把 Valkey 当成“完全等同 Redis 8”的替换品。
取舍:普通开发自用通常不会卡在这里,但再分发、商业托管和客户现场交付必须留痕。Redis 8、Redis 7.4-7.8、Redis 7.2 及更早版本的许可口径不同;迁移到 Valkey 前要建立命令、持久化文件、客户端、故障切换与性能基线的兼容测试。
GUI 保存生产连接会绕过代码评审
现象:代码里没有生产密码,但某个 GUI 客户端保存了生产写账号;一次手工清理影响了真实数据。
判断:
查看团队连接模板是否分环境、分权限。生产连接是否默认只读。截图和演示是否泄漏 key、value、host 或账号。
治理:
生产 Redis 只发只读账号给普通排障。GUI 连接名强制带环境和权限。批量删除不走 GUI。
关键操作要有审计或至少有 owner 记录。
安装后:
镜像 tag 已固定,不使用 latest。镜像 digest、升级复核人和回退版本已记录。Redis 8 / 7.4-7.8 / 7.2 及更早版本的许可口径已按团队需要确认。
docker compose ps redis 显示健康。宿主机端口绑定到 127.0.0.1,没有无意暴露到局域网。volume 名称明确,知道个人本机如何重置。
接入前:
宿主机连接和 Compose 网络连接的 host 已区分。REDIS_KEY_PREFIX 包含环境、项目和模块语义。准备上 Cluster 的项目没有依赖非 0 DB。
多 key 操作已确认同 slot 或已改造成应用侧拆分。应用账号不是 default 用户。ACL 已完成正向写入和反向拒绝验证。
KEYS、FLUSHDB、FLUSHALL 对日常账号返回 NOPERM。缓存写入有默认 TTL。.env 未提交,.env.example 完整。
共享实例前:
owner 已明确。app、readonly、ops 账号已分开。共享实例访问边界、VPN、防火墙或安全组已确认。
单机、主从、Sentinel、Cluster 或托管云形态已做选型说明。RDB / AOF / 云快照的 RPO、RTO 和恢复演练路径已记录。主从复制延迟、AOF rewrite、big key、hot key 有巡检入口。
GUI 客户端生产连接默认只读。清理脚本先 dry run,且只按 prefix 清理。永久 key 有 owner 和清理策略。
凭证轮换和离职回收路径已记录。
排障时:
先确认目标 host、port、database、user 和 prefix。先用 PING、ACL WHOAMI、SET EX、GET、TTL、DEL 验证闭环。扫描 key 使用 SCAN,不用 KEYS *。
旧 volume / AOF / RDB 污染已排查。INFO memory、INFO persistence、INFO replication、SLOWLOG GET 已按现象分层检查。Sentinel 切换或 Cluster 重定向问题已确认客户端模式、拓扑刷新和旧主隔离。
OOM、淘汰、无 TTL、大 key 和热 key 已区分,不把所有问题都归因于“Redis 慢”。错误按 NOAUTH、WRONGPASS、NOPERM、端口、网络、TTL、序列化分层判断。
