Redis 是内存键值数据库——所有数据在内存,读写极快(10万+ QPS),常用作缓存、会话、排行榜、限流、消息队列。核心特点:单线程模型、丰富数据类型、可持久化。这篇笔记覆盖日常开发 90% 的 Redis 用法:五大基础类型、常用命令、过期策略、持久化、事务、集群、缓存设计。
键值数据库:key → value(value 有 5 种基础类型)快:数据在内存,单线程顺序执行(避免锁开销)
数据类型丰富:字符串、哈希、列表、集合、有序集合(+Bitmap/HyperLogLog/Stream 等)
持久化:RDB 快照 + AOF 日志,重启不丢
默认端口:6379
# 本地连接
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。
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 串、二进制。计数器、分布式锁、验证码、限流都靠它。
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 可以单独改一个字段。
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 条)。
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 # 差集适合标签、点赞、好友关系(交集找共同好友)、去重。
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 里最强大的类型。
# 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 0expire 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 秒数据,是默认推荐。
# 事务: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 + 业务逻辑兜底。
# 发布订阅(实时消息,无持久化)
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 托管版已内置这些能力。
| 问题 | 场景 | 解法 |
| 缓存穿透 | 查不存在的数据(恶意/误查)→ 一直打 DB | 缓存空值、布隆过滤器 |
| 缓存击穿 | 热点 key 过期瞬间大量请求打 DB | 互斥锁、逻辑过期、热点不过期 |
| 缓存雪崩 | 大量 key 同一时间过期 | 过期时间加随机值、多级缓存 |
// 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(异步删)
keys *阻塞:生产环境遍历大库会卡死,用 scan替代。
不设过期导致内存爆炸:缓存必须设 TTL,否则一直累积。
缓存与 DB 不一致:先改 DB 后删缓存,并发下仍有窗口,关键业务加锁或延迟双删。
热 key 集中:某 key 访问极高导致单节点压力,做本地缓存 + 分散副本。
大 key 阻塞:删除大 list/set 用 UNLINK而非 DEL(异步删)。
连接泄露:用完不关闭,连接数爆满(maxclients默认 10000),用连接池。
select 多库滥用:集群不支持 select,统一用 db0 或 key 前缀区分。
过期精度:expire是秒级,pexpire才是毫秒;业务要精确到毫秒用 pexpire。
事务不回滚:Redis 事务中间失败不会回滚前面已执行的,要靠 Lua 或业务补偿。
Cluster 跨 slot:多 key 操作(mget)必须在同一 slot,用 hashtag({user1})约束。
AOF 文件膨胀:重写机制不全理解,默认 everysec 就好,重写期间磁盘 IO 高。
bind/protected-mode:默认只本机访问,远程连接要改 bind 和 requirepass。
序列化:存对象用 JSON 或 Protobuf,直接 toString 不易恢复类型。
并发自增:incr是原子的,别用 get+set 自己实现计数器。
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。