Redis 字符串sds学习笔记

62 阅读2分钟

设计目标与背景

Redis 的 SDS(Simple Dynamic String)是替代 C 原生字符串的核心数据结构,解决了传统 C 字符串的三大痛点:

  1. 缓冲区溢出风险:C 字符串拼接时需手动管理内存
  2. 长度计算低效:strlen() 需要 O(n) 遍历
  3. 二进制不安全:无法存储包含空字符的数据

SDS 结构解析

Redis 3.2 后采用柔性数组成员优化后的结构:

struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len;        // 已用长度
    uint8_t alloc;      // 总分配空间(不含header)
    unsigned char flags;// 类型标识(低3位)
    char buf[];         // 柔性数组成员
};
  • 类型分级:sdshdr5(淘汰)/8/16/32/64,根据长度自动选择
  • 内存对齐:使用 packed 取消结构体对齐,节省内存
  • 空间预分配:扩容时按需分配,<1MB 时加倍,free = len,≥1MB 时加 1MB,free= 1M

核心特性

  1. 二进制安全:通过 len 字段记录长度,允许存储任意二进制数据
  2. 惰性空间释放:缩短时不立即回收内存,等待后续复用
  3. 常数级操作
    • O(1) 获取字符串长度
    • 自动扩容保障追加操作效率
  4. 兼容 C 标准:保留 null-terminated 特性,可直接使用部分 C 函数

应用场景

  1. 字符串存储(SET/GET 命令底层实现)
  2. AOF 缓冲区和客户端输入缓冲区
  3. 保存二进制数据(如图片哈希值)
  4. 高效执行 APPEND 等字符串操作

性能优势对比

操作C 字符串SDS
strlen()O(n)O(1)
append 操作O(n)O(n)均摊
缓冲区安全
内存分配次数每次修改预分配优化

学习总结

SDS 作为 Redis 的基础数据结构,通过空间预分配、类型分级、柔性数组成员等设计,在内存效率与操作性能之间达到平衡。其设计思想对理解 Redis 的高性能特性具有重要意义,建议通过阅读 sds.h/sds.c 源码深入学习具体实现细节。