Redis 核心数据结构与命令

Redis 系统讲解第一篇:把五大类型的命令讲全,再补上"01 路线篇"没展开的键设计与底层编码对应关系。01 篇是"高频命令体感",这一篇是"全景地图"——忘了哪个命令,先来这里查。

键设计:先定规范再写代码

Redis 只有 key-value 两层,业务语义全靠 key 的命名约定

业务域:对象:ID:字段     —— 冒号分层是社区通用惯例
user:1:profile          # 用户 1 的资料(Hash)
order:202608:count      # 8 月订单计数(String/INCR)
sign:user:1:202608      # 用户 1 的 8 月签到(Bitmap)

三条红线:

  • key 别太长也别太短:太长占内存(key 本身也是数据),太短没语义。100 字节以内为佳。
  • 警惕大 key:单个 value 太大(如一个 10 万元素的 List、几 MB 的 String)——读写阻塞单线程、删除卡顿(用 UNLINK 异步删代替 DEL)、迁移卡顿。发现手段:redis-cli --bigkeys
  • 警惕热 key:某个 key 被疯狂访问(秒杀商品)——单线程模型下它是瓶颈。解法:本地缓存兜一层、key 加随机后缀拆多份。

String:最全命令与场景

命令 作用 场景备注
SET key val [EX 秒] [NX|XX] [KEEPTTL] 写入 NX=不存在才写;XX=存在才写;KEEPTTL 保留原 TTL
GET / MGET / MSET 读 / 批量读 / 批量写 MGET 一次网络往返拿 N 个,比循环 GET 快
INCR / INCRBY / INCRBYFLOAT 原子自增 计数器、限流、分布式 id 雏形
APPEND / STRLEN 追加 / 长度 value 是字符串语义时用
SETNX 不存在才写 老式锁写法,已被 SET NX EX 取代
GETRANGE / SETRANGE 读子串 / 覆写子串 偏移量操作

注意:Redis 的 String 是二进制安全的——存图片字节、序列化后的 JSON 都行,上限 512MB。

Hash

HSET user:1 name "张三" age 21          # 多 field 一次写
HGET / HMGET / HGETALL                   # 单取 / 多取 / 全取
HDEL field / HKEYS / HVALS / HLEN        # 删 field / 全部 field / 全部 value / 长度
HINCRBY user:1 age 1                     # field 级原子自增——对象内计数很顺手

场景:对象缓存(比整个 JSON 塞 String 好改单字段)、购物车(field=商品 id,value=数量)。

List

LPUSH / RPUSH / LPOP / RPOP              # 双端进出
LRANGE key 0 -1                          # 全量;负数下标从尾数
LLEN / LINDEX / LSET / LTRIM             # 长度 / 按下标取 / 按下标赋值 / 修剪保长度
BLPOP / BRPOP key 5                      # 阻塞弹出,5 秒等不到才放弃

场景:最新消息列表(LTRIM 保留前 N 条=固定窗口)、简单队列。

Set

SADD / SREM / SISMEMBER / SCARD          # 增 / 删 / 判存 / 计数
SMEMBERS                                 # 全部成员——大集合慎用,用 SSCAN 渐进
SINTER / SUNION / SDIFF                  # 交 / 并 / 差(共同关注、推荐)
SRANDMEMBER / SPOP                       # 随机看不取 / 随机弹出

ZSet

ZADD rank 95 "张三"                      # score member
ZINCRBY / ZSCORE / ZCARD                 # 加分 / 查分 / 总数
ZREVRANGE rank 0 9 WITHSCORES            # 排行榜 top10
ZRANK / ZREVRANK                         # 正序 / 逆序排名
ZRANGEBYSCORE rank 90 (100 WITHSCORES    # 区间查询,( 表示开区间
ZREMRANGEBYSCORE rank -inf 60            # 删 60 分以下(定期清理老数据常用)

ZSet 是 Redis 最"值钱"的结构:排行榜、延迟队列(score 存执行时间戳)、滑动窗口限流都靠它。

通用命令与键管理

SCAN 0 MATCH user:* COUNT 100            # 渐进遍历,生产唯一正确姿势
EXPIRE / PEXPIRE / TTL / PTTL            # 秒级 / 毫秒级过期与查看
PERSIST key                              # 去掉 TTL
OBJECT ENCODING key                      # 看底层编码(见下表)
TYPE key                                 # 看类型
RANDOMKEY / DBSIZE / FLUSHDB             # 随机 key / 库大小 / 清库

type 与 encoding:同一类型多种底层实现

TYPE 是对外逻辑类型,OBJECT ENCODING 是底层真实结构——Redis 会按数据大小自动切换编码,这是它省内存的秘诀之一:

TYPE 小数据编码 大数据编码
string int(整数)/ embstr(短字符串) raw(长字符串)
hash listpack(field 少且短) hashtable
list listpack quicklist(双向链表套 listpack)
set intset(全整数时) listpack / hashtable
zset listpack skiplist + dict 双结构

💡 阈值由配置里的 *-max-listpack-entries / *-max-listpack-value 控制。记忆钩子:Redis 总是先用紧凑结构省内存,超阈值自动升级——理解这一点,"为什么我的 hash 存了 130 个字段变慢"这类问题就有了方向。

键过期与淘汰的完整图景

  • 过期删除:惰性删除(访问时检查)+ 定期删除(后台抽样清理)组合
  • 内存淘汰:内存达到 maxmemory 后按 maxmemory-policy 淘汰——noeviction(默认,写报错)/ allkeys-lru / volatile-lru / allkeys-lfu / volatile-lfu / allkeys-random / volatile-random / volatile-ttl
  • 我的选择锚点:纯缓存选 allkeys-lru(或热点更集中的 allkeys-lfu);key 里混着"不能丢"的数据才用 volatile-*(只淘汰带 TTL 的)

⬅️ 01-Redis 学习路线 🏠 00-数据库 ➡️ 03-Redis 应用实战