Redis数据结构速通

0 阅读15分钟

Redis 可以简单理解为:从单值缓存,到消息流、稀疏数组、全文检索、向量检索、概率统计,Redis 已经是一整套内存数据引擎。

本文按最新官方命令文档整理,扩展结构如 JSON、Search、Time Series、Bloom、Vector Set 也以官方命令文档为准。

下面不绕概念,直接看结构、命令、场景和取舍。

先看选型

  • String:单值缓存、计数器、令牌、会话、验证码、限流。
  • Hash:用户资料、订单头信息、购物车摘要、字段局部更新。
  • List:FIFO 队列、最近 N 条消息、操作日志尾部。
  • Set:去重、白名单、标签、交并差集合运算。
  • Sorted Set:排行榜、优先级队列、延时任务、分数区间筛选。
  • Stream:可回放消息、消费组、重试、积压处理。
  • Array:固定下标、稀疏槽位、位置映射。
  • Bitmap / Bitfield:大规模布尔标记、紧凑小计数器。
  • HyperLogLog:海量 UV 近似去重统计。
  • Geo:附近门店、附近骑手、距离计算。
  • JSON:复杂文档、嵌套对象、局部路径更新。
  • Time Series:指标、传感器数据、时间窗口聚合。
  • Search:全文检索、标签过滤、数值过滤、混合查询。
  • Vector Set:相似内容、语义召回、向量近邻搜索。
  • Bloom / CMS / TopK / t-digest:近似判重、热点检测、频次估算、分位数统计。

核心数据结构

String

  • 说明:Redis 最基础的类型。文本、JSON 串、二进制、整数计数器,本质上都可以先落到 String。
  • 常用命令:SETGETGETEXGETDELINCRINCREX
SET session:user:1001 "{\"name\":\"Alice\",\"level\":\"vip\"}" EX 1800
GET session:user:1001
GETEX session:user:1001 EX 1800

SET order:seq 1000
INCR order:seq

INCREX login:fail:user:1001 BYINT 1 UBOUND 5 EX 600 SATURATE
GET login:fail:user:1001
  • 现实场景:登录会话、短信验证码、接口幂等 token、订单流水号、失败次数限流。
  • 什么时候别用:字段很多、经常只改其中一项时,Hash 更省心。

Hash

  • 说明:把一个业务对象塞进一个 key 里,每个属性一个 field。
  • 常用命令:HSETHMGETHGETALLHINCRBYHEXPIREHSCAN
  • Redis 现在还支持字段级过期(如 HEXPIRE)和 Hash subkey notifications,适合“对象局部状态”。
HSET user:1001 name Alice level vip city shanghai points 200
HMGET user:1001 name level city
HINCRBY user:1001 points 50
HGETALL user:1001
  • 现实场景:用户资料、商家信息、订单头、店铺配置、购物车摘要。
  • 什么时候别用:正文很大、结构层级很深、经常按嵌套路径改值时,JSON 更合适。

List

  • 说明:有顺序的字符串列表,擅长头尾 push/pop 和阻塞式消费。
  • 常用命令:LPUSHRPUSHLPOPRPOPBRPOPLTRIM
LPUSH queue:pay order:1001 order:1002 order:1003
BRPOP queue:pay 0

LPUSH feed:user:1001 post:501 post:502 post:503
LTRIM feed:user:1001 0 99
LRANGE feed:user:1001 0 9
  • 现实场景:简单异步队列、最近浏览记录、最近评论、消息时间线。
  • 什么时候别用:如果你需要 ack、重试、消费组、待处理消息列表,直接上 Stream。

Set

  • 说明:无序、唯一。核心价值不是“存一堆值”,而是“天然去重 + 集合运算”。
  • 常用命令:SADDSISMEMBERSMEMBERSSINTERSUNIONSDIFF
SADD tag:article:1001 redis cache database
SISMEMBER tag:article:1001 redis

SADD campaign:618:eligible user:1001 user:1002 user:1003
SADD vip:users user:1002 user:1004
SINTER campaign:618:eligible vip:users
  • 现实场景:活动参与名单、黑白名单、文章标签、去重 ID 集、共同兴趣人群。
  • 什么时候别用:如果要排序、按权重打分、做前 N 名,Sorted Set 更合适。

