Redis 实战笔记:五大基础类型、过期策略、持久化、缓存设计

本文覆盖 Redis 日常开发 90% 用法,包括五大数据类型(String、Hash、List、Set、ZSet)、过期与内存淘汰策略、RDB+AOF 持久化、事务与 Lua 脚本、发布订阅与 Stream、集群与高可用(主从、哨兵、Cluster)、缓存三大问题(穿透、击穿、雪崩)及 Cache-Aside 模式。附带常见坑总结与速查卡,适合快速掌握 Redis 核心知识。

Redis 是内存键值数据库——所有数据在内存,读写极快(10万+ QPS),常用作缓存、会话、排行榜、限流、消息队列。核心特点:单线程模型、丰富数据类型、可持久化。这篇笔记覆盖日常开发 90% 的 Redis 用法:五大基础类型、常用命令、过期策略、持久化、事务、集群、缓存设计

一、基础认知

1.1 Redis 是什么

键值数据库:key → value(value 有 5 种基础类型)
  • :数据在内存,单线程顺序执行(避免锁开销)

  • 数据类型丰富:字符串、哈希、列表、集合、有序集合(+Bitmap/HyperLogLog/Stream 等)

  • 持久化:RDB 快照 + AOF 日志,重启不丢

  • 默认端口:6379

1.2 连接方式

# 本地连接
redis-cli
redis-cli -h 127.0.0.1 -p 6379 -a password

# 测试连通
127.0.0.1:6379> ping
PONG

# 通用命令
keys *                      # 查看所有 key(生产慎用,会阻塞)
exists key                  # key 是否存在
type key                    # 看类型
expire key 60               # 设置过期(秒)
ttl key                     # 剩余过期时间(-1 永不过期,-2 不存在)
persist key                 # 取消过期
del key                     # 删除
rename old new              # 重命名
dbsize                      # 当前库 key 总数
flushdb                     # 清空当前库(慎用!)
flushall                    # 清空所有库(超级慎用!)

keys * 在生产环境是危险操作(百万 key 会卡住),改用 scan 渐进遍历:scan 0 match user:* count 100

二、五大数据类型

2.1 String(字符串)

set key value               # 设置
set key value EX 60         # 设置并过期 60 秒
setnx key value             # 不存在才设置(分布式锁常用)
get key                     # 获取
mset k1 v1 k2 v2            # 批量设置
mget k1 k2                  # 批量获取
incr counter                # 自增 1(原子)
incrby counter 10           # 加 10
decr counter                # 减 1
append key "tail"           # 追加
strlen key                  # 长度
getset key newValue         # 取旧值设新值

最大 512MB。String 可存数字、JSON 串、二进制。计数器、分布式锁、验证码、限流都靠它。

2.2 Hash(哈希)

hset user:1 name "张三" age 18     # 设置字段
hget user:1 name                   # 取字段
hmset user:1 name "李四" age 20    # 多字段
hgetall user:1                     # 取全部
hkeys user:1                       # 所有字段名
hvals user:1                       # 所有值
hdel user:1 age                   # 删字段
hincrby user:1 age 1              # 字段自增
hexists user:1 name               # 字段是否存在

适合存对象(用户资料、商品信息)。对比:String 存 JSON 改字段要整体读写,Hash 可以单独改一个字段。

2.3 List(列表,双向链表)

lpush list a b c             # 左边推入(头插)=> c b a
rpush list x                 # 右边推入(尾插)
lrange list 0 -1             # 取全部(-1 末尾)
lpop list                    # 左边弹出
rpop list                    # 右边弹出
llen list                    # 长度
lindex list 0                # 按下标取
lrem list 1 "a"              # 删1个值为a的元素
ltrim list 0 10              # 只保留前11个(裁剪)

可做队列(lpush+rpop)、栈(lpush+lpop)、最新消息(lpush+ltrim 保留最新 N 条)。

2.4 Set(集合,无序去重)

sadd tags a b c              # 添加
smembers tags                # 全部成员
sismember tags a             # 是否包含
scard tags                   # 数量
srem tags a                  # 删除
spop tags                    # 随机弹出一个
srandmember tags             # 随机取一个(不删)
sinter s1 s2                # 交集
sunion s1 s2                 # 并集
sdiff s1 s2                  # 差集

适合标签、点赞、好友关系(交集找共同好友)、去重。

2.5 ZSet(有序集合,score 排序)

