数据库 ·

Redis 入门:安装、数据结构、持久化、主从哨兵集群与日常排障

Redis 是世界上最流行的内存 KV 与缓存数据库。本文从安装、五大数据结构命令、RDB/AOF、主从复制、哨兵、Cluster 分片,到缓存穿透/击穿/雪崩三大经典问题以及慢查询、OOM、RDB fork 等排障全解。

Redis 入门:安装、数据结构、持久化、主从哨兵集群与日常排障

Redis(Remote Dictionary Server) 是 Salvatore Sanfilippo(@antirez)写的基于内存、可选持久化、支持多种数据结构的 KV 数据库。它被普遍用作:分布式缓存、分布式锁、会话存储、排行榜、限流计数器、消息队列(Stream/PubSub)、社交关系(Set/ZSet)、地理索引(Geo)…… 常被称为”瑞士军刀”。

一、安装 & 第一个 key

1.1 macOS

brew install redis
brew services start redis
redis-cli ping   # 返回 PONG 就是 OK

1.2 Ubuntu / Debian

sudo apt update
sudo apt install -y lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt update
sudo apt install -y redis-server redis-tools
sudo systemctl enable --now redis-server

1.3 Docker(开发最快)

docker run -d --name redis7 \
  -p 6379:6379 \
  -v $PWD/redis-data:/data \
  --restart=unless-stopped \
  redis:7.2-alpine \
  redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru

redis-cli -h 127.0.0.1 -p 6379 ping

1.4 安全加固(生产必做)

生产配置文件 /etc/redis/redis.conf 里至少:

# 1) 不要绑 0.0.0.0!限本机 / 内网
bind 127.0.0.1 10.0.0.10

# 2) 设密码(ACL 推荐,旧版 requirepass)
requirepass  "YourStr0ngP@ssword!"

# 3) 禁用/重命名危险命令(线上被 FLUSHALL 过一次就懂)
rename-command FLUSHDB  ""
rename-command FLUSHALL ""
rename-command CONFIG   ""
rename-command KEYS     "MYKEYS"      # KEYS * 生产会阻塞主线程

# 4) 持久化
appendonly yes
appendfsync everysec

# 5) 内存上限 + 淘汰策略
maxmemory 4gb
maxmemory-policy allkeys-lru

改完:

sudo systemctl restart redis-server
redis-cli -a 'YourStr0ngP@ssword!' ping
# 避免每次敲密码:export REDISCLI_AUTH='YourStr0ngP@ssword!'

二、五大数据结构速用

2.1 String(字符串,最基础)

SET name "Alice" EX 3600           # 存,1 小时过期;PX 是毫秒
GET name                           # 取
DEL name                           # 删
MSET user:1:name Alice user:1:age 28   # 批量设
MGET user:1:name user:1:age            # 批量取
INCR user:1:age                     # +1(原子计数器,常用于点击/限流)
DECRBY user:1:age 2                 # -2
SETNX lock:order:123 1              # 不存在才设 = 分布式锁基础,1=拿到锁
GETSET counter 0                    # 取旧值并设新值,常做滚动计数器

2.2 Hash(哈希,适合存对象字段)

HSET user:100 name Bob age 30 email bob@example.com
HGET user:100 email
HGETALL user:100                    # 全部字段(字段多了别乱用,会 O(N))
HMGET user:100 name age
HINCRBY user:100 age 1
HDEL user:100 email
HEXISTS user:100 phone
HLEN user:100
HSCAN user:100 0                    # 大 hash 一定要用 SCAN 系列,别 HGETALL

2.3 List(双端链表,队列 / 栈 / 时间线)

LPUSH timeline:uid:1 "post-3" "post-2" "post-1"   # 左压入 = 最新在最前
LRANGE timeline:uid:1 0 9        # 取前 10 条(分页)
RPUSH queue:jobs "job-a" "job-b"
LPOP queue:jobs                  # 出队左;RPOP 出队右 → FIFO 队列
BLPOP queue:jobs 30              # 阻塞 30s 等消息(简单 MQ)
LTRIM timeline:uid:1 0 999       # 只保留最近 1000 条,防无限增长
LINDEX timeline:uid:1 0          # 按下标取

