redis数据结构 字符串SDS

  1. SDS 概述
    1.1 什么是 SDS
    SDS (Simple Dynamic String) 是 Redis 中用于存储字符串的核心数据结构,相比传统的 C 字符串具有显著优势:
// C 字符串的问题
char *str = "hello";
int len = strlen(str);  // O(n) 时间复杂度

// SDS 的优势  
sds s = sdsnew("hello");
size_t len = sdslen(s); // O(1) 时间复杂度

1.2 SDS vs C 字符串对比


image.png
  1. SDS 数据结构详解
    2.1 五种 SDS 结构
    Redis 根据字符串长度使用不同的结构,实现空间优化:
typedef char *sds;

// 1. 超小字符串 (< 32字节)
struct __attribute__ ((__packed__)) sdshdr5 {
    unsigned char flags;    // 标志位 + 长度信息
    char buf[];            // 字符串数据
};

// 2. 小字符串 (32-255字节)
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len;           // 已使用长度 (1字节)
    uint8_t alloc;         // 总分配长度 (1字节)  
    unsigned char flags;   // 标志位
    char buf[];           // 字符串数据
};

// 3. 中等字符串 (256字节-64KB)
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len;          // 已使用长度 (2字节)
    uint16_t alloc;        // 总分配长度 (2字节)
    unsigned char flags;   // 标志位
    char buf[];           // 字符串数据
};

// 4. 大字符串 (64KB-4GB)
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len;          // 已使用长度 (4字节)
    uint32_t alloc;        // 总分配长度 (4字节)
    unsigned char flags;   // 标志位
    char buf[];           // 字符串数据
};

// 5. 超大字符串 (>4GB)
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len;          // 已使用长度 (8字节)
    uint64_t alloc;        // 总分配长度 (8字节)
    unsigned char flags;   // 标志位
    char buf[];           // 字符串数据
};
  1. 内存优化原理
    3.1 packed 属性的作用
// ❌ 没有 __packed__ - 浪费空间
struct sdshdr32_normal {
    uint32_t len;        // 4字节
    uint32_t alloc;      // 4字节  
    unsigned char flags; // 1字节
    // 编译器自动填充 3字节
};
// 总大小:12字节

// ✅ 使用 __packed__ - 节省空间
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len;        // 4字节
    uint32_t alloc;      // 4字节
    unsigned char flags; // 1字节
    // 无填充
};
// 总大小:9字节,节省 25% 空间!

3.2 分级结构的空间节省

# 如果统一使用最大结构存储所有字符串
存储 "hello" (5字符):
- 统一方案:17字节头部 + 5字节数据 = 22字节
- SDS方案:3字节头部 + 5字节数据 = 8字节
- 节省:64% 的空间!

3.3 整数类型选择原理


image.png
  1. Redis 字符串对象编码类型
    4.1 三种编码方式
    Redis 字符串对象会根据内容自动选择最优编码:
    INT 编码
# 适用:纯数字字符串
redis> SET count "123"
redis> OBJECT ENCODING count
"int"

# 内存结构:仅占用 redisObject,约16字节

EMBSTR 编码

# 适用:长度 ≤ 44字节的字符串
redis> SET name "Alice"
redis> OBJECT ENCODING name  
"embstr"

# 内存结构:redisObject + SDS 连续存储
[redisObject][sdshdr8][字符串数据]

RAW 编码

# 适用:长度 > 44字节 或 需要修改的字符串
redis> SET article "很长的文章内容..."
redis> OBJECT ENCODING article
"raw"

# 内存结构:redisObject 和 SDS 分别分配
redisObject → ptr → [sdshdr*][字符串数据]

4.2 编码自动转换

# 数字 → 字符串
redis> SET val "123"        # INT编码
redis> APPEND val "abc"     # 转为EMBSTR编码

# 短串 → 长串
redis> SET msg "short"      # EMBSTR编码  
redis> APPEND msg "很长很长..." # 转为RAW编码

# 只读 → 可写
redis> SET greeting "hello" # EMBSTR编码
redis> APPEND greeting "!"  # 转为RAW编码
  1. SDS 核心算法
    5.1 长度获取算法
static inline size_t sdslen(const sds s) {
    unsigned char flags = s[-1];  // 获取flags字段
    switch(flags & SDS_TYPE_MASK) {
        case SDS_TYPE_5:
            return SDS_TYPE_5_LEN(flags);
        case SDS_TYPE_8:
            return SDS_HDR(8,s)->len;
        case SDS_TYPE_16:  
            return SDS_HDR(16,s)->len;
        case SDS_TYPE_32:
            return SDS_HDR(32,s)->len;
        case SDS_TYPE_64:
            return SDS_HDR(64,s)->len;
    }
    return 0;
}

5.2 空间预分配策略

sds sdsMakeRoomFor(sds s, size_t addlen) {
    size_t free = sdsavail(s);
    size_t len, newlen;
    
    if (free >= addlen) return s;  // 空间足够
    
    len = sdslen(s);
    newlen = (len + addlen);
    
    // 预分配策略
    if (newlen < SDS_MAX_PREALLOC)
        newlen *= 2;  // 小于1MB时,分配2倍空间
    else
        newlen += SDS_MAX_PREALLOC;  // 大于1MB时,额外分配1MB
        
    return sdsResize(s, newlen);
}
  1. 内存布局图解
SDS内存布局示例 (sdshdr16):
┌──────────┬──────────┬───────┬─────────────────┬────┐
│   len    │  alloc   │ flags │      buf[]      │ \0 │
│ (2字节)  │ (2字节)  │(1字节)│   (字符串数据)   │    │
└──────────┴──────────┴───────┴─────────────────┴────┘
           ↑                   ↑                      
         头部信息            sds指针指向这里             
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容