Skip to content

第十章:Redis 常用数据结构与典型使用场景 ​

Q26:Redis 常用的数据结构有哪些?分别适合什么场景? ​

答:

Redis 不是简单的 key-value 缓存。它提供了多种数据结构,不同结构解决的问题不同。选型时不要只问“能不能存”,而要问:数据是否需要按字段更新、是否需要排序、是否需要去重、是否需要阻塞消费、是否需要可靠确认、是否允许近似统计、是否需要按地理位置查询。

Redis 常用数据结构总览图 ​

教科书式可编辑画板版总图: [redis-ch10-data-structures-overview.html](file:///Users/binny/workspace-sdd/aiNotes/redis/redis-ch10-data-structures-overview.html)

Excalidraw 源文件: [redis-ch10-data-structures-overview.excalidraw](file:///Users/binny/workspace-sdd/aiNotes/redis/redis-ch10-data-structures-overview.excalidraw)

下面保留一份纯文本版总览图,便于在不支持画板预览的 Markdown 阅读器中快速查看结构:

text
                         Redis
                           │
   ┌───────────────┬───────┼───────────────┬───────────────┐
   │               │       │               │               │
 String         Hash     List / Stream    Set / ZSet      其他模块
   │               │       │               │               │
单值缓存、计数   对象字段   队列/消息流   去重/排序/排名   JSON、搜索、图形化、统计
                              │               │               │
                           阻塞消费         会员关系      向量、过滤器、指标

可以先用下面这张表建立整体印象:

数据结构 / 能力核心特点最典型场景常用命令
String单 key 单 value,可做字符串、数字、JSON、二进制缓存、计数器、验证码、分布式锁GET、SET、INCR、SET NX EX
Hash一个 key 下多个 field用户资料、任务进度、商品详情HSET、HGET、HGETALL、HINCRBY
List有序列表,两端插入/弹出任务队列、最新列表、栈LPUSH、BRPOP、LRANGE、LTRIM
Set无序去重集合点赞用户、标签、共同关注SADD、SISMEMBER、SINTER
ZSet带 score 的有序集合排行榜、延迟队列、时间线排序ZADD、ZREVRANGE、ZRANGEBYSCORE
Stream带消息 ID 的日志型消息流可靠队列、消费组、事件日志XADD、XREADGROUP、XACK
Bitmapbit 位状态存储签到、活跃用户、灰度标记SETBIT、GETBIT、BITCOUNT
BitField在字符串中按位段读写整数多个小整数状态压缩存储BITFIELD
HyperLogLog大规模去重数量估算UV、访问人数估算PFADD、PFCOUNT
GEO经纬度位置索引附近门店、附近的人GEOADD、GEOSEARCH、GEODIST
Pub/Sub实时发布订阅实时通知、配置变更广播PUBLISH、SUBSCRIBE
RedisJSONJSON 文档读写,需模块支持复杂对象缓存、局部 JSON 更新JSON.SET、JSON.GET
Bloom Filter概率型存在性判断,需模块支持防缓存穿透、黑名单预判BF.ADD、BF.EXISTS
TimeSeries时间序列数据,需模块支持监控指标、埋点趋势TS.ADD、TS.RANGE
RedisSearch全文检索和二级索引,需模块支持商品搜索、文档搜索、任务检索FT.CREATE、FT.SEARCH
Vector Set / Vector Search向量相似度检索,需 Redis Stack / 新版本能力语义搜索、相似视频、RAG 检索FT.SEARCH、VSIM
Cuckoo Filter可删除的概率型存在性判断,需模块支持可删除黑名单、临时去重CF.ADD、CF.EXISTS、CF.DEL
Count-Min Sketch频次估算,需模块支持热点 key、热门搜索词、点击频次估算CMS.INCRBY、CMS.QUERY
TopK高频元素近似统计,需模块支持热门视频、热门标签、热门搜索词TOPK.ADD、TOPK.LIST
TDigest分位数统计,需模块支持P95/P99 延迟、耗时分布TDIGEST.ADD、TDIGEST.QUANTILE

Redis 常用数据结构的图形化、CLI 与案例一体化展示 ​

下面把每种数据结构的场景概述、图形化展示、redis-cli 命令和 Python 示例放在同一个小节里,便于横向对照阅读。

1. String:字符串 / 数值 / JSON 缓存 / 分布式锁 ​

场景概述: String 适合存放单个值、计数器、缓存和锁标记。

图形化展示:

text
user:1001  ──►  "{name: 'Tom', level: 3}"
video:6:view_count  ──►  "1024"
lock:task:6  ──►  "random-token"

redis-cli 命令:

bash
redis-cli SET task:6:status RUNNING EX 900
redis-cli GET task:6:status
redis-cli INCR video:6:view_count
redis-cli SET lock:task:6 abc123 NX EX 300

Python 示例:

python
redis_client.set("task:6:status", "RUNNING", ex=900)
redis_client.incr("video:6:view_count")

适合整体读写单个值、计数、验证码、登录态、分布式锁。

2. Hash:对象字段缓存 / 任务进度 / 用户信息 ​

场景概述: Hash 适合保存对象型数据并进行字段级更新。

图形化展示:

text
task:6:progress
  ├── stage   ──► IMAGE
  ├── percent ──► 45
  └── message ──► 正在生成分镜图

redis-cli 命令:

bash
redis-cli HSET task:6:progress stage IMAGE percent 45 message "正在生成分镜图"
redis-cli HGET task:6:progress stage
redis-cli HGETALL task:6:progress

Python 示例:

python
redis_client.hset("task:6:progress", mapping={"stage": "IMAGE", "percent": 45})
progress = redis_client.hgetall("task:6:progress")

适合一个对象有多个字段、并且经常局部更新。

3. List:队列 / 栈 / 最新列表 / 简单任务流 ​

场景概述: List 适合实现队列、栈和简单的消息流。

图形化展示:

text
task:queue
LPUSH 入队 -> [ task:9 ] -> [ task:8 ] -> [ task:7 ] -> [ task:6 ] <- BRPOP 出队

redis-cli 命令:

bash
redis-cli LPUSH task:queue 6
redis-cli BRPOP task:queue 5
redis-cli LRANGE user:1001:feeds 0 19

Python 示例:

python
redis_client.lpush("task:queue", 6)
result = redis_client.brpop("task:queue", timeout=5)

适合简单队列、最新列表、撤销栈。

4. Set:去重集合 / 标签 / 点赞 / 关系运算 ​

场景概述: Set 适合去重、标签关系和集合运算。

与 ZSet 的区别:

维度SetZSet
底层数据结构哈希表(dict)跳表(skiplist)+ 字典(dict)
是否去重是是
是否有序否是,按 score 排序
元素结构只有 membermember + score
典型用途去重、标签、共同关注排行榜、延迟队列、时间线
适合“只关心是否存在”是也可以,但通常没必要
适合“要按顺序取前 N 个”不适合很适合

Set 更像“成员名单”,ZSet 更像“带分数的排名名单”。

底层结构说明:

Set 内部通常使用哈希表存储成员,查找、插入、删除平均都是 O(1)。 ZSet 同时维护字典和跳表:字典负责快速按 member 查找,跳表负责按 score 排序和范围查询。

图形化展示:

text
video:6:liked_users
{ 1001, 1002, 1003, 1008 }

redis-cli 命令:

bash
redis-cli SADD video:6:liked_users 1001 1002 1003
redis-cli SISMEMBER video:6:liked_users 1001
redis-cli SINTER user:1:follows user:2:follows

Python 示例:

python
redis_client.sadd("video:6:liked_users", 1001, 1002, 1003)
liked = redis_client.sismember("video:6:liked_users", 1001)

适合去重、共同关注、抽奖用户池。

5. ZSet:排行榜 / 权重排序 / 延迟队列 / 时间线 ​

场景概述: ZSet 适合排行榜、延迟任务和按分值排序。

与 Set 的区别:

维度SetZSet
是否去重是是
是否有序否是,按 score 排序
元素结构只有 membermember + score
典型用途去重、标签、共同关注排行榜、延迟队列、时间线
取前 N 个元素只能随机或集合运算可以按分值直接取前 N 名

Set 更像“无序去重名单”,ZSet 更像“带分数的排序名单”。

字母 z 的来源:

ZSet 全名是 Sorted Set。Redis 早期命名时为了和 Set 区分,就在前面加了一个 z,表示 sorted,所以 zset 可以理解为“有序集合”。

为什么 ZADD 里 score 写在 member 前面?score 到底在第几位?

先厘清一个最关键的前提:“score 在第几位”取决于你用哪一层,同一个 ZSet 操作在不同客户端里的书写顺序是不一样的:

层写法score 的位置
Redis 原生命令ZADD key 98.5 video:8第 3 个 token 里的值(紧跟 key 后)
redis-cliZADD key score member排在 key 之后、member 之前
Python(redis-py)zadd(name, {member: score})字典的值(value),member 是键(key)

也就是说:在 Redis 命令层,score 排在 key 之后、member 之前;而在 Python 客户端里,score 反而成了字典的“值”,member 成了“键”。这两者不矛盾——原因是 Redis 命令用“位置”表达含义,redis-py 用“键值对”表达含义(member 必须唯一所以当键,score 作为它的值)。理解这一点,就不会纠结“到底谁在前”了。

下面重点解释命令层 ZADD key score member 为什么把 score 写在 member 前面:

  1. score 是排序依据(先决条件),member 是被排序对象(被挂上去的东西)。ZSet 的一切能力——排序、范围、排名——都靠 score 驱动。把 score 写在前面,语义是“先给一个分数,再把这个分数挂到某个 member 上”,读作“给 video:8 一个 98.5 分”,符合“依据在前、对象在后”的表达直觉。

  2. 固定「score + member」顺序,才能稳定解析批量写入。ZADD 支持一次写多组:ZADD key 98.5 video:8 91.0 video:3 76.5 video:6。每组都是「score、member」两两成对。解析器只需固定地“读一个 score、再读一个 member”循环到底,无需判断边界。若反过来改成「member、score」,在连续多组时解析器无法仅凭值本身判断哪里是一组的起点,必须额外依赖“score 只能是数字”去回溯,写起来更脆弱、也更容易出错。

  3. 与 ZSet 的底层实现呼应。ZSet 内部用跳表(skiplist)按 score 排序 + 字典(dict)按 member 定位。score 决定元素在有序结构里的“落点位置”,member 决定元素“是谁”。参数顺序让 score 先出现,正好对应“score 决定位置、member 决定身份”的职责分工。

一句话总结:命令层采用「score 在前、member 在后」,因为 score 是排序与定位的依据(放前)、member 是被排序的对象(放后),并且「score+member」成对且顺序固定,能让批量写入被稳定解析;而在 Python 客户端里,score 被放进字典的值、member 当键,只是同一语义换成了“键值对”形式来表达。

图形化展示:

text
rank:video:hot
98.5  ──► video:8
91.0  ──► video:3
76.5  ──► video:6

redis-cli 命令:

bash
redis-cli ZADD rank:video:hot 98.5 video:8 91.0 video:3 76.5 video:6
redis-cli ZREVRANGE rank:video:hot 0 9 WITHSCORES
redis-cli ZADD delay:order:cancel 1787797000 order:1001
redis-cli ZRANGEBYSCORE delay:order:cancel -inf 1787797060

Python 示例:

python
redis_client.zadd("delay:order:cancel", {"order:1001": 1787797000})
expired = redis_client.zrangebyscore("delay:order:cancel", "-inf", 1787797060)

适合排行榜、延迟任务、订单超时取消。

6. Stream:可靠消息流 / 消费组 / 事件日志 ​

场景概述: Stream 适合可靠消息流、消费组和事件追踪。

图形化展示:

text
stream:task
1690000000000-0  ──► task_id=6, stage=SCRIPT
1690000001000-0  ──► task_id=6, stage=IMAGE

redis-cli 命令:

bash
redis-cli XADD stream:task * task_id 6 stage SCRIPT
redis-cli XGROUP CREATE stream:task video-workers 0 MKSTREAM
redis-cli XREADGROUP GROUP video-workers worker-1 COUNT 10 BLOCK 5000 STREAMS stream:task >
redis-cli XACK stream:task video-workers 1690000000000-0

Python 示例:

python
redis_client.xadd("stream:task", {"task_id": "6", "stage": "SCRIPT"})

适合可靠消息流、事件日志、异步任务消费。

7. Bitmap:签到 / 活跃用户 / 布尔状态压缩存储 ​

场景概述: Bitmap 适合高密度布尔状态和签到统计。

图形化展示:

text
active:2026-08-27
用户偏移: 1001 1002 1003 1004
bit 值:     1    0    1    1

redis-cli 命令:

bash
redis-cli SETBIT active:2026-08-27 1001 1
redis-cli GETBIT active:2026-08-27 1001
redis-cli BITCOUNT active:2026-08-27

Python 示例:

python
redis_client.setbit("active:2026-08-27", 1001, 1)
count = redis_client.bitcount("active:2026-08-27")

适合签到、活跃用户、开关状态。

8. BitField:多个小整数状态压缩存储 ​

场景概述: BitField 适合压缩存储多个小整数状态。

图形化展示:

text
score:user:1001:2026-08
| day1 4bit | day2 4bit | day3 4bit |
|     8     |     6     |     9     |

redis-cli 命令:

bash
redis-cli BITFIELD score:user:1001:2026-08 SET u4 0 8 SET u4 4 6 GET u4 0 GET u4 4

Python 示例:

python
redis_client.execute_command("BITFIELD", "score:user:1001:2026-08", "SET", "u4", 0, 8)

适合评分、等级、小整数压缩。

9. HyperLogLog:大规模 UV 去重估算 ​

场景概述: HyperLogLog 适合大规模去重计数和 UV 估算。

图形化展示:

text
uv:video:6
1001, 1002, 1003, 1001, 1008, 1002
        └── HLL 估算唯一访问数

redis-cli 命令:

bash
redis-cli PFADD uv:video:6 1001 1002 1003
redis-cli PFCOUNT uv:video:6
redis-cli PFMERGE uv:site:range uv:day1 uv:day2

Python 示例:

python
redis_client.pfadd("uv:video:6", 1001, 1002, 1003)
uv = redis_client.pfcount("uv:video:6")

适合 UV 估算、访问人数统计。

10. GEO:附近的人 / 门店距离 / 地理位置查询 ​

场景概述: GEO 适合附近位置查询和距离计算。

图形化展示:

text
geo:stores
store:1 ──► (116.397128, 39.916527)
store:2 ──► (116.410000, 39.920000)

redis-cli 命令:

bash
redis-cli GEOADD geo:stores 116.397128 39.916527 store:1
redis-cli GEOSEARCH geo:stores FROMLONLAT 116.4 39.9 BYRADIUS 5 km WITHDIST
redis-cli GEODIST geo:stores store:1 store:2 km

Python 示例:

python
redis_client.geoadd("geo:stores", {"store:1": (116.397128, 39.916527)})

适合附近门店、同城服务、地理围栏。

11. Pub/Sub:实时发布订阅 / 通知广播 ​

场景概述: Pub/Sub 适合实时广播和轻量通知。

图形化展示:

text
PUBLISH config:changed
        ├── 订阅者 A
        ├── 订阅者 B
        └── 订阅者 C

redis-cli 命令:

bash
redis-cli SUBSCRIBE config:changed
redis-cli PUBLISH config:changed "video:max_workers"

Python 示例:

python
redis_client.publish("config:changed", "video:max_workers")

适合实时广播、配置变更通知。

12. RedisJSON:复杂 JSON 文档缓存 ​

场景概述: RedisJSON 适合嵌套 JSON 文档和局部更新。

图形化展示:

text
json:task:6:config
{ model, ratio, frames[] }

redis-cli 命令:

bash
redis-cli JSON.SET json:task:6:config $ '{"model":"seedance-2.0","ratio":"16:9"}'
redis-cli JSON.GET json:task:6:config $

Python 示例:

python
redis_client.execute_command("JSON.SET", "json:task:6:config", "$", '{"model":"seedance-2.0"}')

适合嵌套 JSON 配置、局部更新。

13. Bloom Filter:存在性预判 / 防缓存穿透 ​

场景概述: Bloom Filter 适合做存在性预判和缓存穿透防护。

图形化展示:

text
bf:goods:ids
已加入: goods:1001, goods:1002, goods:1003

redis-cli 命令:

bash
redis-cli BF.ADD bf:goods:ids goods:1001
redis-cli BF.EXISTS bf:goods:ids goods:1002

Python 示例:

python
redis_client.execute_command("BF.ADD", "bf:goods:ids", "goods:1001")
exists = redis_client.execute_command("BF.EXISTS", "bf:goods:ids", "goods:1002")

适合防缓存穿透、黑名单预判。

14. TimeSeries:监控指标 / 趋势数据 ​

场景概述: TimeSeries 适合记录时间序列指标和趋势。

图形化展示:

text
ts:queue:task:length
1787796000000 -> 12
1787796060000 -> 18

redis-cli 命令:

bash
redis-cli TS.ADD ts:queue:task:length * 12
redis-cli TS.RANGE ts:queue:task:length - +

Python 示例:

python
redis_client.execute_command("TS.ADD", "ts:queue:task:length", int(time.time() * 1000), 12)

适合队列长度、QPS、耗时趋势。

15. RedisSearch:全文检索 / 二级索引 / 多条件筛选 ​

场景概述: RedisSearch 适合全文检索、索引和组合筛选。

图形化展示:

text
idx:tasks
  ├── title 可搜
  ├── stage 可筛选
  └── user_id 可过滤

redis-cli 命令:

bash
redis-cli FT.CREATE idx:tasks ON HASH PREFIX 1 task:search: SCHEMA title TEXT stage TAG user_id NUMERIC
redis-cli FT.SEARCH idx:tasks "@stage:{IMAGE} 海边"

Python 示例:

python
redis_client.execute_command("FT.SEARCH", "idx:tasks", "@stage:{IMAGE} 海边")

适合全文检索和组合筛选。

16. Vector Search:向量相似度检索 ​

场景概述: Vector Search 适合相似检索和语义搜索。

图形化展示:

text
video:6 -> [0.12, 0.88, 0.31]
video:7 -> [0.10, 0.86, 0.35]
查询向量 q -> 找最相似的视频

redis-cli 命令:

bash
redis-cli FT.CREATE idx:vec ON HASH PREFIX 1 video: SCHEMA embedding VECTOR HNSW 6 TYPE FLOAT32 DIM 3 DISTANCE_METRIC COSINE
redis-cli FT.SEARCH idx:vec '*=>[KNN 3 @embedding $vec]' PARAMS 2 vec "..." SORTBY __vector_score DIALECT 2

Python 示例:

python
redis_client.execute_command("FT.SEARCH", "idx:vec", "*=>[KNN 3 @embedding $vec]")

适合相似视频推荐、语义搜索、RAG 检索。

17. Cuckoo Filter:可删除的存在性判断 ​

场景概述: Cuckoo Filter 适合可删除的去重和存在性判断。

图形化展示:

text
cf:task:ids
CF.ADD task:6
CF.EXISTS task:6
CF.DEL task:6

redis-cli 命令:

bash
redis-cli CF.ADD cf:task:ids task:6
redis-cli CF.EXISTS cf:task:ids task:6
redis-cli CF.DEL cf:task:ids task:6

Python 示例:

python
redis_client.execute_command("CF.ADD", "cf:task:ids", "task:6")

适合可删除去重、临时黑名单。

18. Count-Min Sketch:大规模频次估算 ​

场景概述: Count-Min Sketch 适合大规模频次估算。

图形化展示:

text
cms:keywords
redis -> 12000
video -> 8500
worker -> 4300

redis-cli 命令:

bash
redis-cli CMS.INCRBY cms:keywords redis 1 video 1 worker 1
redis-cli CMS.QUERY cms:keywords redis video worker

Python 示例:

python
redis_client.execute_command("CMS.INCRBY", "cms:keywords", "redis", 1)

适合热点词、频次趋势。

19. TopK:高频元素近似统计 ​

场景概述: TopK 适合近似统计高频元素。

图形化展示:

text
topk:videos
video:8, video:6, video:3, video:12, video:1

redis-cli 命令:

bash
redis-cli TOPK.RESERVE topk:videos 5
redis-cli TOPK.ADD topk:videos video:8 video:6 video:3
redis-cli TOPK.LIST topk:videos

Python 示例:

python
redis_client.execute_command("TOPK.ADD", "topk:videos", "video:8", "video:6")

适合热门视频、热门词榜单。

20. TDigest:分位数统计 / P95 / P99 ​

场景概述: TDigest 适合分位数和延迟分布统计。

图形化展示:

text
td:video:duration
样本 -> P50 / P95 / P99

redis-cli 命令:

bash
redis-cli TDIGEST.CREATE td:video:duration
redis-cli TDIGEST.ADD td:video:duration 2.1 2.4 3.0 8.2 15.6 30.1
redis-cli TDIGEST.QUANTILE td:video:duration 0.95

Python 示例:

python
redis_client.execute_command("TDIGEST.ADD", "td:video:duration", 2.1, 2.4, 3.0)

适合延迟分布、耗时分位数。

15. 使用场景中函数参数含义速查 ​

第十章中的示例代码涉及较多 Redis 命令和 Python 辅助函数。阅读这些案例时,重点不是只记住函数名,而是理解每个参数对应 Redis 中的 key、value、field、score、member、offset、过期时间或消费组语义。

String / 通用 key 操作

函数示例参数含义
redis_client.set(name, value, ex=None, nx=False)set("task:6:status", "RUNNING", ex=900)name 是 Redis key;value 是要保存的值;ex 是秒级过期时间;nx=True 表示 key 不存在时才写入,常用于分布式锁
redis_client.get(name)get("task:6:status")name 是要读取的 Redis key,返回该 key 当前保存的 value
redis_client.incr(name, amount=1)incr("video:6:view_count")name 是计数器 key;amount 是递增步长,默认加 1
redis_client.expire(name, time)expire(key, 60)name 是要设置过期时间的 key;time 是过期秒数
redis_client.delete(*names)delete(lock_key)names 是一个或多个要删除的 key。分布式锁中不建议直接删除,容易误删别人的锁
redis_client.eval(script, numkeys, *keys_and_args)eval(UNLOCK_SCRIPT, 1, lock_key, lock_token)script 是 Lua 脚本;numkeys 表示后面有几个参数属于 Redis key;前 numkeys 个参数进入 Lua 的 KEYS;剩余参数进入 Lua 的 ARGV

Hash 操作

函数示例参数含义
redis_client.hset(name, key=None, value=None, mapping=None)hset("task:6:progress", "stage", "IMAGE")name 是 Hash key;key 是字段名 field;value 是字段值;mapping 可一次写入多个 field-value
redis_client.hget(name, key)hget(f"order:{oid}", "status")name 是 Hash key;key 是要读取的字段名
redis_client.hgetall(name)hgetall("task:6:progress")name 是 Hash key,返回这个 Hash 下所有 field-value
redis_client.hincrby(name, key, amount=1)hincrby("cart:user:1001", "goods:2001", 1)name 是 Hash key;key 是字段名;amount 是该字段的整数增量

List 操作

函数示例参数含义
redis_client.lpush(name, *values)lpush("task:queue", 6)name 是 List key;values 是要从左侧压入的一个或多个元素
redis_client.brpop(keys, timeout=0)brpop("task:queue", timeout=5)keys 是一个 key 或多个 key;timeout 是最大阻塞等待秒数,0 表示一直等待
redis_client.lrange(name, start, end)lrange("user:1001:feeds", 0, 19)name 是 List key;start 是起始下标;end 是结束下标,包含该位置,-1 表示最后一个元素
redis_client.ltrim(name, start, end)ltrim("user:1001:feeds", 0, 19)name 是 List key;只保留 start 到 end 范围内的元素,常用于限制最新列表长度
redis_client.lpop(name)lpop("undo:user:1001")name 是 List key,从左侧弹出一个元素
redis_client.llen(name)llen("task:queue")name 是 List key,返回列表长度

Set 操作

函数示例参数含义
redis_client.sadd(name, *values)sadd("video:6:liked_users", 1001)name 是 Set key;values 是要加入集合的成员,重复成员会自动去重
redis_client.sismember(name, value)sismember("video:6:liked_users", 1001)name 是 Set key;value 是要判断是否存在的成员
redis_client.scard(name)scard("video:6:liked_users")name 是 Set key,返回集合成员数量
redis_client.sinter(keys, *args)sinter("user:1:follows", "user:2:follows")参数是多个 Set key,返回这些集合的交集
redis_client.srandmember(name, number=None)srandmember("lottery:202608:users", 2)name 是 Set key;number 是随机返回的成员数量

ZSet 操作

函数示例参数含义
redis_client.zadd(name, mapping)zadd("delay:order:cancel", {order_id: expire_at})name 是 ZSet key;mapping 是 {member: score} 字典,member 是成员,score 是排序分数
redis_client.zincrby(name, amount, value)zincrby("rank:video:hot", 1, "video:6")name 是 ZSet key;amount 是分数增量;value 是要增加分数的成员
redis_client.zrevrange(name, start, end, withscores=False)zrevrange("rank:video:hot", 0, 9, withscores=True)name 是 ZSet key;start/end 是排名范围;withscores=True 表示同时返回 score
redis_client.zrevrank(name, value)zrevrank("rank:video:hot", "video:6")name 是 ZSet key;value 是成员,返回从高到低排序时的名次
redis_client.zrangebyscore(name, min, max, start=None, num=None)zrangebyscore("delay:tasks", 0, now, start=0, num=10)name 是 ZSet key;min/max 是 score 范围;start 是偏移量;num 是最多返回数量
redis_client.zrem(name, *values)zrem("delay:order:cancel", oid)name 是 ZSet key;values 是要删除的成员。多 Worker 场景中,谁 ZREM 成功谁获得处理权

Stream 操作

函数示例参数含义
redis_client.xadd(name, fields, id="*")xadd("stream:task", {"task_id": "6"})name 是 Stream key;fields 是消息字段字典;id="*" 表示 Redis 自动生成消息 ID
redis_client.xgroup_create(name, groupname, id="0", mkstream=False)xgroup_create("stream:task", "video-workers", id="0", mkstream=True)name 是 Stream key;groupname 是消费组名;id 表示从哪个消息 ID 开始消费;mkstream=True 表示 Stream 不存在时自动创建
redis_client.xreadgroup(groupname, consumername, streams, count=None, block=None)xreadgroup("video-workers", "worker-1", {"stream:task": ">"}, count=10, block=5000)groupname 是消费组;consumername 是消费者名;streams 指定要读的 Stream 和起始 ID;count 是最多读取条数;block 是阻塞等待毫秒数
redis_client.xack(name, groupname, *ids)xack("stream:task", "video-workers", message_id)name 是 Stream key;groupname 是消费组;ids 是要确认完成的消息 ID
redis_client.xrange(name, min="-", max="+")xrange("stream:video:event", min="-", max="+")name 是 Stream key;min/max 是消息 ID 范围,- 表示最早,+ 表示最新

Bitmap / BitField 操作

函数示例参数含义
redis_client.setbit(name, offset, value)setbit("active:2026-08-27", 1001, 1)name 是 Bitmap key;offset 是 bit 下标;value 只能是 0 或 1
redis_client.getbit(name, offset)getbit("signin:2026-08:user:1001", day_index)name 是 Bitmap key;offset 是要读取的 bit 下标
redis_client.bitcount(key)bitcount("active:2026-08-27")key 是 Bitmap key,返回值为 1 的 bit 数量
redis_client.bitop(operation, dest, *keys)bitop("AND", "active:and", "active:day1", "active:day2")operation 是位运算类型,如 AND/OR/XOR/NOT;dest 是结果 key;keys 是参与运算的源 key
redis_client.bitfield(key, *args)bitfield("score:user:1001:2026-08", "SET", "u4", 26 * 4, 9)key 是底层字符串 key;args 是 BitField 子命令序列,例如 SET/GET、整数类型 u4、bit 偏移量和写入值

HyperLogLog / GEO / Pub/Sub 操作

函数示例参数含义
redis_client.pfadd(name, *values)pfadd("uv:video:6", 1001, 1002, 1003)name 是 HyperLogLog key;values 是要参与去重估算的元素
redis_client.pfcount(*sources)pfcount("uv:video:6")sources 是一个或多个 HyperLogLog key,返回不重复数量估算值
redis_client.pfmerge(dest, *sources)pfmerge("uv:site:range", "uv:day1", "uv:day2")dest 是合并后的目标 key;sources 是要合并的多个 HyperLogLog key
redis_client.geoadd(name, values)geoadd("geo:stores", [116.397128, 39.916527, "store:1"])name 是 GEO key;values 按经度、纬度、成员名传入
redis_client.geosearch(name, longitude=None, latitude=None, member=None, radius=None, unit="m")geosearch("geo:stores", longitude=116.4, latitude=39.9, radius=5, unit="km")name 是 GEO key;可用经纬度或已有成员作为中心点;radius 是半径;unit 是距离单位
redis_client.geodist(name, place1, place2, unit=None)geodist("geo:stores", "store:1", "store:2", unit="km")name 是 GEO key;place1/place2 是两个成员;unit 是返回距离单位
redis_client.publish(channel, message)publish("config:changed", "video:max_workers")channel 是频道名;message 是要发布的消息内容
redis_client.pubsub()pubsub()创建一个 Pub/Sub 订阅对象,后续可通过该对象订阅频道并读取消息

Redis Stack / 模块命令

函数示例参数含义
redis_client.execute_command("JSON.SET", key, path, value)execute_command("JSON.SET", "json:task:6:config", ".", json_text)第 1 个参数是模块命令名;key 是 JSON key;path 是 JSON 路径;value 是要写入的 JSON 字符串
redis_client.execute_command("JSON.GET", key, path)execute_command("JSON.GET", "json:task:6:config", ".")key 是 JSON key;path 是要读取的 JSON 路径
redis_client.execute_command("BF.ADD", key, item)execute_command("BF.ADD", "bf:goods:ids", "goods:2001")key 是 Bloom Filter key;item 是要加入过滤器的元素
redis_client.execute_command("BF.EXISTS", key, item)execute_command("BF.EXISTS", "bf:goods:ids", "goods:9999")key 是 Bloom Filter key;item 是要判断是否可能存在的元素
redis_client.execute_command("TS.ADD", key, timestamp, value)execute_command("TS.ADD", "ts:queue:task:length", ts, queue_length)key 是时间序列 key;timestamp 是毫秒时间戳;value 是指标值
redis_client.execute_command("TS.RANGE", key, from_ts, to_ts, ...)execute_command("TS.RANGE", "ts:queue:task:length", "-", "+")key 是时间序列 key;from_ts/to_ts 是时间范围,- 到 + 表示全量范围
redis_client.execute_command("FT.CREATE", index, ...)execute_command("FT.CREATE", "idx:task", "ON", "HASH", ...)index 是索引名;后续参数定义索引数据来源、前缀、字段类型和排序规则
redis_client.execute_command("FT.SEARCH", index, query, ...)execute_command("FT.SEARCH", "idx:task", "@stage:{IMAGE}")index 是索引名;query 是查询表达式;后续参数可指定排序、分页、返回字段等
redis_client.execute_command("CF.ADD", key, item)execute_command("CF.ADD", "cf:task:ids", "task:6")key 是 Cuckoo Filter key;item 是要加入的元素
redis_client.execute_command("CF.EXISTS", key, item)execute_command("CF.EXISTS", "cf:task:ids", "task:6")key 是 Cuckoo Filter key;item 是要判断是否可能存在的元素
redis_client.execute_command("CF.DEL", key, item)execute_command("CF.DEL", "cf:task:ids", "task:6")key 是 Cuckoo Filter key;item 是要从过滤器中删除的元素
redis_client.execute_command("CMS.INCRBY", key, item, increment)execute_command("CMS.INCRBY", "cms:keywords", "redis", 3)key 是 Count-Min Sketch key;item 是统计对象;increment 是增加次数
redis_client.execute_command("CMS.QUERY", key, *items)execute_command("CMS.QUERY", "cms:keywords", "video", "redis")key 是 Count-Min Sketch key;items 是要查询频次的多个元素
redis_client.execute_command("TOPK.RESERVE", key, k, width, depth, decay)execute_command("TOPK.RESERVE", "topk:videos", 10, 2000, 7, 0.9)key 是 TopK key;k 是保留前多少名;width/depth/decay 控制近似统计的空间、精度和衰减策略
redis_client.execute_command("TOPK.ADD", key, *items)execute_command("TOPK.ADD", "topk:videos", "video:1")key 是 TopK key;items 是要计入高频统计的元素
redis_client.execute_command("TOPK.LIST", key)execute_command("TOPK.LIST", "topk:videos")key 是 TopK key,返回当前近似 TopK 列表
redis_client.execute_command("TDIGEST.CREATE", key)execute_command("TDIGEST.CREATE", "td:video:duration")key 是 TDigest key,用于保存分位数统计结构
redis_client.execute_command("TDIGEST.ADD", key, value)execute_command("TDIGEST.ADD", "td:video:duration", 12.5)key 是 TDigest key;value 是要加入统计的数值样本
redis_client.execute_command("TDIGEST.QUANTILE", key, quantile)execute_command("TDIGEST.QUANTILE", "td:video:duration", 0.95)key 是 TDigest key;quantile 是分位点,例如 0.95 表示 P95

Python 辅助函数

函数示例参数含义
time.time()int(time.time()) + 300不需要参数,返回当前 Unix 时间戳,单位是秒,常用于计算延迟任务执行时间
int(value)int(time.time())value 是要转换成整数的值,常用于把时间戳或 Redis 返回的字符串任务 ID 转成整数
str(value)str(uuid.uuid4())value 是要转换成字符串的对象,分布式锁中用于把 UUID 转成可保存的 token 字符串
uuid.uuid4()uuid.uuid4()不需要参数,生成随机 UUID,适合作为分布式锁的唯一 lock_token

16. 本项目中的推荐使用方式 ​

结合当前视频任务系统,可以这样选择:

业务数据推荐结构原因
待处理任务队列ListLPUSH + BRPOP 简单、高效,适合 Worker 阻塞消费
任务执行进度Hash可以单独更新 stage、percent、message 等字段
任务状态缓存String / Hash简单状态用 String,多字段状态用 Hash
用户提交频率限制String使用 INCR + EXPIRE 实现限流计数
视频播放量String使用 INCR 做计数器
视频点赞用户Set自动去重,方便判断用户是否点过赞
视频热度排行ZSet用热度分或播放量作为 score 排序
延迟重试任务ZSet / Stream简单延迟用 ZSet,需要 ACK 和恢复用 Stream
可靠事件日志Stream如果后续需要 ACK、重试、消费组,可从 List 升级到 Stream
在线配置广播Pub/Sub通知在线服务刷新配置,消息不需要持久化
队列积压趋势TimeSeries / 普通指标系统如果需要趋势图和聚合,可以记录时间序列
防止无效 ID 穿透数据库Bloom Filter大规模 ID 存在性预判,减少无效 DB 查询

17. 选型口诀表 ​

需求关键词优先选择典型命令示例场景注意点
一个 key 存一个完整值StringSET、GET、EXPIRE验证码、登录 token、任务状态缓存适合整体读写,不适合频繁局部更新对象字段
原子计数、自增自减StringINCR、DECR、INCRBY播放量、点赞数、接口调用次数计数器可以配合 EXPIRE 做限流窗口
一个对象有多个字段HashHSET、HGET、HGETALL用户资料、任务进度、视频元信息适合字段级更新,不适合按字段值排序
简单队列、阻塞消费ListLPUSH、BRPOP视频任务队列、异步任务分发适合简单队列,不支持 ACK 和消费组
最新列表、操作历史ListLPUSH、LRANGE、LTRIM最新动态、最近操作、撤销栈要配合 LTRIM 控制列表长度
去重、判断是否存在SetSADD、SISMEMBER、SCARD点赞用户、抽奖参与用户、黑名单无序集合,不适合按时间或分数排序
集合关系运算SetSINTER、SUNION、SDIFF共同关注、共同标签、权限对比数据量很大时要注意集合运算成本
排名、权重、分数排序ZSetZADD、ZREVRANGE、ZREVRANK视频热榜、用户积分榜、优先级队列score 是排序核心,更新频繁时要评估写入成本
时间戳排序、延迟执行ZSetZADD、ZRANGEBYSCORE、ZREM延迟任务、最近访问、定时重试多 Worker 取任务时要用 ZREM 或 Lua 保证不重复执行
可靠消息、消费组、ACKStreamXADD、XREADGROUP、XACK可靠任务队列、订单事件、视频生成事件流比 List 复杂,但支持 pending、ACK 和故障恢复
大量是/否状态BitmapSETBIT、GETBIT、BITCOUNT用户签到、日活统计、功能灰度offset 要可控,稀疏大 ID 可能浪费空间
多个小整数状态压缩BitFieldBITFIELD每日评分、设备状态档位、小型状态机可读性较差,适合内存极度敏感场景
只统计不重复数量,不关心成员HyperLogLogPFADD、PFCOUNT、PFMERGE网站 UV、视频 UV、活动访问人数结果是估算值,不能列出具体成员
经纬度附近查询GEOGEOADD、GEOSEARCH、GEODIST附近门店、附近设备、同城资源适合基础附近查询,不替代专业 GIS
在线实时广播Pub/SubPUBLISH、SUBSCRIBE配置变更通知、WebSocket 网关广播消息不持久化,订阅者离线会丢消息
复杂 JSON 局部更新RedisJSONJSON.SET、JSON.GET复杂配置、用户画像、商品详情缓存需要 RedisJSON 模块支持,标准 Redis 默认没有
大规模存在性预判Bloom FilterBF.ADD、BF.EXISTS防缓存穿透、URL 去重、风险名单预判有误判率,不能替代精确集合
指标趋势和时间范围查询TimeSeriesTS.ADD、TS.RANGE队列长度趋势、接口 QPS、任务耗时监控需要 RedisTimeSeries 模块支持,也可交给专业监控系统