Sorted Set

  • 说明:唯一成员 + 分数排序,是 Redis 最常用的业务结构之一。
  • 常用命令:ZADDZINCRBYZRANGEZREVRANGEZREMZUNIONZINTER
  • 聚合命令也比较完整,适合排行榜和聚合分析。
ZADD ranking:sales 120 sku:1001 95 sku:1002 88 sku:1003
ZINCRBY ranking:sales 10 sku:1002
ZREVRANGE ranking:sales 0 9 WITHSCORES

ZADD task:delay 1748323200 order:1001 1748323260 order:1002
ZRANGEBYSCORE task:delay -inf 1748323200
  • 现实场景:销量榜、积分榜、直播打赏榜、定时发布、延时重试、价格排序。
  • 什么时候别用:如果只是单纯 membership 判断,没有排序需求,Set 更轻。

Stream

  • 说明:Redis 的消息流结构,支持消息 ID、消费组、pending、重试和回放。
  • 常用命令:XADDXGROUP CREATEXREADGROUPXPENDINGXACKXAUTOCLAIMXNACK
  • XNACK 很实用,可以显式释放失败消息,让它立刻变成可 claim 状态。
XADD order_stream * orderId 1001 status created amount 199
XGROUP CREATE order_stream order_group 0 MKSTREAM
XREADGROUP GROUP order_group worker-1 COUNT 1 BLOCK 0 STREAMS order_stream >
XPENDING order_stream order_group
XACK order_stream order_group 1710000000000-0

XNACK order_stream order_group FAIL IDS 1 1710000000000-0
  • 现实场景:订单异步处理、发票队列、退款任务、库存同步、物流状态流。
  • 什么时候别用:如果只是“在线时收到一下就行”,不要求补发和重试,Pub/Sub 更轻。

Array

  • 说明:Array 适合“按固定下标访问,但又允许稀疏槽位”的数据,元素类型是字符串,目前官方仍标注为 preview。
  • 常用命令:ARSETARGETARLENARCOUNTARINFO
  • 核心语义要记住两点:ARLEN 是最大下标 + 1,ARCOUNT 是实际有值的元素数量。
ARSET seatmap:bus:1001 0 A1 A2 A3
ARSET seatmap:bus:1001 5 A6

ARGET seatmap:bus:1001 0
ARGET seatmap:bus:1001 5
ARLEN seatmap:bus:1001
ARCOUNT seatmap:bus:1001
ARINFO seatmap:bus:1001
  • 现实场景:客运和影院选座、停车位编号、快递柜格口、仓库货位、固定编号状态表。
  • 什么时候别用:如果元素本身还是复杂对象、需要嵌套字段和条件更新,JSON 通常更顺手。

Bitmap

  • 说明:Bitmap 不是单独存储引擎,本质上还是 String,只是把它当 bit 数组来用。
  • 常用命令:SETBITGETBITBITCOUNTBITOP
SETBIT checkin:2026-05-27 1001 1
SETBIT checkin:2026-05-27 1002 1
GETBIT checkin:2026-05-27 1001
BITCOUNT checkin:2026-05-27
  • 现实场景:签到、是否已读、是否开通过功能、广告是否看过、风控命中标记。
  • 什么时候别用:用户 ID 非常离散、偏移量跨度极大时,Bitmap 可能浪费空间。

Bitfield

  • 说明:如果 Bitmap 适合存布尔值,Bitfield 更适合把一个字符串切成很多小整数字段。
  • 常用命令:BITFIELDBITFIELD_RO
BITFIELD ad:freq:user:1001 INCRBY u8 0 1
BITFIELD ad:freq:user:1001 INCRBY u8 8 1
BITFIELD ad:freq:user:1001 GET u8 0 GET u8 8
  • 现实场景:同一用户多个页面的曝光次数、小型计数槽位、紧凑状态位打包。
  • 什么时候别用:字段要经常增删改名、需要可读性时,Hash 更直接。

扩展数据结构

HyperLogLog

  • 说明:用极小内存做“近似去重计数”,适合 UV 之类“不要求绝对精确”的场景。
  • 常用命令:PFADDPFCOUNTPFMERGE
PFADD uv:2026-05-27 user:1001 user:1002 user:1003
PFADD uv:2026-05-27 user:1002
PFCOUNT uv:2026-05-27
PFMERGE uv:2026-05-all uv:2026-05-26 uv:2026-05-27
  • 现实场景:日 UV、周 UV、活动触达人数、广告去重曝光人数。
  • 什么时候别用:如果你要精确名单,Set 才是答案。