2.4 Set(无序不重复集合,交并差、共同关注、抽奖)

SADD user:1:follow 101 102 103 104
SADD user:2:follow 103 104 105 106
SISMEMBER user:1:follow 103          # 1 = 关注了
SINTER user:1:follow user:2:follow   # 交集 = 共同关注
SUNION user:1:follow user:2:follow   # 并集
SDIFF  user:1:follow user:2:follow   # 差集:1 关注但 2 没关注
SCARD user:1:follow                  # 关注数
SRANDMEMBER lottery:pool 3           # 随机抽 3 个(不删除)
SPOP lottery:pool 1                  # 抽 1 个并移除(开奖!)
SMEMBERS small_set                   # 集合小时用;大集一定要用 SSCAN

2.5 ZSet(Sorted Set,有序集合 = 排行榜 / 延迟队列 / 权重调度)

元素 = member + score(分数可重复,member 唯一)。

ZADD leaderboard:2026 1500 "Alice" 1200 "Bob" 2000 "Carol" 800 "Dave"
ZREVRANGE leaderboard:2026 0 9 WITHSCORES   # Top 10,降序(排 1 到 10)
ZRANK leaderboard:2026 "Bob"                 # Bob 排名(升序,从 0 起)
ZREVRANK leaderboard:2026 "Bob"              # 倒序排名
ZSCORE leaderboard:2026 "Carol"              # Carol 分数
ZINCRBY leaderboard:2026 100 "Bob"           # 分数 +100
ZCARD leaderboard:2026                       # 总人数
ZRANGEBYSCORE leaderboard:2026 1000 2000     # 分数区间取
ZREMRANGEBYRANK leaderboard:2026 100 -1      # 保留 Top 100,其他删掉

# 延迟队列:score 设为到期时间戳(ms),定时 ZRANGEBYSCORE -inf <now> 取到期任务

2.6 其他常用”高级类型”

类型应用关键字
Bitmap(String 上的位操作)用户签到 SETBIT、统计活跃用户 BITCOUNT、日留存 BITOPSETBIT / BITCOUNT / BITOP / BITPOS
HyperLogLog亿级 UV 近似去重统计(误差 < 2%)PFADD / PFCOUNT / PFMERGE,12KB 一个 key
Geo + ZSet 实现LBS 附近的人、附近的店GEOADD / GEORADIUS / GEOSEARCH
Stream(5.0+)Kafka 式持久化消息队列:消费组、ACK、拉历史XADD / XREADGROUP / XACK / XCLAIM
布隆过滤器(RedisBloom)“有没有命中过”,省内存但有假阳性BF.ADD / BF.EXISTS,要装模块
JSON / Search(Redis Stack)存 JSON、建二级索引、全文检索Redis Stack 发行版自带

三、通用命令 & 最佳实践

TYPE user:1                         # 看 key 的类型
TTL  user:1                         # 还剩多少秒过期;-1 = 永不过期;-2 = 不存在
EXPIRE user:1 7200                  # 2 小时后过期
SCAN 0 MATCH user:* COUNT 200       # 增量遍历 key(不会卡住 Redis,生产必须用这个,禁止 KEYS *)
EXISTS user:1
OBJECT idletime user:1              # 多久没访问(判断冷热)
MEMORY USAGE user:1                 # 这个 key 占多少字节

# 事务(弱事务:只保证排队原子执行,不回滚;不支持乐观锁要配合 WATCH)
MULTI
  INCR a
  INCR b
EXEC

Redis 客户端(各语言)

