
Redis
- 15 installs
- 1 repo stars
- Updated July 29, 2026
- full-statck-skills/database-skills
Guides Redis work including caching, data structures, pub/sub, and key-value operations.
About
Provides guidance for Redis including caching patterns, data structures, and key-value operations. A developer uses it when adding caching, sessions, or a fast key-value store to an application.
- Key-value and caching patterns
- Data structures and pub/sub coverage
Redis by the numbers
- 15 all-time installs (skills.sh)
- Ranked #593 of 911 Databases skills by installs in the Skillselion catalog
- Data as of Jul 30, 2026 (Skillselion catalog sync)
npx skills add https://github.com/full-statck-skills/database-skills --skill redisAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 15 |
|---|---|
| repo stars | ★ 1 |
| Last updated | July 29, 2026 |
| Repository | full-statck-skills/database-skills ↗ |
What it does
Guides Redis work including caching, data structures, pub/sub, and key-value operations.
Files
Redis — 内存数据结构存储系统
Redis(Remote Dictionary Server)是一个开源的内存数据结构存储系统,用作数据库、缓存和消息代理。
Workflow — 使用流程
遇到 Redis 相关需求时,按以下顺序决策:
Step 1: 明确场景
├── 缓存加速? → 转到 Step 2
├── 数据结构存储? → 转到 Step 2
├── 消息队列? → 转到 1.7 Stream 章节
├── 分布式锁? → 转到 2.4 分布式锁
├── 高可用/集群? → 转到 4. 高可用架构
└── 性能问题? → 转到 6. 性能优化
Step 2: 选择数据结构
├── 简单键值 / 计数器 / Session → String
├── 对象存储 (多字段) → Hash
├── 队列 / 时间线 / 日志 → List
├── 标签 / 社交关系 / 去重 → Set
├── 排行榜 / 延时队列 / 范围查询 → ZSet
├── 签到 / 在线状态 / 布隆过滤 → Bitmap
├── UV 统计 / 去重计数 → HyperLogLog
└── 附近的人 / 地理围栏 → Geo
Step 3: 确定持久化策略
├── 允许丢少量数据? → RDB (默认配置)
├── 高数据安全要求? → AOF appendfsync everysec
├── 最佳性价比? → 混合持久化 (推荐)
└── 纯缓存 (不持久化)? → 关闭持久化
Step 4: 部署架构
├── 单机 (<16GB, 可容忍宕机) → 单机 + AOF
├── 主从 (读流量大) → 主从复制
├── 高可用 (自动故障转移) → Sentinel (3节点)
├── 水平扩展 (>单机内存) → Cluster (6节点起)
└── 读写分离 + 高可用 → Sentinel + 读写分离When to Use (and When NOT to)
| ✅ Use When | ❌ Skip When |
|---|---|
| 需要极低延迟(<1ms)的键值存取 | 需要复杂 SQL 关联查询和事务性报表 |
| 热点数据缓存以减轻数据库压力 | 数据持久性要求超过内存可承受范围 |
| 高并发计数器(INCR/DECR) | 需要完整的 ACID 事务保证(用关系型数据库) |
| 排行榜/时间线/消息队列等数据结构场景 | 数据量远大于内存容量且不需要高速访问 |
| 分布式锁/限流/会话管理 | 已经使用成熟的分布式缓存中间件且不迁移 |
| 实时分析、地理位置搜索、UV 统计 | 需要数据之间强引用约束和外键 |
核心原则:Redis 是内存数据库,不是关系型数据库替代品。
Boundary — 能力边界
| ✅ 完全适用 | ⚠️ 有条件适用 | ❌ 不适用 |
|---|---|---|
| 缓存加速、API 响应提速 | 强一致性要求场景(需配合 DB + 锁) | 代替关系型数据库作为唯一存储 |
| 计数器、排行榜、时间线 | Redis 作为消息队列(Stream 替代 Pub/Sub) | 复杂 SQL 查询和 JOIN |
| 分布式锁、限流、Session 存储 | 生产数据量 > 内存的场景(需 Cluster) | 存储大文件或二进制数据 |
| 实时排行榜、地理空间查询 | 作为主数据库存储核心业务事务 | 需要外键约束和引用完整性 |
| 去重统计(HyperLogLog/Bitmap) | 跨业务共享 Redis 实例(需 ACL 隔离) | 替代搜索引擎做全文搜索(用 RediSearch) |
超出范围时:请使用 PostgreSQL(关系型数据)、MongoDB(文档型)、Elasticsearch(全文搜索)、RabbitMQ/Kafka(消息队列)。
When to trigger this skill
ALWAYS use this skill when the user mentions:
- "Redis", "缓存", "cache", "Session 存储", "分布式锁"
- "String", "Hash", "List", "Set", "ZSet", "Sorted Set", "Geo", "HyperLogLog", "Stream"
- "SET / GET / INCR /... (any Redis command)"
- "RDB", "AOF", "持久化", "Persistence"
- "主从", "Sentinel", "Cluster", "哨兵", "集群", "切片"
- "redis.conf", "redis-cli", "redis-benchmark"
- "Lua 脚本", "事务 / MULTI / EXEC", "Pipeline", "Pub/Sub"
- "缓存穿透", "缓存雪崩", "缓存击穿", "Big Key", "Hot Key"
- "Redis 性能优化", "慢查询", "内存淘汰"
---
1. Redis 核心数据结构与命令
1.1 数据结构选型速查表
| 数据结构 | 底层实现 | 最佳场景 | 复杂度 | 最大容量 |
|---|---|---|---|---|
| String | SDS (Simple Dynamic String) | 缓存、计数器、Session、分布式锁 | O(1) | 512MB |
| Hash | ziplist / dict | 对象存储(用户、文章)、字段更新 | O(n) n为字段数 | 4294967295 字段 |
| List | quicklist | 消息队列、时间线、日志 | O(1) 头尾 | 4294967295 元素 |
| Set | intset / dict | 标签、社交关系、去重 | O(1) 增删查 | 4294967295 成员 |
| ZSet | ziplist / skiplist+dict | 排行榜、延时队列、范围查询 | O(log n) 跳表 | 4294967295 成员 |
| Bitmap | String 位操作 | 签到/活跃用户统计、布隆过滤 | O(1) 位操作 | 512MB (2^32位) |
| HyperLogLog | 概率数据结构 | UV 统计、去重计数 | O(1) | 12KB/键 (0.81%误差) |
| Geo | ZSet 封装 | 附近的人、地理围栏 | O(log n) | 同 ZSet |
| Stream | radix tree | 消息队列、事件溯源、消费组 | O(log n) | 4294967295 消息 |
1.2 String 命令与示例
# 基础操作
SET key "value" -- 设置值
SET key "value" EX 60 -- 设置值 + 60s 过期
SET key "value" NX -- 仅 key 不存在时设置 (分布式锁)
GET key -- 获取值
GETSET key "new" -- 设置新值返回旧值 (原子操作)
STRLEN key -- 获取字符串长度
APPEND key "suffix" -- 追加
# 数字操作 (Redis 内部数字存储为字符串)
INCR counter -- 原子 +1 (自增)
INCRBY counter 10 -- 原子 +10
DECR counter -- 原子 -1
DECRBY counter 5 -- 原子 -5
INCRBYFLOAT price 1.5 -- 浮点数增加
# 批量操作
MSET k1 v1 k2 v2 -- 批量设置 (非原子)
MGET k1 k2 -- 批量获取
MSETNX k1 v1 k2 v2 -- 仅当所有 key 都不存在时设置 (原子)
# 子串操作
GETRANGE key 0 -1 -- 获取全部子串
SETRANGE key 6 "Redis" -- 从偏移 6 覆写
# 带过期操作
SETEX key 3600 "value" -- 设置值 + 秒级过期
PSETEX key 3000 "value" -- 设置值 + 毫秒级过期String 编码选择:值 ≤ 44 字节用 embstr(一次内存分配),> 44 字节用 raw(两次分配)。
1.3 Hash 命令与示例
HSET user:1001 name "Alice" age 30 -- 设置多字段
HGET user:1001 name -- 获取单字段
HMGET user:1001 name age -- 获取多字段
HGETALL user:1001 -- 获取所有字段 (慎用,大 key 场景阻塞)
HKEYS user:1001 -- 获取所有字段名
HVALS user:1001 -- 获取所有字段值
HDEL user:1001 age -- 删除字段
HEXISTS user:1001 name -- 检查字段是否存在
HLEN user:1001 -- 字段数量
HINCRBY user:1001 score 10 -- 字段数值增加
HSETNX user:1001 email "a@b.com" -- 仅字段不存在时设置Hash 编码选择:字段数 < 512 且每个值长度 < 64 字节使用 ziplist(节省内存),否则升级为 dict(哈希表)。可配置 hash-max-ziplist-entries 和 hash-max-ziplist-value。
1.4 List 命令与示例
# 右进左出 (队列模式 - FIFO)
RPUSH queue "job1" "job2" -- 右边推入一个或多个
LPOP queue -- 左边弹出
# 左进右出 (栈模式 - LIFO)
LPUSH stack "a" "b" -- 左边推入
RPOP stack -- 右边弹出
# 范围操作
LRANGE list 0 -1 -- 获取全部元素
LINDEX list 0 -- 获取指定索引元素
LLEN list -- 列表长度
LTRIM list 0 99 -- 修剪保留前 100 个
LREM list 2 "value" -- 移除 2 个匹配的值
LSET list 0 "new" -- 设置指定索引的值
LINSERT list BEFORE "b" "a" -- 在元素前插入
# 阻塞操作 (超时秒数,0 表示无限等待)
BLPOP queue 5 -- 阻塞式左弹出,超时 5s
BRPOP queue 5 -- 阻塞式右弹出List 编码选择:元素数量或单个元素长度超阈值后从 quicklist 模式(ziplist 节点链表)转为 linkedlist。
典型场景:
LPUSH + LTRIM= 固定长度最新消息列表RPUSH + BLPOP= 可靠消息队列BRPOPLPUSH= 安全队列(备份到 backup list)
1.5 Set 命令与示例
SADD tags "redis" "database" -- 添加成员
SREM tags "database" -- 移除成员
SMEMBERS tags -- 获取所有成员 (慎用于大 set)
SISMEMBER tags "redis" -- 判断成员 O(1)
SCARD tags -- 成员数量
# 集合运算 (支持集合间操作)
SINTER set1 set2 -- 交集
SUNION set1 set2 -- 并集
SDIFF set1 set2 -- 差集
SINTERSTORE dest s1 s2 -- 交集存到新 key
SUNIONSTORE dest s1 s2 -- 并集存到新 key
SDIFFSTORE dest s1 s2 -- 差集存到新 key
# 随机操作
SRANDMEMBER key 3 -- 随机返回 3 个成员 (不删除)
SPOP key 2 -- 随机弹出 2 个成员 (删除)
SSCAN key 0 COUNT 100 -- 渐进迭代 (避免阻塞)1.6 ZSet (Sorted Set) 命令与示例
ZADD leaderboard 100 "player1" 200 "player2" -- 添加成员及分数
ZREM leaderboard "player1" -- 移除成员
ZSCORE leaderboard "player1" -- 获取分数
ZCARD leaderboard -- 成员数量
ZINCRBY leaderboard 50 "player1" -- 增加分数
# 按排名查
ZRANGE leaderboard 0 -1 WITHSCORES -- 按分数从小到大 (加分差)
ZREVRANGE leaderboard 0 -1 WITHSCORES -- 按分数从大到小 (排行榜)
ZRANK leaderboard "player1" -- 获取排名 (从小到大)
ZREVRANK leaderboard "player1" -- 获取排名 (从大到小)
# 按分数范围查
ZRANGEBYSCORE salary 2000 5000 -- 按分数范围查询
ZREVRANGEBYSCORE salary 5000 2000 -- 按分数范围逆序
ZCOUNT salary 2000 5000 -- 统计分数区间数
ZREMRANGEBYSCORE salary 0 1000 -- 移除分数区间成员
# 按字典序范围查
ZRANGEBYLEX words [a [z -- 字典序范围查询
ZLEXCOUNT words [a [z -- 统计字典序区间数
ZREMRANGEBYLEX words [a [z -- 移除字典序区间成员
# 集合运算
ZINTERSTORE dest 2 z1 z2 -- 交集
ZUNIONSTORE dest 2 z1 z2 -- 并集
ZSCAN leaderboard 0 COUNT 100 -- 渐进迭代ZSet 编码选择:成员数 < 128 且所有值长度 < 64 字节时用 ziplist,否则用 skiplist + dict。
1.7 高级数据结构
# Bitmap — 位图
SETBIT sign:2024-01 100 1 -- 用户 100 在 1月签到
GETBIT sign:2024-01 100 -- 查询签到状态
BITCOUNT sign:2024-01 -- 统计签到人数
BITOP AND dest sign:01 sign:02 -- 位运算 (AND/OR/NOT/XOR)
# HyperLogLog — 基数统计 (0.81% 误差)
PFADD visits:2024-01 "user1" "user2" -- 添加元素
PFCOUNT visits:2024-01 -- 近似去重计数
PFMERGE total visits:01 visits:02 -- 合并
# Geo — 地理位置
GEOADD cities 116.397 39.908 "北京" -- 添加地标
GEODIST cities "北京" "上海" km -- 计算两地距离
GEORADIUS cities 116.4 39.9 100 km -- 查找 100km 内的位置
GEORADIUSBYMEMBER cities "北京" 500 km -- 以成员为中心查找
GEOHASH cities "北京" -- 返回 geohash 字符串
GEOPOS cities "北京" -- 返回经纬度
# Stream — 消息流 (Redis 5.0+)
XADD mystream * sensor-id 1234 temp 19.8 -- 追加消息 (自动时间戳ID)
XLEN mystream -- 消息长度
XRANGE mystream - + -- 范围查询
XREAD COUNT 10 STREAMS mystream 0 -- 读取消息
XGROUP CREATE mystream mygroup $ -- 创建消费组
XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream > -- 消费
XACK mystream mygroup 1648123456789-0 -- 确认消息---
2. 缓存模式与架构
2.1 缓存读取模式
Read-Through: 应用 → Redis → 数据库
命中 ✓ 返回 未命中 ✗ 回源# Cache-Aside (旁路缓存) — 最常用模式
GET cache_key → 命中返回
→ 未命中: 查 DB → SET cache_key value EX 3600 → 返回
# 伪代码
function get_user(user_id):
user = redis.get("user:" + user_id)
if user is None:
user = db.query("SELECT * FROM users WHERE id=?", user_id)
redis.setex("user:" + user_id, 3600, user)
return user2.2 缓存更新模式
| 模式 | 操作方法 | 并发安全 | 说明 |
|---|---|---|---|
| Cache-Aside | 更新 DB → 删除缓存 | ⚠️ 删除失败有脏数据 | 最通用,使用最广泛 |
| Write-Through | 更新 DB → 同步更新缓存 | ✅ 一致性高 | 写延迟增加,适合写少读多 |
| Write-Behind | 先写缓存 → 异步写 DB | ⚠️ 宕机可能丢数据 | 性能最佳,适合允许略丢数据的场景 |
| Refresh-Ahead | 缓存过期前自动刷新 | ✅ 无过期风暴 | 适合热点 key |
2.3 缓存三大问题
缓存穿透 (Cache Penetration)
├── 问题:查询一个不存在的数据,每次穿透到 DB
├── 后果:大量请求直接打到数据库,可能击垮 DB
├── 解决:
│ ├── ① 布隆过滤器 (Bloom Filter): 用 Bitmap 预判 key 是否存在
│ ├── ② 缓存空值: SET key "" EX 60 (短过期时间)
│ └── ③ 参数校验: 非法参数直接拒绝
└── 提示:推荐组合使用 ① + ②
缓存击穿 (Cache Breakdown / Hot Key)
├── 问题:热点 key 过期瞬间,高并发直接打到 DB
├── 后果:瞬间高并发,DB 扛不住
├── 解决:
│ ├── ① 互斥锁 (Mutex Lock): SETNX 争锁,只有一个线程回源
│ ├── ② 永不过期 + 异步刷新: 物理上不设 TTL,后台线程定时更新
│ └── ③ 热点 key 预留: 预估热点,预加载
└── 提示:互斥锁实现最简单,异步刷新性能最优
缓存雪崩 (Cache Avalanche)
├── 问题:大量缓存同时过期/Redis 宕机,流量直击 DB
├── 后果:DB 被击垮,服务雪崩
├── 解决:
│ ├── ① TTL 随机化: SET key EX (300 + random(0,60))
│ ├── ② 互斥锁: 同击穿方案
│ ├── ③ 双缓存: 主缓存 + 备份缓存
│ ├── ④ Redis 高可用: 主从 + Sentinel/Cluster
│ └── ⑤ 本地缓存 + Redis: 二级缓存 (guava/caffeine)
└── 提示:TTL 随机化是最低成本最高收益的预防措施2.4 分布式锁
# 最简单的分布式锁 (单 Redis 实例)
SET lock:resource "uuid-value" NX EX 30 -- 加锁
-- 执行业务逻辑...
DEL lock:resource -- 释放锁
# 问题:误删其他线程的锁 → 需要 Lua 脚本保证原子性
# 正确的解锁 (Lua 脚本)
-- EVAL "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock:resource uuid-value
# Redlock 算法 (多实例场景)
# 1. 获取当前时间 T1
# 2. 向 N/2+1 个实例尝试加锁 (SET NX PX)
# 3. 用去时间 > 锁有效时间 → 加锁失败,向所有实例发送解锁
# 4. 使用 Redisson / Redlock-py 等客户端实现
# 最佳实践:使用 Redisson 等成熟客户端,不要自行实现2.5 常见缓存 Key 设计规范
# 命名规范
cache:user:{id} -- 用户缓存
cache:article:{id} -- 文章缓存
lock:order:{order_id} -- 分布式锁
rate:limit:ip:{ip} -- 限流
session:{session_id} -- Session
# 过期时间策略
- 通用原则: TTL = 业务可接受的脏数据时间 + random(0, TTL*1/5)
- 静态数据 (配置表): 1-24 小时
- 动态数据 (用户信息): 5-30 分钟
- 热点数据 (首页推荐): 1-5 分钟 + 异步刷新
# Big Key 应对
Big Key 指单个 key 存大量数据 (Hash 上百万字段 / List 千万级元素)
├── 问题:阻塞其他命令、内存不均、慢查询
├── 发现:redis-cli --bigkeys 扫描
├── 拆分:Hash → HASH_KEY:{mod(hash_field, 100)}
└── 替代:List → 改用 Stream + 消费组---
3. 持久化
3.1 RDB (Redis Database) — 快照持久化
原理:定时将内存数据生成快照写入磁盘 (dump.rdb)| 配置 | 说明 | 触发条件 |
|---|---|---|
save 900 1 | 900s 内 ≥1 次写 | 自动 |
save 300 10 | 300s 内 ≥10 次写 | 自动 |
save 60 10000 | 60s 内 ≥10000 次写 | 自动 |
BGSAVE | 后台 fork 子进程生成快照 | 手动 |
SAVE | 主进程生成 (阻塞所有请求) | 手动 |
RDB 优势:文件紧凑,恢复快,适合备份和灾难恢复
RDB 劣势:可能丢失最后一次快照后的数据 (最长丢失一个 save 间隔)3.2 AOF (Append Only File) — 日志持久化
原理:记录每次写操作命令,Redis 重启时回放appendfsync 选项 | 持久化策略 | 数据安全 | 性能影响 |
|---|---|---|---|
always | 每条命令 fsync | 最多丢 1 条 | 极低 (频繁磁盘写入) |
everysec | 每秒 fsync | 最多丢 1s 数据 | 低 (推荐) |
no | 操作系统决定 | 不可预测 | 高 |
AOF 重写:BGREWRITEAOF — 压缩 AOF 文件(将多个命令合并为最小集合)。 配置 auto-aof-rewrite-percentage 100 和 auto-aof-rewrite-min-size 64mb 自动触发。
AOF 优势:数据安全性高 (最多丢 1 秒数据),文件易读
AOF 劣势:文件体积比 RDB 大,恢复比 RDB 慢3.3 最佳选择:RDB + AOF 混合
Redis 4.0+ 支持混合持久化 (aof-use-rdb-preamble yes):
- AOF 重写时先生成 RDB 快照写入 AOF 文件头部
- 后续增量写命令以 AOF 格式追加
- 重启恢复:先加载 RDB(快),再回放 AOF 增量(补全)
推荐生产配置:
┌─────────────────────────────────────────────┐
│ appendonly yes │
│ appendfsync everysec │
│ aof-use-rdb-preamble yes │
│ save 900 1 │
│ save 300 10 │
│ save 60 10000 │
└─────────────────────────────────────────────┘3.4 持久化对比总结
| 维度 | RDB | AOF | 混合 (RDB+AOF) |
|---|---|---|---|
| 数据完整性 | 可能丢失多 | 最多丢 1s | 最多丢 1s |
| 恢复速度 | 快 | 慢 | 快 |
| 文件大小 | 小 | 大 (可重写) | 中 |
| 实时性影响 | fork 开销 (内存翻倍) | 磁盘 I/O (可控) | 组合开销 |
---
4. 高可用架构
4.1 主从复制 (Replication)
┌─────────┐ 复制流 ┌──────────┐
│ Master │ ──────────────→ │ Replica │
│ (写+读) │ │ (只读) │
└─────────┘ └──────────┘复制流程:
1. Replica 发送 SLAVEOF master_ip master_port
2. Master BGSAVE 生成 RDB → 发送到 Replica
3. Replica 加载 RDB + 缓存增量命令
4. 后续持续增量复制 (基于环形缓冲区 repl_backlog)
5. 网络断开重连 → 部分重同步 (PSYNC2)核心配置:
# master
replica-read-only no # Master 默认不设置只读
# replica
replicaof 192.168.1.100 6379 # 指定主节点
replica-read-only yes # 从节点只读
replica-priority 100 # Sentinel 选主优先级 (越小越高)复制注意事项:
- 主节点 fork 子进程执行 BGSAVE 时不阻塞读写(但 COW 机制会使内存翻倍)
- 从节点默认只读,可用于读流量分流
- 主节点崩溃后需手动切换从节点或使用 Sentinel
4.2 Sentinel (哨兵) — 自动故障转移
┌─────────────┐
│ Sentinel-1 │
└──────┬──────┘
│ 监控 + 协调
┌────────────┼────────────┐
│ │ │
┌───▼───┐ ┌────▼────┐ ┌───▼───┐
│Master │ │Replica-1│ │Replica-2│
└───────┘ └─────────┘ └─────────┘Sentinel 核心功能:
1. 监控:PING 主从节点,判断是否下线
2. 通知:管理员或程序通过 API 获取状态变化
3. 故障转移:Master 挂了 → 选举新 Master
4. 配置提供:客户端请求获取当前 Master 地址部署要求:最少 3 个 Sentinel 实例(奇数,保证 quorum)。
sentinel.conf 配置:
sentinel monitor mymaster 127.0.0.1 6379 2 # 监控主节点,2 个哨兵同意即判定下线
sentinel down-after-milliseconds mymaster 5000 # 5s 无响应判主观下线
sentinel failover-timeout mymaster 60000 # 故障转移超时
sentinel parallel-syncs mymaster 1 # 新主后同时多少个从同步4.3 Cluster (集群) — 数据分片 + 高可用
┌──────────┐
│ 客户端 │
└────┬─────┘
│ 请求任意节点,MOVED 重定向
┌────────┼──────────────┐
│ │ │
┌───▼───┐ ┌──▼───┐ ┌───▼───┐
│Node 1 │ │Node 2 │... │Node N │
│ 0-5460 │ │5461-10922 │ │10923-16383│
│+Slave │ │+Slave │ │+Slave │
└────────┘ └───────┘ └───────┘核心概念:
- 16384 个 hash slot:
CRC16(key) % 16384 - 每个节点负责一段 slot 区间
- 节点间 gossip 协议通信(PONG/PING)
- 自动主从切换:主节点挂了,从节点晋升
集群搭建要点:
# 配置文件:(每个节点必须有集群模式)
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000
# 创建集群 (Redis 5+)
redis-cli --cluster create 192.168.1.100:6379 192.168.1.101:6379 \
192.168.1.102:6379 192.168.1.103:6379 192.168.1.104:6379 192.168.1.105:6379 \
--cluster-replicas 1
# 常用操作
redis-cli --cluster check 192.168.1.100:6379 # 检查集群状态
redis-cli --cluster info 192.168.1.100:6379 # 集群信息
redis-cli --cluster rebalance 192.168.1.100:6379 # 重新平衡 slot
redis-cli --cluster add-node 新节点ip:port 已有节点ip:port --cluster-slave集群限制:
- 只支持 0 号数据库(SELECT 0)
- 批量操作(MGET/MSET)的 key 必须在同一 slot(使用 hash tag
{user:1001}) - 事务/Lua 脚本的 key 必须在同一节点(同一 slot)
- 不支持多 key 操作在跨 slot 场景
4.4 架构选型决策树
数据量 < 单个节点内存 (≤16GB) ?
├── YES → 是否需要自动故障转移?
│ ├── NO → 单机 + RDB/AOF
│ └── YES → 读写分离需要?
│ ├── NO → 主从 + Sentinel (3实例)
│ └── YES → 主从 + Sentinel (读写分离)
│
└── NO → 数据量预期增长?
├── NO → 升级单机内存 (垂直扩展)
└── YES → Cluster 集群 (水平扩展)
├── 三主三从 (最小生产配置)
├── 六主六从 (中等规模)
└── 九主九从 (大规模)---
5. Lua 脚本与事务
5.1 事务 (Transaction)
MULTI -- 开始事务
SET key1 "value1" -- 命令入队 (QUEUED)
SET key2 "value2" -- 命令入队
EXEC -- 按顺序执行所有命令
# WATCH — 乐观锁 (CAS 模式)
WATCH stock:100 -- 监视 key
count = GET stock:100 -- 读取当前值
MULTI
SET stock:100 (count - 1) -- 如果期间 stock:100 被修改 → EXEC 返回 nil
EXEC
UNWATCH -- 取消监视事务 vs Pipeline 对比:
| 特性 | MULTI/EXEC (事务) | Pipeline (管道) |
|---|---|---|
| 原子性 | ✅ 全部/全部不执行 | ❌ 不保证 |
| 阻塞等待结果 | ✅ 是 | ✅ 是 |
| 中间可读结果 | ❌ 仅入队不可读 | ✅ 可读 |
| 错误处理 | 语法错全部失败/运行时错其他继续 | 每命令独立 |
| 适用场景 | 需要 "all or nothing" | 批量操作提升性能 |
5.2 Lua 脚本
Redis 2.6+ 内置 Lua 5.1 解释器,脚本在服务器端原子执行。
-- 原子扣减库存脚本
-- EVAL script 1 key arg
-- KEYS[1] = stock:100
-- ARGV[1] = 1 (扣减数量)
local stock = redis.call("GET", KEYS[1])
if not stock or tonumber(stock) < tonumber(ARGV[1]) then
return -1 -- 库存不足
end
redis.call("DECRBY", KEYS[1], ARGV[1])
return redis.call("GET", KEYS[1])
-- 调用方式: EVAL "上述脚本" 1 stock:100 1
-- 缓存: SCRIPT LOAD "script" → SHA → EVALSHA SHA 1 stock:100 1Lua 脚本最佳实践:
- 脚本应短小精悍(控制在 100 行内),长脚本会阻塞其他请求
- 使用
SCRIPT LOAD+EVALSHA减少网络传输 - 脚本中所有 key 必须使用 KEYS 数组传入,不能用硬编码
- 脚本不要访问不同节点的 key(Cluster 场景)
- 使用
redis.log(redis.LOG_WARNING, msg)调试
5.3 CAS (乐观锁) 模式
-- 更安全的库存扣减:数值检查 + 原子操作
local key = KEYS[1]
local expected = tonumber(ARGV[1])
local new_value = tonumber(ARGV[2])
local current = redis.call("GET", key)
if tonumber(current) ~= expected then
return -1 -- 已被其他客户端修改
end
return redis.call("SET", key, new_value)---
6. 性能优化与运维
6.1 内存淘汰策略 (maxmemory-policy)
| 策略 | 说明 | 适用场景 |
|---|---|---|
noeviction | 不淘汰,写操作返回错误 | 数据库模式 (禁止丢数据) |
allkeys-lru | 全 key 最近最少使用 | 通用缓存 (推荐) |
allkeys-lfu | 全 key 最不经常使用 (Redis 4.0+) | 访问频率差异大的缓存 |
volatile-lru | 有过期时间的 key LRU | 部分持久化、部分缓存 |
volatile-ttl | 淘汰 TTL 最短的 key | 特定场景 |
volatile-random | 随机淘汰有过期时间的 key | 不太推荐 |
redis-cli CONFIG SET maxmemory 4gb # 设置最大内存
redis-cli CONFIG SET maxmemory-policy allkeys-lru # LRU 淘汰6.2 Big Key 与 Hot Key
Big Key 检测:
# 扫描大 key (阻塞,建议低峰期执行)
redis-cli --bigkeys
# 用 MEMORY USAGE 精确查看内存占用
redis-cli MEMORY USAGE mykey
# 用 DEBUG 命令 (Redis 4.0+)
redis-cli MEMORY DOCTORBig Key 拆分策略:
场景 1: Hash 包含上百万字段
→ 拆分: HASH_KEY:{hash(field) % 100} = {field: value}
场景 2: List 包含千万级元素
→ 替换为 Stream (支持消费组)
场景 3: ZSet 大排行榜
→ 分桶: ranking:2024-01, ranking:2024-02...
场景 4: String 存储大 JSON (>10MB)
→ 压缩存储: Snappy/LZ4 压缩后存,读取解压Hot Key 应对:
问题:单个 key QPS 极高 (如 10万+/秒)
解决:
├── 本地缓存 (Local Cache): 二级缓存 (如 Caffeine)
├── 读写分离: 从节点分担读流量
├── 热点拆分: hotkey:{random(0,10)} = value (分片读取)
└── 代理层: Redis Proxy (如 Twemproxy/RedisShake)6.3 慢查询日志
CONFIG SET slowlog-log-slower-than 10000 # 记录 >10ms 的命令
CONFIG SET slowlog-max-len 128 # 最多保留 128 条记录
SLOWLOG GET 10 # 获取前 10 条慢查询
SLOWLOG LEN # 慢查询总数
SLOWLOG RESET # 清空慢查询6.4 性能基准与优化
# 基准测试
redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 100000 -q
redis-benchmark -t set,get,incr,lpush -q # 指定命令测试
redis-benchmark -P 10 -q # Pipeline 模式
# 预期性能 (单实例):
# GET/SET: 10万+ QPS (无持久化)
# Pipeline 100条: 100万+ QPS
# Lua 脚本: 5-15万 次/秒关键优化参数:
tcp-backlog 511 # TCP 连接队列
timeout 300 # 客户端空闲超时
tcp-keepalive 300 # TCP keepalive
lfu-log-factor 10 # LFU 计数器对数因子 (Redis 4.0+)
lfu-decay-time 1 # LFU 衰减时间
hz 10 # 后台任务频率 (可增加到 100)6.5 安全加固
# 基础安全
requirepass your_strong_password # 设置密码
RENAME_COMMAND FLUSHALL "" # 禁用危险命令
RENAME_COMMAND FLUSHDB ""
RENAME_COMMAND CONFIG ""
RENAME_COMMAND SHUTDOWN ""
# 网络安全
bind 127.0.0.1 192.168.1.100 # 绑定内网 IP
protected-mode yes # 保护模式
port 6379 # 修改默认端口
# 连接限制
maxclients 10000 # 最大连接数
client-output-buffer-limit normal 0 0 0 # 客户端输出缓冲区限制
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
# ACL (Redis 6.0+)
ACL SETUSER alice on >password ~cached:* +get +set -admin
ACL SETUSER bob on >password ~* +@all -@dangerous---
7. Redis 生态与客户端连接
7.1 客户端配置
// Java (Jedis 连接池)
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(100); // 最大连接数
config.setMaxIdle(50); // 最大空闲
config.setMinIdle(10); // 最小空闲
config.setTestOnBorrow(true); // 获取时校验
config.setTestOnReturn(true); // 返回时校验
config.setMaxWaitMillis(3000); // 获取连接超时
// Java (Lettuce — 推荐,支持异步/响应式)
RedisClient client = RedisClient.create("redis://password@host:6379/0");
StatefulRedisConnection<String, String> conn = client.connect();
RedisCommands<String, String> sync = conn.sync();
RedisAsyncCommands<String, String> async = conn.async();7.2 常用 Redis 监控命令
# 实时监控
redis-cli -a password MONITOR # 实时打印所有命令 (生产慎用)
redis-cli -a password INFO # 全面状态信息
redis-cli -a password INFO STATS # 统计信息
redis-cli -a password INFO MEMORY # 内存信息
redis-cli -a password INFO CLIENTS # 客户端信息
# 连接数监控
redis-cli CLIENT LIST | wc -l # 当前连接数
redis-cli INFO connected_clients # 连接数
# 内存监控
redis-cli INFO used_memory_human # 已用内存
redis-cli INFO used_memory_peak_human # 峰值内存
redis-cli INFO mem_fragmentation_ratio # 内存碎片率 (>1.5 需重启)7.3 Redis Stack 扩展
Redis Stack (Redis 6.2+) 集成了以下模块:
- RediSearch:全文搜索、索引、向量搜索
- RedisJSON:原生 JSON 数据类型支持
- RedisTimeSeries:时间序列数据类型
- RedisBloom:布隆过滤器、Cuckoo Filter
---
Gotchas — 常见陷阱与反模式 (Common Gotchas & Anti-Patterns)
| # | 问题 | 风险 | 解决方案 |
|---|
| # | 反模式 | 问题 | 正确做法 |
|---|---|---|---|
| 1 | 用 KEYS 在生产环境搜索 | O(n) 扫描全库,阻塞 Redis 数秒 | 用 SCAN 游标迭代 |
| 2 | 大集合上用 SMEMBERS/HGETALL | 百万级元素 JSON 序列化,内存爆炸 | 用 SSCAN/HSCAN 分批或拆分 key |
| 3 | 不使用连接池 | 每个请求创建连接,耗尽系统资源 | 使用 JedisPool/Lettuce 连接池 |
| 4 | 所有 key 不设过期时间 | 内存无限增长,触达 maxmemory | 根据场景设置合适的 TTL |
| 5 | 单机当数据库永久存储 | 无高可用,宕机丢失数据 | 主从+Sentinel 或 Cluster |
| 6 | 使用 SELECT 切分数据库 | 不便于管理监控,Cluster 不支持 | 用不同 key 前缀或不同 Redis 实例 |
| 7 | 生成超长 key 名 | 浪费内存 (key 本身也是存储) | key 名控制在合理长度 (32-64 字符) |
| 8 | 用 Redis 存大文件/二进制 | 撑爆单 key 512MB 限制,性能差 | 存文件路径 + 对象存储 |
| 9 | Pipeline 无限攒批 | 客户端缓冲区 OOM | Pipeline 批量大小控制在 100-500 |
| 10 | 不区分业务用同一个实例 | 互相影响,难以隔离 | 按业务拆分实例 + 限制内存/连接 |
---
9. FAQ
Q1: Redis 为什么不建议用作主数据库? Redis 内存昂贵,虽支持持久化但最多丢 1 秒数据,且不支持 SQL 查询和复杂约束。典型架构是 Redis 作为加速层在前,关系型数据库做持久化存储在后。
Q2: Redis 内存满后会发生什么? 取决于 maxmemory-policy。推荐 allkeys-lru,淘汰最近最少使用的 key。如果设为 noeviction,写操作返回 OOM 错误。
Q3: RDB 和 AOF 同时开启时,启动加载顺序? 先加载 AOF(数据更完整),AOF 不存在再加载 RDB。混合持久化时 AOF 文件头部是 RDB 快照,先加载 RDB(快),再回放 AOF 增量。
Q4: 如何选择 Stream 还是 Pub/Sub?
| 对比 | Pub/Sub | Stream |
|---|---|---|
| 消息持久化 | ❌ 不持久,离线丢失 | ✅ 持久化到内存/磁盘 |
| 消费确认 | ❌ 无 ACK | ✅ XACK 确认 |
| 消费组 | ❌ 不支持 | ✅ XGROUP 消费组 |
| 消息回溯 | ❌ 不可回溯 | ✅ XRANGE 可回放 |
| 适用场景 | 实时广播通知 | 可靠消息队列/事件溯源 |
Q5: Cluster 模式下还能用事务/Lua 吗? 可以使用,但所有操作的 key 必须在同一节点。使用 hash tag {tag} 确保相关 key 路由到同一 slot。跨 slot 的事务无法执行。
Q6: Big Key 为什么危险? 一个 Big Key 导致:Redis 变慢(命令 O(n) 阻塞)、集群数据分布不均、持久化时间变长、主从同步延迟大。使用 --bigkeys 定期扫描。
Q7: Redis 线程模型是什么样的? Redis 是单线程处理命令(6.0+ 网络 I/O 处理多线程)。单线程避免了锁竞争,但一个慢查询会阻塞所有后续请求。所以 Lua 脚本必须短小,KEYS 不能在 O(n) 命令上操作大集合。
Q8: 什么情况下用 Redis 6.0+ 的 ACL? 多租户场景、团队共用 Redis 实例时,用 ACL 控制权限可防止误操作。例如:业务线 A 只能操作 a:*,不能使用 FLUSHALL。
Q9: 如何在不重启的情况下修改配置? CONFIG SET 动态修改运行期配置,CONFIG REWRITE 写入 redis.conf 使其重启后生效。
Q10: Redis 内存碎片率高怎么处理? mem_fragmentation_ratio > 1.5 说明碎片严重。Redis 4.0+ 可用 MEMORY PURGE 命令触发碎片整理,或设置 activedefrag yes 自动整理。
---
Keywords
redis, redis-cli, 缓存, string, hash, list, set, zset, sorted set, bitmap, hyperloglog, stream, geo, lua, 事务, pipeline, 持久化, RDB, AOF, 混合持久化, 主从复制, sentinel, 哨兵, cluster, 集群, 缓存穿透, 缓存击穿, 缓存雪崩, 分布式锁, 内存淘汰, LRU, LFU, big key, hot key, 慢查询, 性能优化, 安全加固, ACL, Redisson, Jedis, Lettuce, bigkey, hotkey, slot, hash tag, RediSearch, RedisJSON, Redis Stack, 数据淘汰
---
References
Redis 缓存使用示例
1. Cache-Aside 模式 (Java + Spring Boot)
@Service
public class UserService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private UserMapper userMapper;
public User getUserById(Long id) {
String key = "user:" + id;
// 1. 尝试从缓存获取
User user = (User) redisTemplate.opsForValue().get(key);
if (user != null) {
return user;
}
// 2. 缓存未命中,查数据库
user = userMapper.selectById(id);
if (user != null) {
// 3. 写入缓存,设置 TTL
redisTemplate.opsForValue().set(key, user, 1, TimeUnit.HOURS);
}
return user;
}
public void updateUser(User user) {
// 1. 更新数据库
userMapper.updateById(user);
// 2. 删除缓存 (下次读取时重建)
redisTemplate.delete("user:" + user.getId());
}
}2. 分布式锁 (Python + redis-py)
import redis
import uuid
import time
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
def acquire_lock(lock_name, acquire_timeout=10, lock_timeout=30):
"""获取分布式锁"""
identifier = str(uuid.uuid4())
lock_key = f"lock:{lock_name}"
end = time.time() + acquire_timeout
while time.time() < end:
if r.set(lock_key, identifier, nx=True, ex=lock_timeout):
return identifier # 成功获取锁
time.sleep(0.01) # 短暂休眠后重试
return None # 超时未获取
def release_lock(lock_name, identifier):
"""释放分布式锁 (Lua 脚本保证原子性)"""
lock_key = f"lock:{lock_name}"
lua_script = """
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
"""
return r.eval(lua_script, 1, lock_key, identifier)
# 使用示例
lock_id = acquire_lock("order:1001")
if lock_id:
try:
print("处理订单 1001...")
# 执行业务逻辑
finally:
release_lock("order:1001", lock_id)3. 限流器 (Node.js)
const Redis = require('ioredis');
const redis = new Redis();
async function rateLimit(ip, limit = 100, window = 60) {
const key = `ratelimit:${ip}`;
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, window);
}
return current <= limit;
}
// 使用: 每个 IP 每分钟最多 100 次请求
app.use(async (req, res, next) => {
const allowed = await rateLimit(req.ip);
if (!allowed) {
return res.status(429).json({ error: '请求过于频繁' });
}
next();
});Redis Session 存储示例
1. Spring Session + Redis
<!-- pom.xml 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency># application.yml
spring:
session:
store-type: redis
timeout: 1800 # Session 过期时间 (秒)
redis:
host: localhost
port: 6379
password: your_password
timeout: 2000ms
lettuce:
pool:
max-active: 50
max-idle: 20
min-idle: 5@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class RedisSessionConfig {
// 自动生效,无需额外代码
}2. Flask Session (Python)
from flask import Flask, session
from flask_session import Session
import redis
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.from_url('redis://localhost:6379/0')
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_KEY_PREFIX'] = 'session:'
app.config['SESSION_PERMANENT_TIMEOUT'] = 1800
Session(app)
@app.route('/login')
def login():
session['user_id'] = 1001
session['role'] = 'admin'
return 'Session stored in Redis'
@app.route('/profile')
def profile():
user_id = session.get('user_id')
role = session.get('role')
return f'User {user_id} with role {role}'Redis ZSet 排行榜示例
游戏排行榜 (Go)
package redis
import (
"context"
"github.com/redis/go-redis/v9"
)
type Leaderboard struct {
rdb *redis.Client
key string
}
func NewLeaderboard(rdb *redis.Client, gameID string) *Leaderboard {
return &Leaderboard{rdb: rdb, key: "leaderboard:" + gameID}
}
// AddScore 增加玩家分数 (原子操作)
func (lb *Leaderboard) AddScore(ctx context.Context, player string, score float64) error {
return lb.rdb.ZIncrBy(ctx, lb.key, score, player).Err()
}
// GetTopN 获取前 N 名
func (lb *Leaderboard) GetTopN(ctx context.Context, n int64) ([]redis.Z, error) {
return lb.rdb.ZRevRangeWithScores(ctx, lb.key, 0, n-1).Result()
}
// GetRank 获取玩家排名 (从 0 开始)
func (lb *Leaderboard) GetRank(ctx context.Context, player string) (int64, error) {
rank, err := lb.rdb.ZRevRank(ctx, lb.key, player).Result()
if err != nil {
return -1, err
}
return rank + 1, nil // 转为 1-based
}
// GetScore 获取玩家分数
func (lb *Leaderboard) GetScore(ctx context.Context, player string) (float64, error) {
return lb.rdb.ZScore(ctx, lb.key, player).Result()
}周榜 + 日榜 + 总榜设计
# 命名规范
leaderboard:total # 总榜 (长周期)
leaderboard:2024:W01 # 周榜
leaderboard:2024:01:15 # 日榜
# 每日零点:创建新日榜
# 每周一零点:创建新周榜
# 合并多期分数 (ZUNIONSTORE)
ZUNIONSTORE leaderboard:month 3
leaderboard:2024:01:01 leaderboard:2024:01:02 leaderboard:2024:01:03
WEIGHTS 1 1 1
AGGREGATE SUMRedis Cluster 搭建与运维示例
1. 最小生产集群 (3主3从)
# 6 个节点目录
mkdir -p /data/redis/{7000,7001,7002,7003,7004,7005}
# 每个节点 redis.conf
cat > /data/redis/7000/redis.conf << 'EOF'
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
protected-mode no
bind 0.0.0.0
daemonize yes
logfile /var/log/redis/7000.log
EOF
# 启动 6 个节点
redis-server /data/redis/7000/redis.conf
redis-server /data/redis/7001/redis.conf
redis-server /data/redis/7002/redis.conf
redis-server /data/redis/7003/redis.conf
redis-server /data/redis/7004/redis.conf
redis-server /data/redis/7005/redis.conf
# 创建集群 (Redis 5+)
redis-cli --cluster create \
192.168.1.100:7000 192.168.1.100:7001 192.168.1.100:7002 \
192.168.1.100:7003 192.168.1.100:7004 192.168.1.100:7005 \
--cluster-replicas 12. 集群运维命令
# 检查集群状态
redis-cli -c -h 192.168.1.100 -p 7000 cluster info
redis-cli -c -h 192.168.1.100 -p 7000 cluster nodes
# 重新平衡 slot
redis-cli --cluster rebalance 192.168.1.100:7000 \
--cluster-weight node1=1 node2=2 node3=1 \
--cluster-use-empty-masters
# 修复集群
redis-cli --cluster fix 192.168.1.100:7000
# 动态扩容:添加节点
redis-cli --cluster add-node 新节点:7006 已有节点:7000 --cluster-slave
redis-cli --cluster reshard 已有节点:7000 --cluster-from all \
--cluster-to 新节点id --cluster-slots 1000 --cluster-yes3. 数据迁移方案
# 使用 redis-shake 跨集群迁移
redis-shake.linux -type sync -conf redis-shake.conf
# redis-shake.conf 示例
source.type = cluster
source.address = 192.168.1.100:7000
target.type = cluster
target.address = 192.168.1.200:7000Redis Stream 消息队列示例
1. 生产-消费模式
# 生产者: 发送消息
XADD orders * order_id 1001 user_id 42 amount 99.99 status pending
XADD orders * order_id 1002 user_id 55 amount 199.00 status pending
# 消费者: 读取消息 (非阻塞)
XRANGE orders - + COUNT 10
# 消费者: 阻塞读取新消息
XREAD COUNT 1 BLOCK 5000 STREAMS orders $
# 消息长度
XLEN orders
# 删除消息
XDEL orders 1700000000000-0
# 修剪 (保留最近的 1000 条)
XTRIM orders MAXLEN ~ 10002. 消费组模式
# 创建消费组 (从最新消息开始消费)
XGROUP CREATE orders payment-group $ MKSTREAM
XGROUP CREATE orders inventory-group $
XGROUP CREATE orders notification-group $
# 消费组成员: 读取未确认消息
# payment-service
XREADGROUP GROUP payment-group worker-1 COUNT 1 BLOCK 2000 STREAMS orders >
# inventory-service
XREADGROUP GROUP inventory-group worker-1 COUNT 1 BLOCK 2000 STREAMS orders >
# notification-service
XREADGROUP GROUP notification-group worker-1 COUNT 1 BLOCK 2000 STREAMS orders >
# 确认消费 (ACK)
XACK orders payment-group 1700000000000-0
# 查看待确认消息
XPENDING orders payment-group
# 查看消费组信息
XINFO GROUPS orders
XINFO CONSUMERS orders payment-group3. CAP 对比: Stream vs Kafka
| 特性 | Redis Stream | Apache Kafka |
|---|---|---|
| 延迟 | <1ms | <10ms |
| 消息持久化 | RDB/AOF | 磁盘日志 |
| 消息回溯 | 支持 | 支持 |
| 消费组 | 支持 | 支持 |
| 分区顺序 | 单分区有序 | 单分区有序 |
| 数据保留 | 内存+磁盘 (可控) | 磁盘 (可配置) |
| 吞吐量 | 10万+/s | 百万+/s |
| 运维复杂度 | 低 (Redis 原生) | 高 (需 ZK) |
| 适用场景 | 微服务异步、任务队列 | 大数据流、日志采集 |
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Redis 命令速查
操作分类速查
内存操作: SET / GET / DEL / EXISTS / TYPE / TTL / EXPIRE / PERSIST
计数器: INCR / DECR / INCRBY / INCRBYFLOAT
散列: HSET / HGET / HGETALL / HDEL / HEXISTS / HINCRBY
列表: LPUSH / RPUSH / LPOP / RPOP / LRANGE / LLEN / LTRIM / BLPOP
集合: SADD / SREM / SMEMBERS / SISMEMBER / SCARD / SINTER / SUNION
有序集合: ZADD / ZREM / ZRANGE / ZRANK / ZSCORE / ZINCRBY / ZINTERSTORE
位图: SETBIT / GETBIT / BITCOUNT / BITOP
地理: GEOADD / GEOPOS / GEODIST / GEORADIUS
流: XADD / XREAD / XREADGROUP / XACK / XRANGE / XLEN / XTRIM
超日志: PFADD / PFCOUNT / PFMERGE
事务: MULTI / EXEC / WATCH / DISCARD
脚本: EVAL / EVALSHA / SCRIPT LOAD / SCRIPT KILL
连接: PING / AUTH / SELECT / CLIENT LIST / CLIENT KILL
服务器: INFO / CONFIG GET/SET / SLOWLOG / MONITOR / DBSIZE / FLUSHALL
发布订阅: PUBLISH / SUBSCRIBE / PSUBSCRIBE / PUBSUB字符串命令速查
SET key value [EX|PX] [NX|XX] # 设置值,支持过期和条件
GET key # 返回字符串值或 nil
MGET key1 key2 # 批量获取
MSET k1 v1 k2 v2 # 批量设置
INCR key # 整数 +1 (原子)
INCRBY key n # 整数 +n
DECR key # 整数 -1
DECRBY key n # 整数 -n
APPEND key value # 追加到末尾
GETRANGE key start end # 获取子串
SETRANGE key offset value # 从 offset 覆写
STRLEN key # 获取长度
GETSET key new_value # 返回旧值设新值
SETEX key sec value # 设置+过期
SETNX key value # 不存在才设置哈希命令速查
HSET key field value # 设置字段
HSETNX key field value # 不存在才设置
HGET key field # 获取字段
HGETALL key # 获取所有 (慎用)
HMGET key f1 f2 # 批量获取
HMSET key f1 v1 f2 v2 # 批量设置
HDEL key field # 删除字段
HEXISTS key field # 判断存在
HLEN key # 字段数量
HKEYS key # 所有字段名
HVALS key # 所有字段值
HINCRBY key field n # 字段值 +n
HINCRBYFLOAT key field n # 浮点增加列表命令速查
LPUSH key v1 v2 # 左推
RPUSH key v1 v2 # 右推
LPOP key # 左弹
RPOP key # 右弹
LRANGE key start stop # 范围获取
LINDEX key index # 索引获取
LLEN key # 长度
LREM key count value # 移除元素
LTRIM key start stop # 修剪
LSET key index value # 设置索引值
BLPOP key timeout # 阻塞左弹
BRPOP key timeout # 阻塞右弹
RPOPLPUSH src dst # 转存
BRPOPLPUSH src dst timeout # 阻塞转存集合命令速查
SADD key m1 m2 # 添加
SREM key m1 # 移除
SMEMBERS key # 所有成员
SISMEMBER key m # 是否在集合中
SCARD key # 数量
SPOP key # 随机弹出
SRANDMEMBER key count # 随机取样
SINTER k1 k2 # 交集
SUNION k1 k2 # 并集
SDIFF k1 k2 # 差集
SINTERSTORE dest k1 k2 # 交集存
SUNIONSTORE dest k1 k2 # 并集存
SDIFFSTORE dest k1 k2 # 差集存
SSCAN key cursor # 渐进迭代有序集合命令速查
ZADD key score member # 添加
ZREM key member # 移除
ZRANGE key start stop [WITHSCORES] # 按排名取 (小到大)
ZREVRANGE key start stop [WS] # 按排名取 (大到小)
ZRANGEBYSCORE key min max # 按分数取
ZRANK key member # 排名 (小到大)
ZREVRANK key member # 排名 (大到小)
ZSCORE key member # 分数
ZCARD key # 数量
ZINCRBY key n member # 分数 +n
ZCOUNT key min max # 分数区间内数量
ZREM key member # 移除
ZREMRANGEBYRANK key start stop # 移除排名区间
ZREMRANGEBYSCORE key min max # 移除分数区间
ZINTERSTORE dest n keys [WEIGHTS] # 交集
ZUNIONSTORE dest n keys [WEIGHTS] # 并集
ZSCAN key cursor # 渐进迭代发布订阅命令速查
SUBSCRIBE channel # 订阅
UNSUBSCRIBE channel # 退订
PUBLISH channel message # 发布
PSUBSCRIBE pattern # 模式订阅
PUNSUBSCRIBE pattern # 模式退订
PUBSUB channels # 查看活跃频道
PUBSUB numsub channel # 查看频道订阅数脚本命令速查
EVAL script numkeys key [key] arg [arg] # 执行 Lua
EVALSHA sha1 numkeys key [key] arg [arg] # 通过 SHA1 执行缓存脚本
SCRIPT LOAD script # 加载脚本到缓存
SCRIPT EXISTS sha1 # 检查脚本是否在缓存
SCRIPT FLUSH # 清除脚本缓存
SCRIPT KILL # 终止正在运行的脚本连接命令速查
PING # 检查是否 alive
ECHO message # 回显
AUTH password # 认证
SELECT index # 选择数据库
QUIT # 关闭连接服务器命令速查
INFO [section] # 服务器信息
CONFIG GET parameter # 获取配置
CONFIG SET parameter value # 修改配置 (运行时)
CONFIG REWRITE # 写入配置文件
DBSIZE # 当前数据库 key 数量
FLUSHDB # 清空当前库
FLUSHALL # 清空所有库
CLIENT LIST # 客户端列表
CLIENT KILL ip:port # 杀死客户端连接
SLOWLOG GET n # 获取慢查询日志
MONITOR # 实时监控 (生产慎用)
SAVE # 同步保存 RDB
BGSAVE # 后台保存 RDB
BGREWRITEAOF # 重写 AOF
LASTSAVE # 最后保存时间
SHUTDOWN # 关闭服务器
SLAVEOF host port # 设置主从
ROLE # 查看角色
TIME # 服务器时间
DEBUG OBJECT key # key 调试信息
MEMORY USAGE key # 精确内存
MEMORY PURGE # 整理碎片
COMMAND # 命令统计Redis 命令详解 — Key / 事务 / Lua / PubSub / 连接 / 服务器
内容源自 doc.redisfans.com 完整翻译版 (Redis 2.8+),每个命令包含简介、参数说明、业务场景。
---
1. Key(键)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| DEL | O(N) | ≥1.0.0 | 删除 key |
| EXISTS | O(1) | ≥1.0.0 | 检查存在 |
| EXPIRE | O(1) | ≥1.0.0 | 设置 TTL |
| TTL | O(1) | ≥1.0.0 | 查看 TTL |
| TYPE | O(1) | ≥1.0.0 | 返回类型 |
| KEYS | O(N) | ≥1.0.0 | 查找 key |
| SCAN | O(1)/cursor | ≥2.8.0 | 渐进遍历 |
DEL
DEL key [key ...]
删除一个或多个 key。不支持通配符(请使用 SCAN + DEL)。
- 时间复杂度 O(N):N 为删除的 key 数量,复杂类型(List/Set/ZSet/Hash)删除时间与元素数量相关
业务场景:
- 清理缓存
DEL cache:user:42 cache:user:43 cache:user:44 - 重置数据
DEL user:1001:session
返回值:被删除 key 的数量
---
EXISTS
EXISTS key [key ...] (Redis 3.0.3+ 支持多 key)
检查 key 是否存在。多 key 版本返回存在的 key 数。
业务场景:
- 缓存命中判断
EXISTS cache:hot:article:42→ 1 命中 - 批量校验
EXISTS key1 key2 key3→ 快速判断多个 key 全部存在
---
EXPIRE / PEXPIRE
EXPIRE key seconds PEXPIRE key milliseconds
设置 key 的生存时间(秒/毫秒),到期后自动删除(易失性)。
- TTL 不会被只读/修改命令(INCR/LPUSH/HSET)改变
- RENAME 后新 key 继承 TTL
- SET/GETSET 会清除原有 TTL
业务场景:
# 导航会话(60 秒无操作清空)
MULTI
RPUSH navig:user:42 "page_3"
EXPIRE navig:user:42 60
EXEC---
EXPIREAT / PEXPIREAT
EXPIREAT key timestamp PEXPIREAT key milliseconds-timestamp
设置 key 在指定 Unix 时间戳过期。精确到秒/毫秒。
业务场景:
- 优惠券到期:
EXPIREAT coupon:user:42 1893456000(2030-01-01 00:00) - 定时删除:配合 cron 计算到期时间戳
---
TTL / PTTL
TTL key — 返回剩余生存时间(秒),-1 无过期,-2 key 不存在 PTTL key — 返回毫秒数
业务场景:
- 热键 TTL 监控(防止缓存穿透)
- 动态延长热点数据 TTL:TTL < 30 时 EXPIRE 续期
---
PERSIST
PERSIST key — 移除 key 的过期时间,使其持久保留
业务场景:将热点 key 从"定时过期"转为"永久缓存"
---
TYPE
TYPE key — 返回 key 的数据类型:string / list / set / zset / hash / stream / none
业务场景:键值类型校验,防止对集合类型执行字符串操作
---
KEYS
KEYS pattern — 查找所有匹配 pattern 的 key
- 支持 glob 风格:
*?[a-z] - O(N) 阻塞操作,生产环境严禁使用
正确做法:使用 SCAN 0 MATCH user:* COUNT 100
---
SCAN
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
渐进式迭代数据库中的 key。每次返回游标 + 一批 key。
- cursor = 0 开始迭代,cursor = 0 结束
- COUNT 提示每次返回数量(不保证精确)
- TYPE 过滤类型 (Redis 6.0+)
业务场景:
SCAN 0 MATCH user:* COUNT 100 # 迭代查找 user: 开头的 key
SCAN 0 TYPE hash COUNT 100 # 只找 hash 类型的 key---
RENAME / RENAMENX
RENAME key newkey — 改名(newkey 存在则覆盖) RENAMENX key newkey — 改名(仅 newkey 不存在时)
业务场景:数据迁移、key 命名变更、A/B 测试流量切换
---
MOVE
MOVE key db — 将当前数据库的 key 移到指定数据库
注意:Cluster 模式只支持 0 号数据库,MOVE 无法使用。
---
RANDOMKEY
RANDOMKEY — 从当前数据库中随机返回一个 key
业务场景:数据采样、缓存预热随机检查
---
DUMP / RESTORE
DUMP key — 序列化 key 并返回(含 TTL 信息) RESTORE key ttl serialized-value [REPLACE] [ABSTTL] [IDLETIME t] [FREQ f]
业务场景:
- 迁移单个 key:源 DUMP → 目标 RESTORE
- 备份恢复:对单个 key 做序列化备份
---
OBJECT
OBJECT subcommand [arguments [arguments]]
OBJECT REFCOUNT key— 引用计数OBJECT ENCODING key— 底层编码(raw/embstr/ziplist/dict/intset/skiplist)OBJECT IDLETIME key— 空闲时间(LRU 相关)
业务场景:
OBJECT ENCODING user:1001 → "hashtable" 或 "ziplist"
OBJECT IDLETIME hot_data → 判断是否为闲置 key---
SORT
SORT key [BY pattern] [LIMIT offset count] [GET pattern] [ASC|DESC] [ALPHA] [STORE destination]
对 List、Set、ZSet 中的元素排序(支持外部 key BY/GET,可能阻塞)。
Redis 6.2.0+ 弃用 SORT,推荐使用 SORT_RO(只读版)。
---
2. 事务(Transaction)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| MULTI | O(1) | ≥1.2.0 | 开始事务 |
| EXEC | 取决于命令 | ≥1.2.0 | 执行 |
| DISCARD | O(1) | ≥2.0.0 | 取消 |
| WATCH | O(1) | ≥2.0.0 | 乐观锁 |
MULTI / EXEC / DISCARD
MULTI — 标记事务块开始(后续命令入队) EXEC — 顺序执行队列中所有命令 DISCARD — 取消事务,清空命令队列
事务特性:
- 原子性:EXEC 时要么全部执行,要么因语法错误全部不执行
- 无回滚:运行时错误(如对 string 执行 LIST 操作)不影响其他命令
- 隔离性:EXEC 前其他客户端不会看到中间状态
业务场景:
# 转账(原子扣减 + 增加)
MULTI
DECRBY account:42 1000
INCRBY account:100 1000
EXEC---
WATCH / UNWATCH
WATCH key [key ...] — 乐观锁(CAS) UNWATCH — 取消所有 WATCH
业务场景:
# 库存扣减(CAS 保证)
WATCH stock:item:1001
count = GET stock:item:1001
if count > 0:
MULTI
DECRBY stock:item:1001 1
EXEC # 如果 stock:item:1001 在此期间被修改 → EXEC 返回 nil
else:
UNWATCH # 放弃监视---
3. Lua 脚本命令
| 命令 | 可用版本 | 说明 |
|---|---|---|
| EVAL | ≥2.6.0 | 执行脚本 |
| EVALSHA | ≥2.6.0 | 执行缓存脚本 |
| SCRIPT LOAD | ≥2.6.0 | 加载到缓存 |
| SCRIPT EXISTS | ≥2.6.0 | 检查缓存 |
| SCRIPT FLUSH | ≥2.6.0 | 清理缓存 |
| SCRIPT KILL | ≥2.6.0 | 终止运行 |
EVAL
EVAL script numkeys key [key ...] arg [arg ...]
在服务器端执行 Lua 脚本。脚本在 Redis 内原子执行。
关键规则:
- 所有 key 通过 KEYS 数组传入(Cluster 兼容)
- 所有参数通过 ARGV 数组传入
- 脚本应短小精悍(Lua 脚本执行时阻塞其他所有请求)
业务场景:原子取余分配
-- 一致性哈希槽分配
local slot = redis.call("HGET", KEYS[1], ARGV[1])
if not slot then
slot = redis.call("HLEN", KEYS[1]) % tonumber(ARGV[2])
redis.call("HSET", KEYS[1], ARGV[1], slot)
end
return slot业务场景:原子限流
-- 滑动窗口限流
local key = KEYS[1]
local now = redis.call("TIME")[1]
local window = tonumber(ARGV[1])
local limit = tonumber(ARGV[2])
redis.call("ZREMRANGEBYSCORE", key, 0, now - window)
local count = redis.call("ZCARD", key)
if count < limit then
redis.call("ZADD", key, now, now .. ":" .. math.random())
redis.call("EXPIRE", key, window)
return 1 -- 允许
else
return 0 -- 限流
end---
4. Pub/Sub(发布/订阅)命令
| 命令 | 可用版本 | 说明 |
|---|---|---|
| SUBSCRIBE | ≥2.0.0 | 订阅频道 |
| PUBLISH | ≥2.0.0 | 发布消息 |
| PSUBSCRIBE | ≥2.0.0 | 模式订阅 |
SUBSCRIBE / PUBLISH
SUBSCRIBE channel [channel ...] — 订阅一个或多个频道 PUBLISH channel message — 向频道发送消息
业务场景:
- 实时通知广播:用户发布新内容时通知关注者
- 服务状态广播:配置变更通知所有服务实例
- 实时聊天:每个聊天室一个频道
PSUBSCRIBE
PSUBSCRIBE pattern [pattern ...]
按模式订阅频道。模式支持 glob 风格:news.* 匹配 news.sports、news.tech 等。
PUBSUB
PUBSUB subcommand [argument [arguments]]
PUBSUB CHANNELS [pattern]— 查看当前活跃频道PUBSUB NUMSUB [channel ...]— 查看频道订阅数PUBSUB NUMPAT— 查看模式订阅数
---
5. 连接(Connection)命令
| 命令 | 可用版本 | 说明 |
|---|---|---|
| AUTH | ≥1.0.0 | 密码认证 |
| SELECT | ≥1.0.0 | 切换数据库 |
| PING | ≥1.0.0 | 存活检测 |
| CLIENT | ≥2.4.0 | 客户端管理 |
AUTH
AUTH password — 向 Redis 验证密码(requirepass 配置)
SELECT
SELECT index — 切换到指定数据库(0-15,默认 16 个库)
⚠️ Cluster 模式不支持 SELECT,只可用 0 号库。推荐用不同 key 前缀代替。
PING
PING — 检查连接是否存活。返回 PONG。
QUIT
QUIT — 关闭连接
CLIENT 系列
CLIENT SETNAME name — 设置连接名称(便于 DEBUG) CLIENT GETNAME — 获取连接名称 CLIENT LIST — 列出所有连接(含名称/地址/状态/缓冲区大小) CLIENT KILL [ip:port] [ID client-id] — 杀掉连接 CLIENT PAUSE timeout — 暂停所有客户端命令(用于故障转移) CLIENT UNPAUSE — 恢复
---
6. 服务器(Server)命令
| 命令 | 可用版本 | 说明 |
|---|---|---|
| INFO | ≥1.0.0 | 服务器信息 |
| CONFIG | ≥2.0.0 | 配置管理 |
| SLOWLOG | ≥2.2.12 | 慢查询日志 |
| MONITOR | ≥1.0.0 | 实时调试 |
INFO
INFO [section]
返回服务器信息(含 9 个 section):
- Server / Clients / Memory / Persistence / Stats / Replication / CPU / Keyspace / Cluster
常用:INFO MEMORY INFO STATS INFO REPLICATION INFO KEYSPACE
CONFIG
CONFIG GET parameter — 获取配置值 CONFIG GET * 全部 CONFIG SET parameter value — 修改运行时配置(无需重启) CONFIG REWRITE — 写入 redis.conf(使修改持久化) CONFIG RESETSTAT — 重置 INFO 统计
SLOWLOG
SLOWLOG GET [count] — 返回慢查询 SLOWLOG LEN — 慢查询总数 SLOWLOG RESET — 清空慢查询
MONITOR
实时打印 Redis 收到的所有命令。生产慎用(降低约 50% 吞吐量)。
FLUSHDB / FLUSHALL
FLUSHDB — 清空当前数据库 FLUSHALL — 清空所有数据库
用 CONFIG SET rename-command FLUSHALL "" 禁用BGSAVE / SAVE
BGSAVE — 后台 fork 生成 RDB(不阻塞) SAVE — 前台生成 RDB(阻塞所有请求)
BGREWRITEAOF
异步重写 AOF 文件(压缩)。
SHUTDOWN
SHUTDOWN [NOSAVE|SAVE] — 关闭服务器
- SAVE:关闭前生成 RDB
- NOSAVE:跳过保存
SLAVEOF
SLAVEOF host port — 设置主从 SLAVEOF NO ONE — 取消复制,提升为主
ROLE
返回实例的角色:master / slave / sentinel + 复制状态
INFO 关键字段解读
used_memory_human: 4.00G # 已用内存
used_memory_peak_human: 6.00G # 峰值内存
mem_fragmentation_ratio: 1.37 # 碎片率(>1.5 需整理)
connected_clients: 50 # 当前连接数
instantaneous_ops_per_sec: 15000 # 当前 QPS
keyspace_hits: 410000 # 缓存命中率计算
keyspace_misses: 82000
expired_keys: 0 # 过期 key 数
evicted_keys: 0 # 淘汰 key 数
rejected_connections: 0 # 拒绝的连接数Redis 命令详解 — Set / ZSet / Bitmap / Geo / HyperLogLog / Stream
内容源自 doc.redisfans.com 完整翻译版 (Redis 2.8+),每个命令包含简介、参数说明、业务场景。
---
1. Set(集合)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| SADD | O(1)/member | ≥1.0.0 | 添加成员 |
| SREM | O(1)/member | ≥1.0.0 | 移除成员 |
| SISMEMBER | O(1) | ≥1.0.0 | 判断存在 |
| SMEMBERS | O(N) | ≥1.0.0 | 获取全部 |
| SCARD | O(1) | ≥1.0.0 | 成员数量 |
SADD
SADD key member [member ...]
将一个或多个成员添加到集合。已存在的成员被忽略。
业务场景:
- 标签系统:
SADD article:42:tags redis database cache - 社交关系:
SADD user:42:followers user:100 - 白名单/黑名单:
SADD blacklist:ip 192.168.1.1 - 去重记录:谁访问过某页面
返回值:新增成员的数量(不含已存在的)
---
SREM
SREM key member [member ...]
移除集合中的一个或多个成员。不存在的成员被忽略。
业务场景:取消关注 (SREM user:42:following user:100)、标签删除
---
SISMEMBER
SISMEMBER key member
判断 member 是否是集合的成员(O(1) 级快速),这是 Set 最核心优势之一。
业务场景:
- 检查用户是否已点赞:
SISMEMBER post:42:likes user:1001 - IP 是否在黑名单
- 用户是否已有某个角色/权限
返回值:1(存在)| 0(不存在)
---
SMEMBERS
SMEMBERS key
返回集合中所有成员。O(N) 操作,大集合场景慎用(可能阻塞)。用 SSCAN 替代。
---
SCARD
SCARD key
返回集合的基数(成员数量)。O(1),不扫描。
业务场景:粉丝数 SCARD user:1001:followers、标签数量
---
集合运算
SINTER / SINTERSTORE
SINTER key [key ...] SINTERSTORE destination key [key ...]
返回/存储所有给定集合的交集。
业务场景:
- 共同好友:
SINTER user:42:friends user:100:friends - 权限交集:同时拥有权限 A 和 B 的用户
- 标签匹配:同时包含 redis 和 database 标签的文章
SUNION / SUNIONSTORE
SUNION key [key ...] SUNIONSTORE destination key [key ...]
返回/存储所有给定集合的并集。自动去重。
业务场景:
- 合并好友列表:获取共同好友的总集
- 群体权限合并
- 内容推荐去重
SDIFF / SDIFFSTORE
SDIFF key [key ...] SDIFFSTORE destination key [key ...]
返回/存储第一个集合与后续集合的差集。(即:在 A 中但不在 B 中的元素)
业务场景:
- 推荐新关注:
SDIFF user:42:may_know user:42:following - 新粉丝检测:昨天的新增粉丝
- 增量处理:这批数据中哪些是新的
---
SPOP / SRANDMEMBER
SPOP key [count] — 随机移除并返回 count 个成员 SRANDMEMBER key [count] — 随机返回但不移除 count 个成员
- count > 0:返回 count 个不重复成员
- count < 0:返回 |count| 个可重复成员(允许重复)
业务场景:
- 抽奖系统:
SRANDMEMBER lucky:draw:users 1 - 随机推荐:
SRANDMEMBER articles 5 - 资源抽取:随机分配任务(SPOP 消耗)
---
SMOVE
SMOVE source destination member
将 member 从 source 移动到 destination。原子操作。
业务场景:任务流转(待处理 → 处理中)、队列状态迁移
---
SSCAN
SSCAN key cursor [MATCH pattern] [COUNT count]
渐进式迭代集合元素。替代 SMEMBERS 的大集合场景。
---
2. Sorted Set(有序集合)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| ZADD | O(log N)/item | ≥1.2.0 | 添加/更新 |
| ZRANGE | O(log N+M) | ≥1.2.0 | 按排名查 |
| ZRANK | O(log N) | ≥2.0.0 | 获取排名 |
| ZSCORE | O(1) | ≥1.2.0 | 获取分数 |
| ZINCRBY | O(log N) | ≥1.2.0 | 增加分数 |
ZADD
ZADD key [NX|XX] [GT|LT] [CH] [INCR] score member [score member ...]
将一个或多个 member 及其 score 加入有序集合。如果 member 已存在则更新 score。
参数说明:
NX:仅新成员,不更新已存在XX:仅更新已存在,不添加新成员GT|LT:仅当新分数大于/小于当前分数时更新CH:返回值包含更新而不是新增的数量INCR:增加分数(等价 ZINCRBY)
业务场景:
- 实时排行榜:
ZADD leaderboard 9527 "player_42" - 延时队列:
ZADD delay:queue <unix_timestamp> "job_id"(用 ZRANGEBYSCORE 轮询到期任务) - 带权重的标签匹配
返回值:新增成员数量(不含更新)
---
ZRANGE / ZREVRANGE
ZRANGE key start stop [WITHSCORES] ZREVRANGE key start stop [WITHSCORES]
按分数从小到大(ZRANGE)/ 从大到小(ZREVRANGE)返回排名区间内的成员。WITHSCORES 选项同时返回分数。
业务场景:
- ZREVRANGE 0 9 WITHSCORES → 排行榜 Top 10
- ZRANGE 0 -1 → 全部成员(按分排序)
注意:ZRANGE 在 Redis 6.2.0+ 中扩展支持 BYSCORE / BYLEX / REV 参数,提供了更强的排序能力。
---
ZRANGEBYSCORE / ZREVRANGEBYSCORE
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
按分数范围返回成员。支持区间符号:
(5不包含 55包含 5-inf/+inf负无穷 / 正无穷
业务场景:
- 延时队列消费:
ZRANGEBYSCORE delay:queue 0 <current_timestamp LIMIT 0 10 - 薪资范围查询:
ZRANGEBYSCORE salary 10000 20000 - 分数段统计:
ZCOUNT leaderboard 1000 2000
---
ZRANK / ZREVRANK
ZRANK key member ZREVRANK key member
返回 member 在有序集合中的排名(0-based)。
业务场景:
- 查看自己的排名:
ZREVRANK leaderboard "player_42" - 排名变化监控:计算排名差
---
ZSCORE
ZSCORE key member
返回 member 的分数值。O(1) 操作。
---
ZINCRBY
ZINCRBY key increment member
将 member 的分数增加 increment(可正可负)。
业务场景:
- 实时更新分数:
ZINCRBY leaderboard 50 "player_42"(+50 分) - 扣分:
ZINCRBY leaderboard -10 "player_42"
---
ZCARD
ZCARD key — 返回有序集合的成员数量(O(1))
业务场景:排行榜总人数、队列长度
---
ZCOUNT
ZCOUNT key min max — 返回分数在 min 和 max 之间的成员数量
业务场景:特定分段人数统计(不及格/及格/优秀各多少人)
---
ZREM / ZREMRANGEBYRANK / ZREMRANGEBYSCORE
ZREM key member [member ...] — 移除指定成员 ZREMRANGEBYRANK key start stop — 移除排名区间 ZREMRANGEBYSCORE key min max — 移除分数区间
业务场景:
- 清除过期成员
ZREMRANGEBYSCORE leaderboard -inf 0(分数 ≤ 0 的移除) - 排行榜缩容
ZREMRANGEBYRANK leaderboard 100 -1(保留前 100)
---
ZINTERSTORE / ZUNIONSTORE
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS w] [AGGREGATE SUM|MIN|MAX] ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS w] [AGGREGATE SUM|MIN|MAX]
计算多个有序集的交集/并集,结果保存到 destination。
- WEIGHTS:每个 key 的权重乘数
- AGGREGATE:SUM(分数相加)/ MIN(取最小分数)/ MAX(取最大分数)
业务场景:
- 多周期合并:
ZUNIONSTORE monthly 4 week1 week2 week3 week4(月排行榜 = 4 周合并) - 加权推荐:
ZINTERSTORE recommend 2 clicks:user purchases:user WEIGHTS 0.3 0.7(点击 ×0.3 + 购买 ×0.7 的加权推荐)
---
ZSCAN
ZSCAN key cursor [MATCH pattern] [COUNT count]
渐进式迭代有序集合。
ZRANGEBYLEX / ZLEXCOUNT / ZREMRANGEBYLEX
ZRANGEBYLEX key min max [LIMIT offset count] ZLEXCOUNT key min max ZREMRANGEBYLEX key min max
基于字典序范围操作(需要所有成员分数相同)。区间用 [(闭区间)和 ((开区间)。
业务场景:字符串分组统计、按字母序浏览
---
3. Bitmap(位图)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| SETBIT | O(1) | ≥2.2.0 | 设置位 |
| GETBIT | O(1) | ≥2.2.0 | 获取位 |
| BITCOUNT | O(N) | ≥2.2.0 | 统计 1 数量 |
| BITOP | O(N) | ≥2.2.0 | 位运算 |
| BITPOS | O(N) | ≥2.8.7 | 查找位 |
SETBIT / GETBIT
SETBIT key offset value (value: 0 或 1) GETBIT key offset
# 用户 42 在 2024-01-15 签到
SETBIT sign:2024-01-15 42 1
# 查询签到状态
GETBIT sign:2024-01-15 42业务场景:
- 每日签到:亿级用户只需 (用户数/8) 字节
- 独立用户标记:
SETBIT online:2024-01-15 user_id 1
BITCOUNT
BITCOUNT key [start end [BYTE|BIT]]
业务场景:
- 日活统计:
BITCOUNT online:2024-01-15 - 签到人数:
BITCOUNT sign:2024-01
BITOP
BITOP operation destkey key [key ...]
业务场景:
- 月活:
BITOP OR monthly dest week1 week2 week3 week4 - 连续活跃:
BITOP AND dest day1 day2 day3
BITPOS
BITPOS key bit [start [end [BYTE|BIT]]]
返回第一位为 0 或 1 的位置。用于找到第一个空闲位或第一个标记位。
---
4. HyperLogLog 命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| PFADD | O(1) | ≥2.8.9 | 添加元素 |
| PFCOUNT | O(1) | ≥2.8.9 | 基数估算 |
| PFMERGE | O(N) | ≥2.8.9 | 合并 |
PFADD
PFADD key element [element ...]
添加元素到 HyperLogLog 数据结构。元素可重复添加(自动去重)。
PFCOUNT
PFCOUNT key [key ...]
返回 HyperLogLog 的基数估算值。单 key O(1),多 key O(N)(需合并临时结构)。
误差:标准误差 0.81%
业务场景:
- UV 统计:
PFADD uv:2024-01-15 "user_42"→PFCOUNT uv:2024-01-15 - 多日合并 UV:
PFCOUNT uv:day1 uv:day2 uv:day3 - 搜索词去重:
PFADD search:terms "redis cluster"
PFMERGE
PFMERGE destkey sourcekey [sourcekey ...]
合并多个 HyperLogLog 到 destkey。
业务场景:月 UV = 合并 30 天的 UV PFMERGE uv:2024-01 uv:0101 uv:0102 ... uv:0130
---
5. Geo(地理位置)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| GEOADD | O(log N)/item | ≥3.2.0 | 添加位置 |
| GEOPOS | O(log N)/item | ≥3.2.0 | 获取坐标 |
| GEODIST | O(log N) | ≥3.2.0 | 距离计算 |
| GEORADIUS | O(N+log M) | ≥3.2.0 | 半径查询 |
| GEOHASH | O(log N)/item | ≥3.2.0 | 编码转换 |
GEOADD
GEOADD key longitude latitude member [longitude latitude member ...]
将指定的地理空间位置(经度、纬度、名称)添加到 key 中。
GEOADD cities 116.397 39.908 "北京" 121.474 31.230 "上海"
GEOADD cities 113.264 23.129 "广州" 114.057 22.543 "深圳"---
GEODIST
GEODIST key member1 member2 [m|km|mi|ft]
返回两个给定位置之间的距离。默认米(m)。
GEODIST cities "北京" "上海" km → 1067.5
GEODIST cities "北京" "广州" km → 1889.6---
GEORADIUS
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
以给定的经纬度为中心,查找半径内的位置元素。
WITHDIST:同时返回距离WITHCOORD:同时返回坐标COUNT:限制返回数量
业务场景:
- 附近的人/店铺:
GEORADIUS locations 116.4 39.9 5 km WITHDIST COUNT 20 - 地理围栏:查询指定范围内的 POI
---
GEORADIUSBYMEMBER
GEORADIUSBYMEMBER key member radius m|km|ft|mi [...]
以已存储的成员为中心,查找附近的元素。
业务场景:基于用户当前位置查找附近服务
---
GEOHASH
GEOHASH key member [member ...]
返回 Geohash 编码字符串(11 字符)。
---
6. Stream(消息流)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| XADD | O(1)/entry | ≥5.0.0 | 追加消息 |
| XREAD | O(N) | ≥5.0.0 | 读取消息 |
| XRANGE | O(N) | ≥5.0.0 | 范围查询 |
| XGROUP | O(1) | ≥5.0.0 | 管理消费组 |
| XREADGROUP | O(N) | ≥5.0.0 | 消费组读取 |
| XACK | O(1) | ≥5.0.0 | 确认消费 |
XADD
*XADD key [NOMKSTREAM] [MAXLEN|MINID [~] threshold] |id field value [field value ...]**
向 Stream 追加一条新消息。* 表示自动生成唯一时间戳 ID,格式 unix_ms-sequence。
NOMKSTREAM:key 不存在时不自动创建MAXLEN [~]:限制长度(~启用近似修剪提升性能)MINID [~]:按 ID 阈值修剪
业务场景:
# 订单事件流
XADD orders * order_id 1001 user_id 42 amount 99.99 status created
XADD orders * order_id 1001 status paid
XADD orders * order_id 1001 status shipped---
XRANGE / XREVRANGE
XRANGE key start end [COUNT count] XREVRANGE key end start [COUNT count]
按 ID 范围返回消息。用 - 和 + 表示最小/最大 ID。
业务场景:
- 查看最新消息:
XREVRANGE stream + - COUNT 10 - 按时间段查询:
XRANGE orders 1700000000000-0 1700001000000-0 - 全量回放:
XRANGE stream - +
---
XREAD
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]
读取一个或多个 Stream 中 ID 大于指定值的新消息。
BLOCK 0:阻塞等待(不超时)COUNT 10:最多返回 10 条
业务场景:
# 非阻塞读取
XREAD COUNT 10 STREAMS mystream 0
# 阻塞等待新消息
XREAD COUNT 1 BLOCK 5000 STREAMS mystream $---
XGROUP
XGROUP [CREATE|SETID|DESTROY|DELCONSUMER] key group [id|$] [MKSTREAM]
管理消费组。
XGROUP CREATE mystream mygroup $:创建组,从最新消息开始XGROUP CREATE mystream mygroup 0:创建组,从第一条消息开始MKSTREAM:key 不存在时自动创建
---
XREADGROUP
XREADGROUP GROUP group consumer [COUNT count] [BLOCK ms] STREAMS key [key ...] id [id ...]
消费组读取。> 表示读取未被其他消费者读取的新消息。
业务场景:
# 多消费者处理订单流
# 消费者 1
XREADGROUP GROUP orders-group consumer-1 COUNT 1 BLOCK 2000 STREAMS orders >
# 消费者 2 (自动负载均衡)
XREADGROUP GROUP orders-group consumer-2 COUNT 1 BLOCK 2000 STREAMS orders >---
XACK
XACK key group id [id ...]
确认消息已被处理。消息确认后才从 Pending 列表移除。
---
XPENDING / XINFO
XPENDING key group [start end count [consumer]] XINFO GROUPS key
管理 Pending 消息(已投递但未 ACK)。
XPENDING orders payment-group:查看待确认XPENDING orders payment-group - + 10 consumer-1:查看消费者 1 的待确认
---
7. 编码与空间效率对比
| 数据结构 | 小数据编码 | 内存效率 | 数据量阈值 |
|---|---|---|---|
| Hash | ziplist → hashtable | 高(小数据)→ 中 | entries:512, value:64B |
| ZSet | ziplist → skiplist | 高(小数据)→ 中 | entries:128, value:64B |
| Set | intset → hashtable | 高(全整数)→ 中 | entries:512 |
| List | quicklist (ziplist节点) | 高 | list-max-ziplist-size:-2 |
Redis 命令详解 — String / Hash / List
内容源自 doc.redisfans.com 完整翻译版 (Redis 2.8+),每个命令包含简介、参数说明、业务场景。
---
1. String(字符串)命令
| 命令 | 时间复杂度 | 可用版本 | 分类 |
|---|---|---|---|
| SET | O(1) | ≥1.0.0 | 基础 |
| GET | O(1) | ≥1.0.0 | 基础 |
| INCR | O(1) | ≥1.0.0 | 计数器 |
| MSET | O(N) | ≥1.0.1 | 批量 |
| APPEND | O(1) | ≥2.0.0 | 字符串操作 |
SET
SET key value [EX seconds] [PX milliseconds] [NX|XX] [KEEPTTL]
将字符串值 value 关联到 key。如果 key 已存在,SET 覆写旧值。对于原带 TTL 的 key,SET 执行后清除原 TTL。
参数说明:
EX seconds:设置过期时间(秒),等价 SETEXPX milliseconds:设置过期时间(毫秒),等价 PSETEXNX:仅在 key 不存在时设置,等价 SETNXXX:仅在 key 已存在时设置KEEPTTL(Redis 6.0+):保留 key 原有的 TTL
⚠️ Redis 未来版本可能废弃 SETNX / SETEX / PSETEX,推荐统一使用 SET 的可选参数。
业务场景:分布式锁
SET resource:lock random_string NX EX 30- 返回 OK → 获得锁
- 返回 NIL → 锁被占用,稍后重试
- 解锁需配合 Lua 脚本原子校验 token 后 DEL
业务场景:缓存
SET user:profile:42 '{"name":"Alice"}' EX 3600返回值:OK(成功)| NIL(NX/XX 条件未满足)
---
GET
GET key
返回 key 所关联的字符串值。key 不存在返回 nil,key 不是 string 类型返回错误。
业务场景:
- 缓存读取(配合 SETEX 写入)
- 分布式锁 token 校验
- Session 数据获取
返回值:字符串值 | nil(key 不存在)
---
INCR
INCR key
将 key 中存储的数字值增一。key 不存在则先初始化为 0 再执行。值不能超过 64 位有符号整数。
业务场景:
- 计数器:页面访问量、文章 PV/UV
- 序列生成器:订单号自增 (
INCR order:seq) - 限流计数器:每秒/每分钟请求计数
- 消息未读数:
INCR user:42:unread
错误处理:如果 key 存的值不是数字,返回 WRONGTYPE 错误。
返回值:执行 INCR 后的新值
---
INCRBY
INCRBY key increment
将 key 中的数字加上指定增量(可正可负)。等价于 INCR 的通用版本。
业务场景:
- 积分增减
INCRBY user:42:points 100 - 库存批量扣减
INCRBY stock:item:1001 -1
---
INCRBYFLOAT
INCRBYFLOAT key increment
为 key 中的值加上浮点数增量。支持精度到小数点后 17 位。
业务场景:价格计算、余额操作、汇率换算
---
DECR / DECRBY
DECR key / DECRBY key decrement
将 key 中的数字值减一/减 decrement。等价于 INCRBY 的减量版本。
业务场景:
- 库存剩余量实时递减
- 优惠券剩余数量
- 限流可用配额
---
MSET
MSET key value [key value ...]
同时设置一个或多个 key-value。MSET 是原子操作(要么全设要么全不设),MGET 不是(但读取本身是原子单次操作)。
业务场景:批量初始化缓存、批量保存配置
MSET user:1:name "Alice" user:1:age 30 user:1:city "Beijing"返回值:OK
---
MSETNX
MSETNX key value [key value ...]
仅当所有给定 key 都不存在时,才同时设置一个或多个 key-value。原子性保证"全部或全不"。
业务场景:批量初始化确保不覆盖已有数据
---
MGET
MGET key [key ...]
返回所有给定 key 的值(按请求顺序返回)。某个 key 不存在则返回 nil。
业务场景:批量查缓存(比 N 次 GET 节省 RTT)
---
APPEND
APPEND key value
将 value 追加到 key 原值的末尾。key 不存在则等同于 SET。
业务场景:日志追加、文本拼接、Feed 构建
返回值:追加后的字符串长度
---
GETRANGE
GETRANGE key start end
返回 key 中字符串的子串(0-based,包含 start 和 end)。支持负数偏移(-1 是最后一个字符)。
业务场景:截取部分内容展示、分页读取长字符串
---
SETRANGE
SETRANGE key offset value
从 offset 开始,用 value 覆写 key 的字符串。原字符串长度不足则自动补充零字节(\x00)。
业务场景:更新固定长度字段、位图叠加写入
---
STRLEN
STRLEN key
返回字符串值的长度。key 不存在返回 0。
---
GETSET
GETSET key value
原子操作:设置新值,返回旧值。如果 key 不存在则返回 nil(此时相当于 SET)。
业务场景:计数器重置(获取旧值后置零)、轮转更新
---
SETEX
SETEX key seconds value
等价 SET key value EX seconds。建议直接用 SET 替代。
---
SETNX
SETNX key value
等价 SET key value NX。建议直接用 SET 替代。
---
PSETEX
PSETEX key milliseconds value
等价 SET key value PX milliseconds。建议直接用 SET 替代。
---
BITCOUNT
BITCOUNT key [start end [BYTE|BIT]]
计算字符串中 1 的比特位数量(popcount)。可通过 start/end 指定字节范围。
业务场景:
- 在线用户统计:每天一个 BITMAP,用户 ID 作为 offset
- 签到统计:
BITCOUNT sign:2024-01-15 - 日活 UV 统计:多天 BITMAP 的 BITOP OR 再 BITCOUNT
---
BITOP
BITOP operation destkey key [key ...]
对一个或多个 key 执行位运算:AND / OR / NOT / XOR,结果保存到 destkey。
业务场景:
- 连续签到统计:
BITOP AND result sign:01 sign:02 sign:03(当月全部签到的用户) - 任意签到查找:
BITOP OR result sign:01 sign:02(月内至少签到一次的用户) - 广告去重:多日曝光用户 BITOP OR
---
SETBIT / GETBIT
SETBIT key offset value / GETBIT key offset
设置/获取指定偏移量上的比特位(0 或 1)。
业务场景:
- 用户签到:
SETBIT sign:2024-01 42 1 - 布隆过滤器实现
- 独立用户标记
---
2. Hash(哈希表)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| HSET | O(1) | ≥2.0.0 | 设置字段 |
| HGET | O(1) | ≥2.0.0 | 获取字段 |
| HGETALL | O(N) | ≥2.0.0 | 获取所有 |
| HMSET | O(N) | ≥2.0.0 | 批量设置 |
| HINCRBY | O(1) | ≥2.0.0 | 字段计数 |
HSET
HSET key field value [field value ...] (Redis 4.0+ 支持多 field)
设置哈希表 key 中的字段。字段已存在则覆盖旧值。多字段版本返回新创建字段数量。
业务场景:对象存储
HSET user:1001 name "Alice" age 30 email "alice@example.com"替代了 set user:1001:name / set user:1001:age / set user:1001:email 三个 key,节省约 50% 内存。
---
HGET
HGET key field
获取哈希表中指定字段的值。
---
HGETALL
HGETALL key
返回哈希表中所有字段和值(交替排列)。大 Hash 场景慎用(阻塞 Redis)。
业务场景:小对象(字段数 < 100)适合全量读取;大对象改用 HSCAN 分批迭代。
---
HMSET / HMGET
HMSET key field value [field value ...] HMGET key field [field ...]
批量设置/获取字段。HMSET 已被 HSET 的多 field 版本取代。
业务场景:HMGET user:1001 name email 只取需要的字段,避免 HGETALL 浪费带宽。
---
HEXISTS / HDEL
HEXISTS key field — 判断字段是否存在 HDEL key field [field ...] — 删除一个或多个字段
---
HLEN
HLEN key — 返回哈希表中字段数量
业务场景:Hash 大小时监控(HLEN 是 O(1) 的快照)。
---
HKEYS / HVALS
HKEYS key — 获取所有字段名 HVALS key — 获取所有字段值
---
HINCRBY / HINCRBYFLOAT
HINCRBY key field increment — 整数增加 HINCRBYFLOAT key field increment — 浮点数增加
业务场景:Hash 中的计数器(如用户积分 HINCRBY user:1001 score 10)
---
HSETNX
HSETNX key field value — 字段不存在时才设置(等价 Hash 版的 SETNX)
业务场景:
- 第一次访问时设置初始值
- 防止覆盖已有数据
HSCAN
HSCAN key cursor [MATCH pattern] [COUNT count]
渐进式迭代哈希表中的字段。替代 HGETALL 大 Hash 场景。
---
3. List(列表)命令
| 命令 | 时间复杂度 | 可用版本 | 说明 |
|---|---|---|---|
| LPUSH | O(1) | ≥1.0.0 | 左推 |
| RPUSH | O(1) | ≥1.0.0 | 右推 |
| LPOP | O(1) | ≥1.0.0 | 左弹 |
| LRANGE | O(S+N) | ≥1.0.0 | 范围查 |
| LTRIM | O(N) | ≥1.0.0 | 修剪 |
| BLPOP | O(1) | ≥2.0.0 | 阻塞左弹 |
RPUSH / LPUSH
RPUSH key value [value ...] — 右端推入 LPUSH key value [value ...] — 左端推入
业务场景:
- 队列 (FIFO):
RPUSH queue job1+LPOP queue或BLPOP queue - 栈 (LIFO):
LPUSH stack item+LPOP stack - 时间线:
LPUSH timeline:user42 post_id+LTRIM timeline:user42 0 99
---
LRANGE
LRANGE key start stop
返回列表中指定区间内的元素(0-based)。负偏移索引:-1 是最后一个。
业务场景:分页读取列表、获取最新 N 条消息
LRANGE messages 0 9 -- 最新 10 条
LRANGE messages 0 -1 -- 全部(慎用,大列表会阻塞)---
LTRIM
LTRIM key start stop
修剪列表,仅保留指定区间内的元素。
业务场景:固定长度列表
LPUSH recent:items article:1001
LTRIM recent:items 0 99 -- 最多保留 100 条---
LPOP / RPOP
LPOP key [count] (Redis 6.2+) — 移除并返回左边第一个元素 RPOP key [count] (Redis 6.2+) — 移除并返回右边第一个元素
---
BLPOP / BRPOP
BLPOP key [key ...] timeout BRPOP key [key ...] timeout
阻塞式弹出:列表为空时等待,直到超时或有元素加入。timeout=0 表示无限等待。
业务场景:可靠消息队列
# Worker 端
BLOP queue 0 # 无限等待新任务
# 有元素加入队列时立即返回,无需轮询阻塞特性:
- 多个客户端同时 BLPOP 同一 key → 第一个等待的客户端优先
- 监视多个 key:按 key 顺序依次检查
- 超时返回 nil(两个 nil 值)
---
RPOPLPUSH / BRPOPLPUSH
RPOPLPUSH source destination — 转存(原子操作) BRPOPLPUSH source destination timeout — 阻塞版转存
业务场景:可靠消息处理(备份队列)
# 生产:RPUSH queue:incoming job
# 消费:BRPOPLPUSH queue:incoming queue:processing 0
# 成功处理后:LREM queue:processing 1 job
# 处理失败:RPUSH queue:retry job原子转移保证消息不丢——崩溃重启后还能从 processing 队列恢复。
---
LINDEX / LSET / LINSERT
LINDEX key index — 根据索引获取 LSET key index value — 设置索引位置的元素 LINSERT key BEFORE|AFTER pivot value — 在指定元素前后插入
业务场景:LRANGE 读取后定位到特定位置修改、列表中间插入优先级任务
---
LLEN
LLEN key — 返回列表长度(O(1))
业务场景:消息队列积压长度监控、列表大小的快速判断
---
LREM
LREM key count value
移除列表中与 value 匹配的元素。
- count > 0:从左到右移除最多 count 个
- count < 0:从右到左移除最多 |count| 个
- count = 0:移除全部匹配
业务场景:取消点赞、清理已处理消息
---
LPUSHX / RPUSHX
LPUSHX key value — 仅当列表存在时左推 RPUSHX key value — 仅当列表存在时右推
业务场景:仅在队列初始化后才接收新消息,避免自动创建空列表。
Redis 内存优化深度指南
1. 内存模型
Redis 内存构成:
┌─────────────────────────────────┐
│ 数据内存 (key + value) │ ← 主要部分
│ 元数据 (dict entry/robj) │ ← 每个 key 约 64 字节开销
│ 缓冲区 (client/复制/AOF) │
│ 自身 (代码/栈) │
└─────────────────────────────────┘2. 编码优化 — 选择最省内存的数据结构
| 数据结构 | 小数据编码 | 省内存机制 | 阈值配置 |
|---|---|---|---|
| Hash | ziplist | 连续内存块,无指针开销 | hash-max-ziplist-entries 512<br>hash-max-ziplist-value 64 |
| ZSet | ziplist | 同上 | zset-max-ziplist-entries 128<br>zset-max-ziplist-value 64 |
| Set | intset | 整数数组,连续内存 | set-max-intset-entries 512 |
| List | quicklist | ziplist 链表节点 | list-max-ziplist-size -2<br>list-compress-depth 0 |
3. 内存优化 10 大技巧
3.1 用 Hash 替代 String 存对象
# 坏: 每个字段一个 key (大量元数据开销)
SET user:1001:name "Alice"
SET user:1001:age 30
SET user:1001:email "alice@example.com"
# 内存: 3 × (37+key_overhead) ≈ 300 字节
# 好: 一个 Hash 存所有字段
HSET user:1001 name "Alice" age 30 email "alice@example.com"
# 内存: ~160 字节 (节省 ~50%)3.2 合理设置过期时间
# 不使用过期 = 内存只增不减
# 最佳实践: 每个 key 都设 TTL
SET cache:xxx value EX 3600
# 批量设置随机 TTL 避免雪崩
SET cache:a value EX $(( 300 + RANDOM % 60 ))3.3 短 key 命名
# 坏: 超长 key 名
SET "user:profile:data:by:user:id:1001:preferences" value
# 好: 短 key 名
SET u:1001:pref value
# 节省: 每个 key 减少数十字节, 百万 key 节省数十 MB3.4 使用小数据类型
# 统计在线用户数
# 坏: Set 存储所有用户ID
SADD online:users 1001 # 每个 member 约 60+ 字节
# 好: Bitmap 按位存储 (每个用户 1 bit)
SETBIT online:2024-01-15 1001 1 # 仅 1 位
# 统计 UV
# 坏: Set 存储所有访问用户 (大数据量)
# 好: HyperLogLog (单 key 仅 12KB)
PFADD visits:2024-01-15 "user1" "user2"3.5 压缩大 Value
import zlib
import json
# 存储前压缩
data = json.dumps(large_object)
compressed = zlib.compress(data.encode())
redis.set("large:key", compressed)
# 读取后解压
compressed = redis.get("large:key")
data = json.loads(zlib.decompress(compressed))4. 内存监控与调优
# 查看内存使用
redis-cli INFO MEMORY
# 关键指标解读
used_memory_human: 4.00G # 已用内存
used_memory_peak_human: 6.00G # 峰值 (需关注)
used_memory_rss_human: 5.50G # 系统分配内存 (含碎片)
mem_fragmentation_ratio: 1.37 # 碎片率 (>1.5 需处理)
# 找到大 key
redis-cli --bigkeys
# 查看 key 的精确内存占用
redis-cli MEMORY USAGE user:1001
# 查看 key 的编码
redis-cli OBJECT ENCODING user:1001
redis-cli OBJECT IDLETIME user:10015. 内存淘汰策略选择
| 策略 | 适用场景 | 示例配置 |
|---|---|---|
| allkeys-lru | 通用缓存,访问时间间隔模式 | maxmemory-policy allkeys-lru |
| volatile-lru | 部分 key 持久化部分做缓存 | maxmemory-policy volatile-lru |
| allkeys-lfu | 访问频率差异大的场景 | maxmemory-policy allkeys-lfu |
| allkeys-random | 缓存键命中率均匀 | maxmemory-policy allkeys-random |
| volatile-ttl | 优先保留过期时间短的 | maxmemory-policy volatile-ttl |
# 最佳生产配置: 4GB 内存 + LRU 淘汰
maxmemory 4gb
maxmemory-policy allkeys-lru6. 内存碎片处理
# 检查碎片率
redis-cli INFO | grep mem_fragmentation_ratio
# 自动碎片整理 (Redis 4.0+)
CONFIG SET activedefrag yes
CONFIG SET active-defrag-threshold-lower 10
CONFIG SET active-defrag-threshold-upper 100
CONFIG SET active-defrag-ignore-bytes 100mb
CONFIG SET active-defrag-cycle-min 5
CONFIG SET active-defrag-cycle-max 75
# 手动 (高碎片率时)
redis-cli MEMORY PURGE
# 如仍高,需重启 Redis 节点Redis 生产配置最佳实践
推荐生产配置 (redis.conf)
# ────────────────────────────────────
# 基础配置
# ────────────────────────────────────
daemonize no
pidfile /var/run/redis_6379.pid
port 6379
bind 0.0.0.0 # 生产环境改为内网 IP
protected-mode yes
# ────────────────────────────────────
# 内存管理
# ────────────────────────────────────
maxmemory 4gb
maxmemory-policy allkeys-lru
maxmemory-samples 10 # LRU 采样样本数 (越大越精确)
# ────────────────────────────────────
# 持久化 — 混合模式
# ────────────────────────────────────
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data/redis/
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes # 混合持久化 (Redis 4.0+)
# ────────────────────────────────────
# 网络与连接
# ────────────────────────────────────
tcp-backlog 511
timeout 300
tcp-keepalive 300
maxclients 10000
# ────────────────────────────────────
# 复制
# ────────────────────────────────────
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
# ────────────────────────────────────
# 安全
# ────────────────────────────────────
requirepass your-strong-password-here
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command SHUTDOWN ""
rename-command DEBUG ""
rename-command SLAVEOF ""
# ────────────────────────────────────
# 慢查询日志
# ────────────────────────────────────
slowlog-log-slower-than 10000 # 记录 >10ms 的命令
slowlog-max-len 128
# ────────────────────────────────────
# 高级配置
# ────────────────────────────────────
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hz 10
dynamic-hz yes
activedefrag yes # 自动碎片整理 (Redis 4.0+)Docker 部署
# 单机 Redis
docker run -d --name redis \
-p 6379:6379 \
-v /data/redis/data:/data \
-v /data/redis/redis.conf:/usr/local/etc/redis/redis.conf \
redis:7-alpine redis-server /usr/local/etc/redis/redis.conf
# Redis Cluster
docker network create redis-cluster
for port in 7000 7001 7002 7003 7004 7005; do
mkdir -p /data/redis/${port}
docker run -d --name redis-${port} \
--net redis-cluster \
-p ${port}:${port} \
-v /data/redis/${port}:/data \
redis:7-alpine redis-server \
--port ${port} \
--cluster-enabled yes \
--cluster-config-file nodes.conf \
--cluster-node-timeout 5000 \
--appendonly yes
done
# 创建集群
docker exec redis-7000 redis-cli --cluster create \
192.168.1.100:7000 192.168.1.100:7001 192.168.1.100:7002 \
192.168.1.100:7003 192.168.1.100:7004 192.168.1.100:7005 \
--cluster-replicas 1性能调优检查清单
- [ ]
maxmemory设置为物理内存的 60-70% - [ ]
maxmemory-policy设为allkeys-lru(缓存场景) - [ ] 禁用危险命令(FLUSHALL/CONFIG/EVAL...)
- [ ] 慢查询阈值 ≤ 10ms
- [ ] 连接池配置合理(maxTotal ≤ maxclients)
- [ ] Big Key 已拆分或索引
- [ ] 不分业务混用实例
- [ ] 监控指标已接入(INFO 命令定期采集)
- [ ] RDB + AOF 混合持久化已配置
- [ ] 主从 / Sentinel / Cluster 已部署