Geo

  • 说明:Geo 用经纬度做空间索引,底层和 Sorted Set 关系很近,但命令层面对距离和范围查询更友好。
  • 常用命令:GEOADDGEODISTGEOSEARCH
GEOADD driver:online 116.397 39.908 driver:1001 116.405 39.920 driver:1002
GEODIST driver:online driver:1001 driver:1002 km
GEOSEARCH driver:online FROMLONLAT 116.397 39.908 BYRADIUS 3 km WITHDIST COUNT 10 ASC
  • 现实场景:附近门店、附近骑手、最近仓库、就近服务网点。
  • 什么时候别用:如果你要复杂多边形 GIS 分析,专业地理引擎更合适。

JSON

  • 说明:JSON 适合直接存复杂文档,按路径读写,比把整个对象序列化成 String 更灵活。
  • 常用命令:JSON.SETJSON.GETJSON.MGETJSON.NUMINCRBY
  • JSON.SET 也支持 FPHA,适合齐次浮点数组这样的场景。
JSON.SET product:1001 $ '{"title":"耳机","stock":10,"price":199,"tags":["audio","wireless"]}'
JSON.GET product:1001 $
JSON.NUMINCRBY product:1001 $.stock -1
JSON.GET product:1001 $.stock
  • 现实场景:商品详情、CMS 内容块、动态配置、带嵌套结构的业务对象。
  • 什么时候别用:高频计数、单字段热点更新,Hash 和 String 通常更快更直。

Time Series

  • 说明:Time Series 专门处理“时间戳 + 数值”的连续数据,天然适合聚合、保留期、标签过滤。
  • 常用命令:TS.CREATETS.ADDTS.RANGETS.MRANGE
  • 单序列看 TS.RANGE,多序列按标签聚合看 TS.MRANGE;两者都支持聚合,能减少客户端额外处理。
TS.CREATE metrics:order:qps RETENTION 86400000 LABELS biz order env prod
TS.ADD metrics:order:qps * 128
TS.ADD metrics:order:qps * 136
TS.RANGE metrics:order:qps - + AGGREGATION avg 60000
  • 现实场景:接口 QPS、延迟曲线、设备温度、支付成功率、库存波动。
  • 什么时候别用:如果存的是业务正文、对象字段,不要硬塞进时序结构。

Search

  • 说明:Search 负责全文检索、标签过滤、数值过滤和复杂查询组合。
  • 常用命令:FT.CREATEFT.SEARCHFT.AGGREGATE
  • FT.HYBRIDFT.PROFILE 在混合检索场景更好调优。
FT.CREATE idx:article ON HASH PREFIX 1 article: SCHEMA title TEXT tags TAG publishAt NUMERIC
HSET article:1001 title "Redis 实战" tags "redis,cache" publishAt 1748313600
HSET article:1002 title "Bun 性能笔记" tags "bun,backend" publishAt 1748227200
FT.SEARCH idx:article "Redis @tags:{redis}"
  • 现实场景:文章搜索、商品筛选、企业知识库、后台管理搜索页。
  • 什么时候别用:如果只是精确按 key 读取,普通 GET / HGET 更快。

Vector Set

  • 说明:Vector Set 用来存向量,并直接做相似度检索。
  • 常用命令:VADDVSIMVSETATTRVGETATTR
  • 这套命令已经比较完整,适合把“向量存储 + 相似检索”直接放在 Redis 里。
VADD user_embeddings VALUES 3 0.12 0.87 0.33 user:1001
VADD user_embeddings VALUES 3 0.10 0.84 0.30 user:1002
VADD user_embeddings VALUES 3 0.91 0.08 0.11 user:1003
VSIM user_embeddings ELE user:1001 WITHSCORES COUNT 3
  • 现实场景:相似商品、相似内容、语义召回、相似用户推荐、文档 embedding 检索。
  • 什么时候别用:如果只是精确过滤或普通全文搜索,没必要引入向量结构。

Bloom Filter

  • 说明:Bloom Filter 用极低内存做“这个元素大概率见过 / 没见过”的判断。
  • 常用命令:BF.RESERVEBF.ADDBF.EXISTS
  • 它会有误判,但误判方向只有一种:可能把“没见过”说成“见过了”。
