Redis 内部使用一个 redisObject 对象来表示所有的 key 和 value。

  • type :代表一个 value 对象具体是何种数据类型。
  • encoding :是不同数据类型在 redis 内部的存储方式,比如:type=string 代表 value 存储的是一个普通字符串,那么对应的 encoding 可以是 raw 或者是 int,如果是 int 则代表实际 redis 内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:”123” “456”这样的字符串。
  • vm 字段:只有打开了 Redis 的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的。 Redis 使用 redisObject 来表示所有的 key/value 数据是比较浪费内存的,当然这些内存管理成本的付出主要也是为了给 Redis 不同数据类型提供一个统一的管理接口,实际作者也提供了多种方法帮助我们尽量节省内存使用。

redisObject 的 type/encoding 二层结构是理解 Redis 内存行为的钥匙,但原文停留在字段介绍。本文补全三块:type→encoding 的完整映射与转换条件、全局哈希表与渐进式 rehash、以及内存优化的实际手段(object encoding 命令验证)。

type 与 encoding 的完整映射

type encoding 转换条件
string int 值是能 long 表示的整数
string embstr ≤44 字节短串(对象头+数据一次分配,只读)
string raw 长串或修改后的 embstr
list listpack(ziplist) 元素少且小(list-max-listpack-size)
list quicklist 超出阈值(listpack 组成的双向链表)
hash listpack 字段数<128 且值<64B(hash-max-listpack-entries/value)
hash hashtable 超出阈值
set intset 全整数且量小(set-max-intset-entries)
set listpack 小集合非全整数(新版本)
set hashtable 超出阈值
zset listpack 成员少且小
zset skiplist+hashtable 超出阈值

要点:encoding 会随数据增长自动升级且不可逆(listpack→hashtable 单向);小集合用紧凑结构(listpack 连续内存、无指针开销)是 Redis 省内存的核心手段。OBJECT ENCODING key 可验证当前编码。

全局结构:字典 + 渐进式 rehash

  • 所有键空间存于一个哈希表(dict,两个 dichtab)
  • 扩容/缩容不一次性 rehash(会阻塞单线程),而是渐进式 rehash:新旧表并存,每次 CRUD 顺带迁移若干桶,后台定时任务辅助搬迁——把 O(N) 的 rehash 摊平到每次操作
  • 过期键:惰性删除(访问时检查)+ 定期删除(每 100ms 抽样清理)双策略,平衡内存与 CPU

redisObject 的开销与优化

每个 redisObject 头约 16 字节(type/encoding/lru/refcount/ptr),小值场景开销占比高。优化手段:

  • 尽量命中紧凑编码:控制 hash/set/zset 的元素数与值大小在 listpack 阈值内(阈值可调但权衡 CPU)
  • 键名简短:键也是对象,长键名浪费可观(亿级键时 GB 级)
  • 整数化:能存整数不存字符串(int encoding 直接存值于 ptr,零额外分配)
  • 共享对象:0-9999 整数对象共享池(embstr/int 场景复用)
  • 32bit vs 64bit:指针 4 vs 8 字节,内存敏感场景的历史选项(今天少用)

单线程与结构的配合

redisObject 的统一接口让单线程命令分发可以对五种 type 一视同仁;紧凑编码减少内存占用即减少缓存缺失与 swap 风险——内部结构的全部设计都服务于”单线程+全内存”这两个前提:结构要省内存(内存是瓶颈)、操作要 O(1)/O(logN)(CPU 时间片珍贵)、rehash 要渐进(不能阻塞)。

验证与排障工具

  • OBJECT ENCODING key / MEMORY USAGE key:单键编码与内存
  • redis-cli --bigkeys / --memkeys:大键扫描(大 key 是删除阻塞与迁移卡顿的元凶)
  • INFO memory:used_memory vs RSS、碎片率 mem_fragmentation_ratio(>1.5 考虑重启整理或 activedefrag)

Redis 内部结构的主线:redisObject 统一抽象 + type/encoding 二层映射(小数据紧凑编码省内存)+ 全局字典渐进 rehash(单线程不阻塞)+ 双策略过期删除。记住”encoding 自动升级不可逆”与”大 key 是万恶之源”两条,内存类问题的排查就有了起点。