Redis 提供 5 大基本数据类型String字符串、List列表、Set集合、Hash哈希、Zset有序集合。其底层实现会根据数据特征智能切换数据结构以达到性能与内存的最优平衡。0、底层数据结构简介压缩列表 (Ziplist)早期使用的紧凑结构但因存储“前一项长度”而存在连锁更新风险修改一个元素可能引发后续元素的内存重排。列表包 (ListPack)Redis 7.0 引入是 Ziplist 的优化版。它将“长度信息”放在条目末尾且只记录自身长度彻底解决了连锁更新问题。哈希表 (HashTable)使用渐进式 rehash进行扩容。内部维护两个哈希表ht[0]和ht[1]扩容时逐步将ht[0]的数据迁移到更大的ht[1]。期间新写入的数据直接进入ht[1]查找时会同时检查两个表。迁移完成后释放ht[0]并将ht[1]设置为新的主表。一、StringString 的底层是SDS (Simple Dynamic String)。SDS 有 5 种类型sdshdr5/8/16/32/64根据字符串长度自动选择以优化内存。structsdshdr{intlen;// 字符串实际长度intalloc;// 分配的总空间charbuf[];// 存储数据的柔性数组unsignedcharflags;// 标识 SDS 类型};核心特点二进制安全不依赖\0判断结尾可存储任意二进制数据如图片、序列化对象。为了兼容 C 标准库函数SDS 末尾仍会添加\0但这不影响其二进制安全性。O(1) 获取长度直接读取len字段。动态扩容写入前检查剩余空间不足时自动扩容避免缓冲区溢出。内存优化对不同长度的字符串使用不同大小的头部减少内存开销。三种编码自动切换INT存储整数值如SET key 123直接将数值存储在指针位置无需额外分配。EMBSTR存储短字符串≤44 字节。Redis 对象头与 SDS 数据存储在同一块连续内存中内存局部性好一次分配完成。RAW存储长字符串 44 字节。Redis 对象头与 SDS 数据分开分配。44 字节边界是根据 64 位系统内存对齐jemalloc 分配器常用 64 字节块精确计算得出的优化值。二、ListList 的底层是QuickList它是一个宏观上的双向链表但每个链表节点 (quicklistNode) 内部并不直接存储数据而是包含一个ListPack来紧凑存储多个元素。QuickList 结构 [quicklistNode] - [quicklistNode] - [quicklistNode] ↓ ↓ ↓ ListPack ListPack ListPack [e1,e2,e3] [e4,e5,e6] [e7,e8,e9]设计优势对比纯链表避免了每个元素都需要prev/next指针的巨大内存开销。对比纯 ListPack避免了在超长连续内存中插入/删除元素时的大规模数据移动。通过配置list-max-listpack-size可以控制每个 ListPack 的最大容量如-2表示约 8KB从而在内存紧凑性和节点内操作性能之间取得平衡。三、SetSet 存储无序且唯一的元素底层使用IntSet或HashTable。IntSet当所有元素都是整数且元素数量 ≤set-max-intset-entries默认 512时使用。它是一个有序整数数组支持二分查找O(log N)内存极其紧凑。HashTable当插入非整数元素或元素数量超过阈值时自动转换为 HashTable。此时只使用字典的键Key来存储元素值Value统一为NULL实现 O(1) 复杂度的查找。关键点IntSet 升级当新插入的整数超出当前编码范围如从 int16 到 int32时会触发升级重新分配内存并转换所有元素。升级是单向不可逆的。HashTable 也使用渐进式 rehash扩容机制与其他场景下的哈希表一致。四、ZSet (Sorted Set)ZSet 存储带分值score的有序唯一元素底层使用ListPack或字典(Dict) 跳表(SkipList)的双结构。ListPack当元素数量 ≤zset-max-listpack-entries默认 128且每个元素值长度 ≤zset-max-listpack-value默认 64 字节时使用。元素按分值连续紧凑存储。Dict SkipList当不满足上述条件时使用。跳表 (SkipList)维护分值有序结构支持 O(log N) 的范围查询如ZRANGE,ZRANK。字典 (Dict)实现 O(1) 复杂度的单点查询如ZSCORE。双结构设计精髓空间换时间用额外空间指针同时获得 O(1) 查找和 O(log N) 范围查询。数据共享两个结构中的元素值SDS指向同一内存对象避免重复存储。五、HashHash 存储字段-值对field-value底层使用ListPack或HashTable。ListPack当字段数量 ≤hash-max-listpack-entries默认 512且所有字段值长度 ≤hash-max-listpack-value默认 64 字节时使用。字段和值交替存储在 ListPack 中。HashTable当不满足上述条件时使用提供 O(1) 的字段操作。为什么小 Hash 还用 ListPack虽然 ListPack 的查询是 O(N)但对于小规模数据几十个字段内存效率极高比 HashTable 节省约 30%-50% 内存无指针和额外元数据开销。缓存友好数据连续存储CPU 缓存命中率高。自动转换超过阈值后 Redis 会自动转为 HashTable对应用透明。这是一种典型的“二八定律”优化为80%的小数据场景优化内存20%的大数据场景则保证性能。