REDIS · 缓存内存库 / 高频命令
Redis速查
覆盖五大基础结构与扩展结构、过期删除与内存淘汰、RDB/AOF 持久化、主从哨兵与 Cluster 高可用、缓存三大问题及分布式锁方案,背面试、写业务时即查即用。
9速查小节
57速查条目
5大基础结构
8种淘汰策略
📖 速查表
点击展开各小节
🧱 五大基础结构
| 结构 | 底层编码 | 高频命令与典型场景 |
|---|---|---|
| String | int(纯整数)/ embstr(≤44 字节)/ raw(SDS 动态字符串) | SET / GET / INCR / SETNX;缓存对象、计数器、分布式锁 |
| List | quicklist(双向链表 + listpack 节点,3.2 前为 ziplist 节点) | LPUSH / RPOP / LRANGE / BLPOP;消息队列、最新列表、时间线 |
| Hash | listpack(7.0 前 ziplist,元素少且短时)/ hashtable | HSET / HGET / HGETALL / HINCRBY;存对象、购物车 |
| Set | intset(全为整数时)/ listpack(7.0)/ hashtable | SADD / SISMEMBER / SINTER / SRANDMEMBER;标签、抽奖去重、共同好友 |
| ZSet | listpack(7.0 前 ziplist)/ skiplist(跳表 + dict 双结构) | ZADD / ZRANGE / ZREVRANK / ZINCRBY;排行榜 延迟队列 |
🧮 扩展结构
| 结构 | 用途 | 代表命令 |
|---|---|---|
| BitMap | 用 1 个 bit 表示 0/1 状态,极致省内存;签到 活跃用户统计、布隆过滤器底层 | SETBIT / GETBIT / BITCOUNT / BITOP |
| HyperLogLog | 基数估算,固定约 12KB,误差约 0.81%;UV 统计这类允许误差的去重计数 | PFADD / PFCOUNT / PFMERGE |
| GEO | 底层为 ZSet,存经纬度并按距离索引;附近的人、附近门店 | GEOADD / GEOPOS / GEODIST / GEOSEARCH |
| Stream | 可持久化消息队列(5.0+),支持消费者组、ACK 确认与消息回溯;MQ 轻量替代 | XADD / XREAD / XREADGROUP / XACK |
⏰ 过期与淘汰
| 过期删除策略 | 机制 | 权衡 |
|---|---|---|
| 惰性删除 | 访问 key 时才检查是否过期,过期则删除并返回空 | CPU 友好;但长期不访问的过期 key 会残留占内存,需定期删除兜底 |
| 定期删除 | 默认每秒 10 次(hz 10)从过期字典随机抽查,过期比例超过 1/4 就继续下一轮 | 在 CPU 与内存之间折中;与惰性删除配合覆盖绝大多数过期场景 |
| 内存淘汰策略 | 淘汰范围 | 说明 |
|---|---|---|
| noeviction | 不淘汰 | 内存写满后写命令直接报 OOM 错误 默认 |
| volatile-lru | 仅设置了过期时间的 key | 淘汰最久未被使用的 key(近似 LRU,采样而非全量) |
| volatile-lfu | 仅设置了过期时间的 key | 淘汰访问频率最低的 key(4.0+,Morris 计数 + 衰减) |
| volatile-ttl | 仅设置了过期时间的 key | 优先淘汰剩余存活时间(TTL)最短的 key |
| volatile-random | 仅设置了过期时间的 key | 在过期 key 中随机淘汰 |
| allkeys-lru | 全部 key | 淘汰最久未使用的 key,纯缓存场景首选 最常用 |
| allkeys-lfu | 全部 key | 淘汰访问频率最低的 key(4.0+),适合热点明显的访问分布 |
| allkeys-random | 全部 key | 全库随机淘汰,访问分布均匀时才可接受 |
💾 持久化
RDB 是某一时刻的全量快照、AOF 是每条写命令的流水账;生产标配是 4.0+ 的混合持久化——恢复快、丢得少。
| 对比项 | RDB 快照 | AOF 日志 |
|---|---|---|
| 原理 | 某一时刻全量内存数据的二进制快照 | 以文本追加方式记录每条写命令(RESP 协议) |
| 触发方式 | save 阻塞主线程;bgsave fork 子进程;配置 save 900 1 自动触发 | 写后记日志,刷盘策略 appendfsync always / everysec / no |
| 优点 | 文件紧凑体积小、恢复速度快,适合定时备份与容灾传输 | everysec 最多丢约 1 秒数据,可读性好,日志可人工修复 |
| 缺点 | 两次快照之间宕机会丢数据;fork 瞬间阻塞,写时复制放大内存占用 | 文件大、恢复慢;命令膨胀需 AOF 重写(bgrewriteaof)压缩 |
| 配置要点 | save 900 1、dbfilename dump.rdb、dir 指定落盘目录 | appendonly yes、appendfsync everysec(性能与安全折中) |
| 混合持久化 | 4.0+ aof-use-rdb-preamble yes:AOF 重写时前半段写 RDB 全量、后半段追加增量命令,恢复快且丢数据少 推荐 | |
🔁 高可用
| 机制 | 核心流程 | 要点与注意 |
|---|---|---|
| 主从复制 | 首次为全量同步:主库 bgsave 生成 RDB 传输给从库,再补发缓冲区增量;之后进入命令传播 | 断线重连时 2.8+ 依据 repl_backlog 偏移量做部分重同步,backlog 太小会退化为全量 |
| 读写分离 | 主库写、从库读,分摊读压力 | 复制是异步的,存在主从延迟可能读到旧数据;从库过多会放大主库传播压力 |
| 哨兵 Sentinel | 监控:主库无响应标记主观下线,多数哨兵确认后升级客观下线;领头哨兵(Raft 式选举)执行故障转移 | 从从库中按优先级、复制偏移量挑新主,并通知客户端新地址;哨兵自身需多节点部署 |
| Cluster 集群 | 数据划分 16384 个 hash slot,CRC16(key) % 16384 定位;节点间 gossip 协议交换状态 | 槽位迁移中返回 ASK 重定向,已易主返回 MOVED;智能客户端本地缓存槽位映射表 |
| 为什么是 16384 | 心跳包需携带槽位图,16384 位即 2KB,体积可控 | 官方建议集群不超过 1000 节点,16384 个槽足够分配,再大只会浪费心跳带宽 |
🚧 缓存三大问题
三者区分口诀:穿透是查「根本不存在的数据」、击穿是「热点 key 恰好过期」、雪崩是「大面积同时失效或实例宕机」——对因下药才有效。
| 问题 | 成因 | 典型后果 |
|---|---|---|
| 缓存穿透 | 查询的数据在缓存和 DB 中都不存在,请求永远打不到缓存层 | 恶意攻击或业务误用时,DB 被无效查询打满 |
| 缓存击穿 | 某个热点 key 在过期瞬间,大量并发同时请求并直击 DB 重建缓存 | 瞬时 DB 压力陡增,接口超时甚至雪崩 |
| 缓存雪崩 | 大量 key 同一时刻集中过期,或 Redis 实例整体宕机 | 请求洪峰全部涌入 DB,引发级联故障 |
| 解决方案 | 应对问题 | 说明 |
|---|---|---|
| 布隆过滤器 | 穿透 | 缓存前拦截:判定「不存在」则直接返回;有误判率、不支持删除,可用布谷鸟过滤器改进 |
| 空值缓存 | 穿透 | 把「不存在」的结果以短 TTL(如 60s)缓存,避免同一无效 key 反复打库 |
| 互斥锁重建 | 击穿 | 只放一个线程查 DB 重建缓存(SETNX 分布式锁或 singleflight),其余线程等待或返回旧值 |
| 逻辑过期 | 击穿 | 不设物理 TTL,value 内存过期时间字段;发现逻辑过期后异步重建,读请求永不阻塞 |
| 过期时间打散 | 雪崩 | TTL 加随机偏移(如 30min + 随机 10min),错峰失效避免同时过期 |
| 熔断限流 + 多级缓存 | 雪崩 | 限流降级保护 DB;本地缓存 + Redis 多级兜底;部署哨兵 / Cluster 保证缓存层高可用 |
🔐 分布式锁与一致性
| 主题 | 说明 | 示例 / 模板 |
|---|---|---|
| SET NX EX 加锁 | 加锁与设置过期时间必须原子(不能拆成 SETNX + EXPIRE 两条命令);value 存唯一标识防误删 | SET lock:order unique_value NX EX 30 |
| Lua 安全释放 | 释放前校验 value 是否为自己的锁,判断 + 删除保持原子性 | if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) end |
| 看门狗续期 | Redisson 加锁未指定 leaseTime 时启用看门狗,默认锁 30s、每 10s(1/3)自动续期,防止业务未完成锁先过期 | redissonClient.getLock("lock").lock() |
| Redlock 争议 | 多节点过半加锁才成功的红锁算法;Martin Kleppmann 质疑其时钟假设与 fencing token 缺失,生产更常用 Redisson 主从 + 业务兜底 | 一句话:强正确性场景别把 Redis 锁当唯一屏障,落库层再加唯一约束 |
| 先更库后删缓存 | Cache-Aside 标准写法:先更新 DB,再删除缓存,下次读回填;并发脏数据窗口比「先删缓存后更库」小 首选 | update DB → DEL cache |
| 延迟双删与兜底 | 删缓存 → 更库 → 延迟几百毫秒再删一次,覆盖读写并发下旧值回填窗口;要求更高可用 Canal 订阅 binlog 异步删缓存 | 缓存与 DB 本就无法强一致,业务侧需接受短暂不一致或串行化写入 |
🧯 线上故障演练
Redis 的线上事故大多重复发生:大 key、热 key、内存打满、慢命令……把下面 6 类故障的「现象 → 根因 → 处置」背熟,值班时能救命。
| 故障 | 典型现象 / 根因 | 处置方案 |
|---|---|---|
| 大 key 删除卡顿 | DEL 百万元素的 Hash / Set 会同步释放内存,主线程卡顿数百毫秒,监控毛刺、请求超时 | 用 UNLINK 异步释放(4.0+,后台线程分段回收),或 SCAN 分批删字段;上线前用 --bigkeys 排查存量 |
| 热 key 打满网卡 | 单 key QPS 极高,所在节点带宽 / CPU 打满,其余 key 受牵连;多见于爆款商品、明星微博 | 应用层本地缓存(Caffeine)挡一层;key 拆多副本 key:1..N 随机读分摊流量;集群模式把热 key 所在槽位独占节点 |
| 主从切换丢数据 | 主库宕机瞬间,尚未复制到从库的写入丢失;appendfsync everysec 崩溃也约丢 1 秒 | 配置 min-replicas-to-write 1 + min-replicas-max-lag 10:从库不足时拒绝写入,宁可不可用也不丢数据;持久化按业务权衡 |
| 内存打满 | used_memory 逼近 maxmemory,写入报 OOM,或淘汰策略误删了不该删的 key | 纯缓存设 allkeys-lru / lfu;TTL 加随机偏移打散过期;治理大 key;别用 noeviction 硬扛 |
| 慢命令阻塞 | Redis 单线程,KEYS *、全量 HGETALL、大集合 SUNION 执行期间所有请求排队 | 生产禁用 KEYS(改 SCAN 游标遍历);批量读合并为 MGET / pipeline 降网络往返;大集合改分页取 |
| 连接暴涨 | 突发流量或应用泄漏连接,超过 maxclients 后新连接被拒,报错 max number of clients reached | 连接池限流(合理 maxTotal + 空闲回收)+ 客户端设 timeout 排查阻塞;CLIENT LIST 按 idle 找泄漏来源 |
🛠 运维命令速查
排查线上问题常用的 6 组命令,从找大 key 到调内存上限一条龙;每条都标注了使用注意,避免「排障工具变成故障源」。
| 命令 | 用途 | 要点与注意 |
|---|---|---|
| redis-cli --bigkeys | 扫描各类型最大的 key(String 最长 / 集合元素最多) | 采样式统计,对线上压力小,配 -i 0.1 控制节奏;精确内存用 MEMORY USAGE key |
| redis-cli --latency | 探测服务端延迟,定位网络抖动 / fork 卡顿 | --latency-history 每 15 秒采样一段可画趋势;延迟尖刺常与 bgsave / AOF 重写的 fork 时刻重合 |
| SLOWLOG GET 10 | 查看最近 10 条慢命令日志 | 阈值由 slowlog-log-slower-than 控制(默认 10ms),只记录不阻断;看完可 SLOWLOG RESET 清空 |
| INFO memory | 内存全景:用量、峰值、碎片率、淘汰计数 | 重点看 used_memory_human 与 mem_fragmentation_ratio(> 1.5 碎片偏高,< 1 说明 swap 了) |
| CONFIG SET maxmemory 4gb | 在线调整内存上限,无需重启 | 改完 CONFIG REWRITE 写回配置文件才持久;同步确认 maxmemory-policy 淘汰策略是否匹配 |
| CLIENT LIST | 列出所有客户端连接的地址、空闲时长、最近命令 | 按 idle 倒序排查连接泄漏;MONITOR 危险:实时输出全部命令、性能杀手,仅排障短时开启 |