语言推荐库
Gogo-redis / rueidis
JavaJedis(小应用)+ Lettuce(Spring Data Redis 默认,线程安全)
Pythonredis-py(pip install redis[hiredis]
Nodeioredis / node-redis
PHPphpredis(C 扩展,性能好) / predis(纯 PHP)

几乎所有语言的客户端都支持”连接池 + Pipeline 批量 + 集群模式”,上线前务必开连接池而不是每请求新建连接。

四、持久化:RDB vs AOF

维度RDB(快照)AOF(Append Only File)
是什么某时刻内存全量快照,压缩二进制文件每一条写命令追加写日志文件
开关save 900 1 / save 300 10 / save 60 10000appendonly yes
恢复速度快(直接读二进制入内存)慢(逐条重放命令,重写后才快)
丢数据多(上一次快照之后到宕机全丢)少(appendfsync everysec 最多 1 秒)
文件体积大(要定期 BGREWRITEAOF 瘦身)
生产推荐两个都开(Redis 4.0+ 混合持久化 aof-use-rdb-preamble yes 综合两者优点)

持久化关键参数(redis.conf):

save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error no        # RDB 失败时是否禁止写入(谨慎 yes)
rdbcompression yes
rdbchecksum yes

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec                  # 每秒刷盘一次(性能+安全平衡,推荐)
no-appendfsync-on-rewrite yes        # rewrite 期间暂不 fsync,避免磁盘 IO 打架
auto-aof-rewrite-percentage 100      # AOF 比上次重写大一倍时自动重写
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes             # 混合持久化

五、架构升级路径

5.1 主从复制(读写分离 + 数据冗余)

# 从节点 redis.conf 加一行
replicaof master-ip 6379
masterauth "MasterPassword"
replica-read-only yes

验证:在 master SET foo 1 → 在 replica GET foo 能看到;INFO replicationrole:slave + master_link_status:up

⚠️ 注意:Redis 的主从复制是异步的,主挂了会丢少量数据,所以还要哨兵或 Cluster 做自动故障转移。

5.2 Redis Sentinel(哨兵:高可用)

3 个 Sentinel 节点 + 1 主 2 从。哨兵负责:监控、告警、自动故障转移(选主)、配置更新通知客户端新主地址

sentinel.conf(三个节点,配置几乎一样,改端口和 id):

port 26379
sentinel monitor mymaster 10.0.0.10 6379 2     # 2 = 多少个 sentinel 同意才故障转移
sentinel auth-pass mymaster MasterPassword
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

客户端连接时不要硬编码 master IP,用客户端 Sentinel 模式:先问 sentinel “mymaster 当前主是谁?“,拿了地址再连。

5.3 Redis Cluster(官方分片集群,超大规模用)

  • 至少 6 个节点(3 主 3 从)
  • 总共有 16384 个哈希槽(slot)分到所有主节点,key 根据 CRC16(key) % 16384 落在某个槽
  • 优点:线性水平扩展、单集群百 GB/万 QPS
  • 代价:不能跨节点多 key 事务、mget/rename 涉及多节点要 hash tag({user123}:profile{user123}:posts 用同一个 tag 保证同槽)
  • 现在生产用 Cluster 最简单的路径是:云厂商 Redis 实例(阿里云 Tair / 云数据库 Redis)直接选集群版

redis-cli --cluster create 搭建集群用内置工具就行;更推荐 redis-cli --cluster help 官方路线,不要用老的 redis-trib.rb。

六、缓存三大经典问题

问题描述解决办法
缓存穿透查的 key 永远不存在(恶意构造不存在的 ID 打到 DB)1) 空值也缓存(短 TTL 60s)
2) 布隆过滤器提前挡掉一定不存在的 key
3) 接口参数合法性校验 + 恶意 IP 限流
缓存击穿某一个热点 key 在 TTL 到期瞬间,同时几万请求打到 DB(秒杀商品详情)1) 热点 key “永不过期”(后台异步更新)
2) 加互斥锁:SETNX lock:key 1 EX 30 拿到锁的那个人去查 DB 回源,其他自旋等 100ms 再查缓存
3) 本地进程缓存(Caffeine / LRUMap)挡一层
缓存雪崩一瞬间大量 key 同时过期 or Redis 挂了 → DB 被打垮1) TTL 加随机抖动 TTL = 基础 + rand(0, 300s) 避免集体失效
2) 多级缓存(本地 + Redis)
3) Redis 高可用(Sentinel / Cluster)
4) DB 侧限流 + 熔断 + 降级兜底

七、日常排障手册

7.1 状态与健康检查

