文章目录

Redis OBJECT ENCODING查看数据结构底层编码类型

发布于 2026-05-07 12:16:05 · 浏览 5 次 · 评论 0 条

Redis 中的 5 种基础数据类型(String、List、Hash、Set、ZSet)在底层实现上并不单一。为了平衡内存占用与读写性能,Redis 会根据数据量的大小、元素的长度等因素,自动在多种底层数据结构(编码类型)之间进行切换。理解这些编码类型是进行 Redis 性能调优和内存优化的关键。使用 OBJECT ENCODING 命令可以直接查看某个 Key 对应的底层编码。

以下是查看和分析 Redis 数据结构底层编码的详细步骤。


1. 准备工作

在开始操作前,需要确保本地或远程已经安装并启动了 Redis 服务。

  1. 打开终端或命令行工具。
  2. 输入连接命令并登录 Redis:
    redis-cli
  3. 输入 PING 命令,若返回 PONG,则表示连接成功。

2. 查看 String 类型的底层编码

String 类型是 Redis 中最基础的类型,其底层编码主要根据值的长度和内容决定。

  1. 执行以下命令设置一个纯整数值:

    SET number 10086
  2. 输入查看编码的命令:

    OBJECT ENCODING number
  3. 观察返回结果,结果为 int。这说明 Redis 发现该值是长整数,直接将其存储为整数类型,以节省空间并支持数值计算。

  4. 执行以下命令设置一个短字符串(长度小于 44 字节):

    SET short "hello redis"
  5. 输入查看编码命令:

    OBJECT ENCODING short
  6. 观察返回结果,结果为 embstr。这是一种专门用于保存短字符串的编码方式,它只要求一次内存分配,且数据连续存储,读取速度快。

  7. 执行以下命令设置一个长字符串(生成一个超过 44 字节的字符串):

    SET long "This is a very long string designed to exceed the embstr encoding limit of 44 bytes in Redis."
  8. 输入查看编码命令:

    OBJECT ENCODING long
  9. 观察返回结果,结果为 raw。当字符串长度超过阈值(通常是 44 字节)时,Redis 会使用动态字符串(SDS)并使用 raw 编码,此时需要进行两次内存分配。


3. 查看 Hash 类型的底层编码

Hash 类型在元素较少且每个元素值较小时,会使用压缩列表以节省内存;当数据量增大时,会转换为哈希表。

  1. 执行以下命令创建一个包含少量字段的小 Hash:

    HSET user:1 name "Tom" age 25
  2. 输入查看编码命令:

    OBJECT ENCODING user:1
  3. 观察返回结果,结果为 ziplist。此时 Redis 将所有数据紧挨着存储在连续内存块中,极其节省内存。

  4. 为了触发编码转换,需要修改配置参数或一次性大量插入数据。这里使用脚本一次性插入 513 个字段(默认阈值通常是 512):

    for i in {1..513}; do redis-cli HSET big_hash field_$i value_$i; done

    (注:上述命令在 Bash 环境下执行,Windows 用户可使用 PowerShell 循环或手动插入足够多的数据)

  5. 输入查看编码命令:

    OBJECT ENCODING big_hash
  6. 观察返回结果,结果为 hashtable。当字段数量超过 hash-max-ziplist-entries(默认 512)或单个元素值长度超过 hash-max-ziplist-value(默认 64 字节)时,编码会转换为哈希表。哈希表的读写时间复杂度为 $O(1)$,但内存消耗会比压缩列表大。


4. 查看 List 类型的底层编码

List 类型的底层结构在不同版本的 Redis 中有所变化。在 Redis 3.2 之后,统一使用 quicklist(快速列表)。

  1. 执行以下命令创建一个包含少量元素的列表:
    LPUSH my_list a b c
  2. 输入查看编码命令:
    OBJECT ENCODING my_list
  3. 观察返回结果,结果为 quicklistquicklistziplistlinkedlist 的结合体,它将多个 ziplist 使用双向指针串联起来。既保证了列表中间插入元素的性能,又减少了指针的内存开销。

5. 查看 Set 类型的底层编码

Set 集合的编码分为整数集合和哈希表。

  1. 执行以下命令创建一个包含少量整数的集合:

    SSET numbers 1 2 3

    (注:若提示无效命令,请使用 SADD numbers 1 2 3)

  2. 输入查看编码命令:

    OBJECT ENCODING numbers
  3. 观察返回结果,结果为 intset。当集合中的所有元素都是整数且元素数量较少(默认小于 512 个)时,Redis 使用紧凑的整数数组存储。

  4. 执行以下命令向集合中添加一个非整数元素:

    SADD numbers "redis"
  5. 输入查看编码命令:

    OBJECT ENCODING numbers
  6. 观察返回结果,结果变为 hashtable。一旦引入非整数元素,或者整数数量超过阈值,编码将立即升级为哈希表,其中 Key 为集合元素,Value 为 null。


6. 查看 ZSet 类型的底层编码

有序集合(ZSet)的编码选择逻辑与 Hash 类似,取决于元素数量和成员大小。

  1. 执行以下命令创建一个小的有序集合:

    ZADD rank 10 "player1" 20 "player2"
  2. 输入查看编码命令:

    OBJECT ENCODING rank
  3. 观察返回结果,结果为 ziplist。此时,ZSet 将成员和分值紧挨着存储在同一个 ziplist 中,先按分值排序,再存储成员。

  4. 执行以下命令插入大量数据(超过默认阈值 128 个元素):

    for i in {1..129}; do redis-cli ZADD big_rank $i "member$i"; done
  5. 输入查看编码命令:

    OBJECT ENCODING big_rank
  6. 观察返回结果,结果为 skiplist。当元素较多或成员字符串较长时,Redis 会使用跳跃表加字典的组合结构。跳跃表负责维持排序和范围查询的高效性($O(\log N)$),字典则保证根据成员查询分值的高效性($O(1)$)。


7. 编码转换逻辑总结

为了更直观地理解 Redis 何时进行编码转换,可以参考以下决策流程。

graph TD A[Redis Key: Set Operation] --> B{Data Type?} B -->|String| C{Is Integer?} C -->|Yes| D[int] C -->|No| E{Length < 44 Bytes?} E -->|Yes| F[embstr] E -->|No| G[raw] B -->|Hash| H{Entries < 512
& Value Size < 64B?} H -->|Yes| I[ziplist] H -->|No| J[hashtable] B -->|Set| K{All Integers
& Count < 512?} K -->|Yes| L[intset] K -->|No| J B -->|ZSet| M{Count < 128
& Value Size < 64B?} M -->|Yes| I M -->|No| N[skiplist + dict] B -->|List| O[quicklist]

8. 自定义编码转换阈值

如果需要针对特定业务场景调整编码转换的触发条件,可以通过配置文件或命令行修改。

  1. 查看当前的 Hash 类型压缩列表阈值配置:
    CONFIG GET hash-max-ziplist-entries
    CONFIG GET hash-max-ziplist-value
  2. 修改配置以允许更大的压缩列表:
    CONFIG SET hash-max-ziplist-entries 1000
  3. 执行修改后,新创建的 Hash 在元素数量小于 1000 时都会使用 ziplist 编码。这会增加内存使用的紧凑性,但在大数据量下可能会导致 ziplist 连锁更新带来的性能抖动。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文