BF.RESERVE signup:seen 0.001 100000
BF.ADD signup:seen user:1001
BF.ADD signup:seen user:1002
BF.EXISTS signup:seen user:1001
BF.EXISTS signup:seen user:9999
  • 现实场景:注册链接去重、爬虫 URL 去重、短期风控黑名单快速判断。
  • 什么时候别用:如果必须精确删除和精确判断,Set 或 Cuckoo Filter 更合适。

Count-Min Sketch

  • 说明:Count-Min Sketch 适合做海量频次估算,结果可能偏大,但不会偏小。
  • 常用命令:CMS.INITBYDIMCMS.INCRBYCMS.QUERY
CMS.INITBYDIM freq:query 2000 5
CMS.INCRBY freq:query redis 1 mysql 1 redis 2 bun 5
CMS.QUERY freq:query redis mysql bun
  • 现实场景:搜索词热度、接口访问热度、广告词点击频次、热点 SKU 预估。
  • 什么时候别用:如果你要精确排名和精确数值,普通计数器或数据库聚合更稳。

Top-K

  • 说明:Top-K 用近似算法持续追踪最热的前 K 个元素。
  • 常用命令:TOPK.RESERVETOPK.ADDTOPK.LISTTOPK.QUERY
TOPK.RESERVE hot:search 5 2000 7 0.925
TOPK.ADD hot:search redis mysql redis ai redis bun bun bun
TOPK.LIST hot:search
TOPK.QUERY hot:search redis java
  • 现实场景:热搜词、热点商品、热门 API、热门页面、热门错误码。
  • 什么时候别用:如果你要完整长尾明细和精确排序,Sorted Set 更直接。

t-digest

  • 说明:t-digest 适合看分位数,比如 p95、p99 这种“尾延迟”。
  • 常用命令:TDIGEST.CREATETDIGEST.ADDTDIGEST.QUANTILE
TDIGEST.CREATE latency:pay COMPRESSION 100
TDIGEST.ADD latency:pay 12 18 20 32 35 60 75 110
TDIGEST.QUANTILE latency:pay 0.5 0.95 0.99
  • 现实场景:接口延迟、支付耗时、物流签收时长、客服响应时长。
  • 什么时候别用:如果样本量很小、必须每个值都能回查,直接存原始数据更好。

Redis 的关键特性

过期与 TTL

  • 说明:TTL 是 Redis 最常用的能力之一,缓存、验证码、草稿、锁、限流都离不开它。
  • 常用命令:EXPIRETTLPERSISTGETEXGETDEL
  • 要注意:expired 事件是在 key 真正被删除时触发,不是理论上 TTL 归零那一刻。
SET otp:login:13800000000 731952 EX 300
TTL otp:login:13800000000

SET order:draft:1001 "{\"status\":\"draft\"}"
EXPIRE order:draft:1001 1800
PERSIST order:draft:1001
  • 现实场景:验证码、购物车保留、临时锁、草稿单、活动倒计时状态。

Pub/Sub

  • 说明:Pub/Sub 是实时广播,不做持久化,不做补发,语义是 at-most-once。
  • 常用命令:PUBLISHSUBSCRIBEPSUBSCRIBESPUBLISHSSUBSCRIBE
  • 在集群里可以用分片 Pub/Sub,把频道按 slot 分发到对应 shard。
SUBSCRIBE notice:order
PUBLISH notice:order "order:1001 created"

SSUBSCRIBE stock:{sku:1001}
SPUBLISH stock:{sku:1001} "stock changed"
  • 现实场景:在线通知、聊天室、直播弹幕、实时看板推送。
  • 什么时候别用:订单、退款、发票这类不能丢消息的核心流程,不要只靠 Pub/Sub。

Keyspace Notifications

  • 说明:Keyspace Notifications 让 Redis 自己把 key 的变更事件发出来。
  • 常用命令:CONFIG SET notify-keyspace-events ...PSUBSCRIBE
  • 要注意:这是通知,不是可靠消息;集群里也是节点本地事件,不会自动全局汇总。
CONFIG SET notify-keyspace-events KEA
PSUBSCRIBE __key*__:*

SET order:1001 paid
EXPIRE order:1001 600
  • 现实场景:缓存失效广播、审计埋点、增量同步、后台监控。
  • 现在也有 Hash subkey notifications,会把受影响的 field 名一起带出来,适合只同步某个 field 的变化。