INFO                       # 最有用。所有统计:Server/Clients/Memory/Persistence/Stats/Replication/CPU/Cluster/Keyspace
INFO memory                # 内存
INFO stats                 # 命令计数、瞬时 ops
INFO replication           # 主从 / 哨兵关系
INFO persistence           # RDB + AOF 状态
INFO errorstats            # 命令级错误统计(7.0+)

最重要的几个字段快速解读:

字段好 / 坏判断
used_memory_human远超 maxmemory → 淘汰键了;长时间持续增长说明有泄漏 / 没设过期
mem_fragmentation_ratio> 1.5 碎片率高(可能需要重启 / 4.0+ MEMORY PURGE);< 1 说明被 SWAP,危险(会慢 100 倍)
connected_clients突增 = 客户端连接池配置错 / 没关连接 / 异常攻击
instantaneous_ops_per_sec突然变 0 = 全堵了;突然暴涨 = 活动热点
rejected_connections> 0 → 到了 maxclients 上限
keyspace_hits / keyspace_misseshit_rate = hits / (hits+misses) 太低(< 85%)说明缓存命中率差
rdb_last_bgsave_status / aof_last_bgrewrite_statusok / err,err 说明持久化失败(多半磁盘满、权限、fork 不出内存)
blocked_clients阻塞等待的客户端数(BLPOP / BLPUSH / 事务…)
latest_fork_usecfork 耗时微秒。> 1000000(1s)就危险,期间主进程阻塞(见下面 RDB fork 问题)

7.2 常见报错对照表