zadd rank 100 "张三" 200 "李四"    # 添加(score 权重)
zrange rank 0 -1                  # 按 score 升序取全部
zrevrange rank 0 -1               # 降序
zrange rank 0 -1 withscores       # 带分数
zscore rank "张三"                 # 查分数
zincrby rank 10 "张三"            # 加分
zrank rank "张三"                  # 排名(从0)
zrem rank "张三"                   # 删除
zcard rank                         # 数量
zrangebyscore rank 100 200         # 分数区间内

排行榜、延迟队列(score 用时间戳)、优先级队列都用它。是 Redis 里最强大的类型。

2.6 其他类型

# Bitmap:位运算(签到、在线状态)
setbit sign:2026-08-28 1 1
getbit sign:2026-08-28 1
bitcount sign:2026-08-28

# HyperLogLog:基数统计(UV)
pfadd uv user1 user2
pfcount uv

# Stream:消息流(类似 Kafka 轻量版)
xadd mystream * field1 v1
xread count 10 streams mystream 0

三、过期与内存

expire key 3600              # 3600 秒后过期
pexpire key 1000             # 毫秒
set key val ex 60            # 设置时直接过期
ttl key                      # -1 永不过期 / -2 不存在 / 数字=剩余秒

过期删除策略

  • 惰性删除:访问时才检查过期,删掉

  • 定期删除:后台周期性抽样检查

  • 内存淘汰(内存满时,靠 maxmemory-policy):noeviction(报错)/ allkeys-lru(全库LRU)/ volatile-lru(仅过期键LRU)/ allkeys-random/ volatile-ttl(快过期的先删)

缓存设计中一定要设过期,否则内存无限增长。热点数据可"逻辑过期"(存有效期字段,业务判断)避免缓存击穿。

四、持久化(两种机制)

机制原理优点缺点
RDB定时快照(二进制)恢复快、文件小可能丢最近数据
AOF记录每一条写命令数据更安全文件大、恢复慢
# 配置(redis.conf)
save 900 1          # 900秒内至少1次修改 → 触发 RDB
save 300 10
appendonly yes      # 开启 AOF
appendfsync everysec  # AOF 每秒刷盘(默认,平衡)

# 命令
bgsave              # 后台快照
bgrewriteaof        # 重写 AOF

生产建议:RDB + AOF 都开(RDB 做备份,AOF 保数据)。AOF 的 everysec最多丢 1 秒数据,是默认推荐。

五、事务与 Lua

# 事务:multi / exec(不保证原子失败回滚,而是"打包执行")
multi
set a 1
incr b
exec                 # 一起执行
discard              # 取消事务

# 乐观锁(Watch)
watch money          # 监视 key
multi
incrby money -10
exec                 # 若 money 期间被改,exec 返回 nil(事务不执行)
# Lua 脚本(原子执行,适合复杂操作)
eval "return redis.call('set', KEYS[1], ARGV[1])" 1 mykey "hi"

Redis 事务≠关系型事务:中间某条失败不会回滚已执行的命令,它只是"打包顺序执行"。需要原子性用 Lua 脚本或 pipeline + 业务逻辑兜底。

六、发布订阅与 Stream

# 发布订阅(实时消息,无持久化)
subscribe channel1            # 订阅(阻塞等待)
publish channel1 "hello"      # 发布
psubscribe news.*             # 模式订阅

# Stream(持久化消息流,推荐替代发布订阅做队列)
xadd mystream * name zhangsan    # 追加消息(* 自动生成ID)
xrange mystream - +              # 范围读
xread count 1 streams mystream $ # 阻塞读最新
xgroup create mystream g1 0      # 创建消费组
xreadgroup g1 consumer1 count 1 streams mystream >

简单通知用 publish/subscribe;需要持久化 + 消费组 + ACK 的队列场景用 Stream(Redis 5+)。

七、集群与高可用

# 主从复制
replicaof 127.0.0.1 6380      # 从节点复制主节点(redis.conf 里配 replicaof)

# 哨兵(Sentinel):监控 + 自动故障转移
sentinel monitor mymaster 127.0.0.1 6379 2    # 2 个哨兵同意才判定下线

# 集群(Cluster):数据分片(16384 个 slot)
redis-cli --cluster create ip1:port1 ip2:port2 ... --cluster-replicas 1

核心概念

  • 主从:一主多从,读写分离(从库只读)

  • 哨兵:主挂了自动选从库上位

  • Cluster:数据分片中,单节点故障不影响整体

