Redis 字符串 String类型的底层实现是什么?

105 阅读3分钟

Redis 字符串 String类型的底层实现是什么?

重要内容

Redis 字符串(String)类型的底层实现基于 简单动态字符串(SDS)并且根据字符串内容及长度动态选择编码方式(int、embstr、raw等),以优化内存和性能

扩展知识

不同编码的选择

int 编码
  • 适用场景:当存储的字符串可以表示为一个64位有符号整数时,Redis会采用 int 编码来存储这个值

  • 实现原理:直接使用一个64位的整数来存储该值,这样可以节省内存,并且在进行数值操作(如 INCRDECR 等)时,不需要进行额外的类型转换,提高了操作效率

    struct redisObject {
        unsigned type:4;      // 数据类型(字符串、哈希等)
        unsigned encoding:4;  // 编码类型,这里是 int
        int64_t ptr;          // 实际的数据指针,这里直接存储整数值
    };
    
    image-20250322131044045
  • 示例代码

    # 设置一个可以表示为整数的字符串
    redis-cli set num 123
    # 查看该键的编码方式
    redis-cli object encoding num
    # 输出结果:int
    
embstr 编码
  • 适用场景:当存储的字符串长度较短(Redis 3.2 及以前版本中长度小于等于39字节,Redis 3.2 以后版本中长度小于等于44字节)时,Redis会采用 embstr 编码

  • 实现原理embstr 是一种专门为短字符串设计的编码方式,它将 RedisObject 结构和简单动态字符串 SDS 结构连续存储在一块内存中,避免了内存碎片,并且减少了内存分配和释放的次数,提高了内存使用效率

    struct redisObject {
        unsigned type:4;       // 数据类型
        unsigned encoding:4;   // 编码类型,这里是 embstr
        void *ptr;             // 指向 sdshdr 结构
    };
    
    struct sdshdr {
        uint32_t len;          // 当前字符串长度
        uint32_t alloc;        // 已分配的内存大小
        unsigned char flags;   // 编码类型
        char buf[];            // 实际字符串数据
    };
    
    image-20250322131115031
  • 示例代码

    # 设置一个短字符串
    redis-cli set short_str "hello"
    # 查看该键的编码方式
    redis-cli object encoding short_str
    # 输出结果:embstr 
    
raw 编码
  • 适用场景:当存储的字符串长度较长(超过 embstr 编码所允许的最大长度)时,Redis会采用 raw 编码

  • 实现原理raw 编码使用普通的 SDS 结构来存储字符串,RedisObject 结构和 SDS 结构分别存储在不同的内存块中。虽然 raw 编码在内存使用效率上不如 embstr 编码,但它可以存储任意长度的字符串

    struct redisObject {
        unsigned type:4;       // 数据类型
        unsigned encoding:4;   // 编码类型,这里是 raw
        void *ptr;             // 指向 sdshdr 结构
    };
    
    struct sdshdr {
        uint32_t len;          // 当前字符串长度
        uint32_t alloc;        // 已分配的内存大小
        unsigned char flags;   // 编码类型
        char buf[];            // 实际字符串数据
    };
    
    image-20250322131218289
  • 示例代码

    # 设置一个长字符串
    redis-cli set long_str "abcdefghijklmnopqrstuvwxyz1234567890abcde"
    # 查看该键的编码方式
    redis-cli object encoding long_str
    # 输出结果:raw