事务与 WATCH

  • 说明:Redis 事务是 MULTI / EXEC,配合 WATCH 做乐观锁。
  • 要点:Redis 没有传统数据库那种回滚语义,失败时更像“整批没执行”或“执行时报错”。
  • 如果逻辑复杂,Lua / Functions 往往比客户端拼事务更直接。
WATCH stock:sku:1001
MULTI
DECR stock:sku:1001
INCR order:seq
EXEC
  • 现实场景:秒杀扣库存、优惠券发放、名额抢占、简单余额保护。

Lua / Functions

  • 说明:把多条命令合并成一次服务端执行,减少网络往返,也避免并发窗口。
  • 常用方式:EVALFCALL
EVAL "local stock=tonumber(redis.call('GET', KEYS[1]) or '0'); if stock <= 0 then return 0 end; redis.call('DECR', KEYS[1]); return 1" 1 stock:sku:1001
  • 现实场景:库存扣减、幂等校验、限流判断、一次性更新多类 key。
  • 什么时候别用:超长逻辑、重 CPU 计算不适合塞进 Redis 主线程。

持久化

  • 说明:Redis 支持 RDB、AOF、无持久化、RDB + AOF。
  • 经验:缓存型实例可以轻一点;核心业务数据通常至少要 AOF,很多场景直接 RDB + AOF 一起开。
  • 7.0 以后 AOF 是 multi-part 机制,重写和恢复都更稳一些。
CONFIG SET appendonly yes
CONFIG SET save "60 1000"
BGSAVE
BGREWRITEAOF
INFO persistence
  • 现实场景:订单、账单、库存这类重要数据尽量别只靠内存和运气。

复制

  • 说明:Redis 复制默认是异步的,常用来做读扩展、热备和高可用基础。
  • 常用命令:REPLICAOFINFO replicationWAIT
  • 要点:WAIT 只能降低写丢失概率,不能把 Redis 变成强一致系统。
REPLICAOF 10.0.0.12 6379
INFO replication
WAIT 1 1000
  • 现实场景:读多写少业务、报表查询、热点只读副本、主从热备。
  • 风险点:主库关闭持久化再配自动重启,是很危险的组合。

Cluster

  • 说明:Redis Cluster 用 16384 个 hash slot 做分片,客户端要处理 MOVEDASK 重定向。
  • 要点:多 key 操作想稳定可用,key 设计时就要考虑 hash tag。
  • 常用命令:CLUSTER SHARDSCLUSTER KEYSLOT
CLUSTER SHARDS
CLUSTER KEYSLOT order:{1001}:info
CLUSTER KEYSLOT order:{1001}:items

MSET {user:1001}.name Alice {user:1001}.level vip
  • 现实场景:单机内存不够、读写量上去、业务要横向扩容。
  • 什么时候别用:如果业务强依赖大量跨 key 原子事务,而且 key 很难用 hash tag 归槽,设计成本会明显上升。

客户端缓存

  • 说明:Redis 支持 server-assisted client-side caching,也就是服务端帮客户端做失效通知。
  • 常用命令:CLIENT TRACKING
  • 有默认 tracking、BCASTOPTINOPTOUTNOLOOP 等模式。
CLIENT TRACKING ON BCAST PREFIX product:
GET product:1001
GET product:1002
  • 现实场景:商品详情、用户资料、配置中心、热点文章详情页。
  • 风险点:一旦失效通知连接断了,本地缓存要主动清空,不能假装没事。

最后怎么选

  • 要单值、TTL、计数器:String。
  • 要对象字段和局部更新:Hash。
  • 要最近 N 条和简单队列:List。
  • 要去重和集合关系:Set。
  • 要排序、打分、延时:Sorted Set。
  • 要可靠消息、重试、消费组:Stream。
  • 要固定位置和稀疏下标:Array。
  • 要复杂文档:JSON。
  • 要全文检索:Search。
  • 要语义相似:Vector Set。
  • 要近似统计:HyperLogLog、Bloom、CMS、TopK、t-digest。
  • 只要在线广播:Pub/Sub。
  • 要监听 key 变化:Keyspace Notifications。

Redis 最强的地方,不是“快”,而是把大量高频业务结构直接做成原生命令。结构选对了,代码会明显变短,出错点也会明显变少。


我是农村程序员,独立开发者,前端之虎陈随易。