选型:中小项目用主从 + 哨兵够用;海量数据 / 高并发用 Cluster 分片。云厂商(阿里云、AWS)的 Redis 托管版已内置这些能力。

八、缓存设计(实战重点)

8.1 缓存三大问题

问题场景解法
缓存穿透查不存在的数据(恶意/误查)→ 一直打 DB缓存空值、布隆过滤器
缓存击穿热点 key 过期瞬间大量请求打 DB互斥锁、逻辑过期、热点不过期
缓存雪崩大量 key 同一时间过期过期时间加随机值、多级缓存

8.2 典型读写模式

// Cache-Aside(旁路缓存,最常用)
// 读:先查缓存,没有查 DB,回填缓存
// 写:更新 DB,再删缓存(或更新缓存)

// 分布式锁(SET NX EX)
SET lock:order:1 <uuid> NX EX 30     # 抢锁
// 释放:用 Lua 保证原子(判断是自己加的锁再删)
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) end

先更新 DB 还是先删缓存? 一般"先更新 DB、再删缓存"(Cache-Aside),删除而非更新,避免并发下的脏数据。分布式锁务必设置过期 + 唯一标识,防止误删别人的锁。

九、常见问题排查

info memory                # 内存使用(used_memory, maxmemory)
info stats                 # 命令统计
slowlog get 10             # 慢查询(默认 >10ms 记录)
config get maxmemory       # 看上限
config set maxmemory 2gb   # 动态调上限
client list                # 看连接

BigKey 问题

  • 单个 String > 10KB / Hash/List/Set/ZSet > 5000 元素 → 删除/传输阻塞

  • redis-cli --bigkeys扫描定位

  • 解决:拆分、分批删除、用 UNLINK(异步删)

十、常见坑总结

  1. keys *阻塞:生产环境遍历大库会卡死,用 scan替代。

  2. 不设过期导致内存爆炸:缓存必须设 TTL,否则一直累积。

  3. 缓存与 DB 不一致:先改 DB 后删缓存,并发下仍有窗口,关键业务加锁或延迟双删。

  4. 热 key 集中:某 key 访问极高导致单节点压力,做本地缓存 + 分散副本。

  5. 大 key 阻塞:删除大 list/set 用 UNLINK而非 DEL(异步删)。

  6. 连接泄露:用完不关闭,连接数爆满(maxclients默认 10000),用连接池。

  7. select 多库滥用:集群不支持 select,统一用 db0 或 key 前缀区分。

  8. 过期精度expire是秒级,pexpire才是毫秒;业务要精确到毫秒用 pexpire。

  9. 事务不回滚:Redis 事务中间失败不会回滚前面已执行的,要靠 Lua 或业务补偿。

  10. Cluster 跨 slot:多 key 操作(mget)必须在同一 slot,用 hashtag({user1})约束。

  11. AOF 文件膨胀:重写机制不全理解,默认 everysec 就好,重写期间磁盘 IO 高。

  12. bind/protected-mode:默认只本机访问,远程连接要改 bind 和 requirepass。

  13. 序列化:存对象用 JSON 或 Protobuf,直接 toString 不易恢复类型。

  14. 并发自增incr是原子的,别用 get+set 自己实现计数器。

  15. ZSet 的 score 精度:score 是 double,极大/极小 score 排序要小心精度问题。

附录:速查卡

# 连接
redis-cli  /  redis-cli -h host -p port -a pwd

# 通用
keys/exists/type/expire/ttl/del/scan

# 类型命令
String:  set/get/mset/incr/setnx
Hash:    hset/hget/hgetall/hincrby
List:    lpush/rpush/lrange/lpop
Set:     sadd/smembers/sinter/sunion
ZSet:    zadd/zrange/zrevrange/zincrby

# 持久化
save/bgsave/appendonly/bgrewriteaof

# 集群
info/replicaof/sentinel/cluster

# 设计口诀
缓存:Cache-Aside(读缓存、写删缓存)
锁:SET key uuid NX EX n + Lua 删
限流:incr + expire(或令牌桶 Lua)

Redis 上手路径:先把五大数据类型的命令练熟(90% 的业务操作都在这里面),再理解过期/淘汰持久化,最后掌握缓存设计三件套(穿透/击穿/雪崩)和分布式锁。官方文档 https://redis.io/docs/latest/ 的命令参考(Commands)可按字母查完整参数。记住:Redis 是缓存,不是数据库 —— 核心数据要有 DB 兜底,别把唯一真相放 Redis。

学习有两忌,自高和自狭。 —— 书摘
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号