现象排查方式
(error) NOAUTH Authentication required没输密码。AUTH <密码>;或客户端连接时密码没传对 / 多节点哨兵模式下”从节点也要同样的密码”忘记配置
(error) READONLY You can't write against a read only replica写到了从节点。检查客户端 master 地址取对没;或者刚主从切换完,客户端缓存的旧 master 没及时刷新
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on diskRDB 持久化失败(bgsave 报错)。stop-writes-on-bgsave-error yes 是默认,会禁止写。临时先 CONFIG SET stop-writes-on-bgsave-error no,再查真因(磁盘满 / 权限 / 内存不够 fork)
(error) OOM command not allowed when used_memory > maxmemory内存到顶 + 淘汰策略没法淘汰(比如 noeviction 或全是永不过期 key + volatile-lru)。临时加大 maxmemory 或换 allkeys-lru / allkeys-lfu,长期:扩容 + 设 TTL + 清理大 key
(error) BUSY Redis is busy running a scriptLua 脚本/Function 跑太久 > lua-time-limit(默认 5s)。SCRIPT KILL 能杀还没写的;写了的只能 SHUTDOWN NOSAVE 再救
(error) CLUSTERDOWN Hash slot not servedCluster 有槽没覆盖 → 某主节点挂了 & 没完成 failover;或槽迁移中断了。redis-cli --cluster check 看详情
(error) CROSSSLOT Keys in request don't hash to the same slotmget / 事务 里的多 key 不在同槽。加 hash tag {tag}key1 {tag}key2 让它们进同槽
(error) ERR max number of clients reached连接数到顶。`CLIENT LIST
主从复制中断 master_link_status:down1) 网络不通:telnet masterIP 6379 + 防火墙
2) masterauth 密码错
3) Replication Backlog Buffer 太小,主积压的写命令 slave 赶不上 → 全量同步死循环,加大 repl-backlog-size 256mb
4) slave 自身 client-output-buffer-limit slave 256mb 64mb 60 设太小
慢查询超多 / 延迟飙升SLOWLOG GET 30 看最慢的 30 条命令 → 基本都是:
1) 误用 KEYS *
2) HGETALL / SMEMBERS / LRANGE 0 -1 用在百万级大 key 上
3) 大 value(MB 级)取存都慢
4) RDB/AOF rewrite 期间 fork 阻塞主线程

7.3 Redis 变慢排查标准流程

  1. 先看是不是慢在哪一层:应用到 Redis 网络 RTT?Redis 命令执行?Redis 写盘?
    • redis-cli --latency 本地测本机 Redis 指令延迟(≤1ms 正常)
    • redis-cli --intrinsic-latency 10 测操作系统调度/机器本身抖动(虚拟化常会抖)
    • 开启 AOF 慢:appendfsync 设成 everysec 会有 1s 级丢请求;或磁盘真的慢(iostat -x 1%util
  2. 大 key
    redis-cli --bigkeys -i 0.1   # 官方自带,抽样找最大的各类型 key
    # 或更准:python rdb-tools 离线分析 RDB 文件
    大 key 处理:hash 分桶、ZSet 按天分片、list 拆多个小 list、异步 DEL(UNLINK,非阻塞删大 key,Redis 4.0+,比 DEL 安全 100 倍)
  3. fork 耗时过长INFO stats latest_fork_usec → 大实例 fork 会阻塞毫秒~秒级。建议:控制单实例内存 ≤ 16-32GB(云厂商很多也这么卖),超大了就上 Cluster 分片;echo never > /sys/kernel/mm/transparent_hugepage/enabled 关 THP,能让 fork 快非常多。
  4. 内存被 swapcat /proc/$(pidof redis-server)/smaps | grep Swap 有非 0 就糟了。要么给 Redis 多留内存,要么 vm.swappiness = 1,要么 OOMScoreAdjust 让内核别 swap Redis。
  5. 慢命令SLOWLOG LENSLOWLOG GET 20,按命令把 KEYS/HGETALL/SMEMBERS/LRANGE 0 -1/ZRANGE 0 -1 这种 O(N) 全遍历批量换成 SCAN / 分批分页。

7.4 备份 & 恢复

# 1) 在线热备份(不会阻塞):bgsave → 拿到最新 dump.rdb
redis-cli -a xxx bgsave
# 等 INFO persistence 里 rdb_bgsave_in_progress:0
cp /var/lib/redis/dump.rdb /backup/redis-$(date +%Y%m%d).rdb

# 2) 从 RDB 恢复:停 redis → 把 dump.rdb 覆盖到数据目录 → 起 redis
#   AOF 开着的话,重启时会优先生效 AOF(看 redis.conf 加载顺序)

# 3) AOF 文件损坏修复(极少,断电 + fsync 没刷)
redis-check-aof --fix appendonly.aof

# 4) RDB 文件损坏修复(极少)
redis-check-rdb dump.rdb

7.5 安全被刷事件急救

  1. 发现 Redis 暴露在公网 + 被写了奇怪的 key / flushall 了
    • 立即:iptables -A INPUT -p tcp --dport 6379 -s <你的IP段> -j ACCEPT; iptables -A INPUT -p tcp --dport 6379 -j DROP
    • 关闭 CONFIG SET protected-mode yes(默认就是 yes,但被改过的话要回来)
    • 开启 requirepass
    • 检查 crontab /root/.ssh/authorized_keys 有没有被留后门(Redis 未授权写 cron / SSH 公钥是古老但最常用的入侵
  2. 被 FLUSHALL 了但还没新写很多
    • 如果有 AOF:AOF rewrite 还没运行 → redis-check-aof --fix 把 FLUSHALL 命令去掉,然后重放
    • 如果只有 RDB:最近的 RDB 备份恢复 + 之后业务补数据

八、学习路线

  1. 单机五大数据结构 + 常用命令熟练
  2. Pipeline / Lua / 事务 / 过期策略 → 深入内存模型 & 淘汰策略 & 淘汰算法 LRU/LFU
  3. 持久化原理:fork + COW(写时复制)、AOF fsync 三种、混合持久化
  4. 主从复制 + 哨兵(RDB/AOF/偏移量 backlog、PSYNC2 部分重同步)
  5. Redis Cluster 原理:Gossip、hash slot、MOVED/ASK 重定向、故障转移、hash tag
  6. 源码级:跳表、SDS 字符串、intset/ziplist/listpack 压缩结构、事件驱动(ae_epoll)
  7. 周边工具:RedisInsight(GUI)、RedisBloom / RedisJSON / RediSearch(Redis Stack)
  8. 云托管:阿里云 Tair / AWS ElastiCache / GCP Memorystore / Azure Cache,避免自己搞集群运维

参考资料

问问 AI