redis--底层 sds inset

一、SDS(Simple Dynamic String,简单动态字符串)

Redis 底层字符串实现,Redis 的 key、很多 value 底层都是 SDS,没有直接使用 C 原生字符串。

1. C 原生字符串缺陷

  1. 获取长度:必须遍历,O (n)
  2. 非二进制安全:遇到\0就截断,无法保存图片、音频等二进制数据
  3. 修改字符串容易缓冲区溢出,扩容麻烦

2. SDS 结构体(sdshdr8 示例)

复制代码
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len;    // 当前有效字符串长度,不含末尾\0
    uint8_t alloc;  // 已分配内存总大小(预分配空间),不含末尾\0
    unsigned char flags; // 标记SDS类型(5种:SDS_TYPE_5/8/16/32/64,决定header大小)
    char buf[];     // 柔性数组,存放字符,末尾保留\0,兼容C函数
};

__packed__:取消内存对齐,节省内存。

3. SDS 动态扩容(内存预分配)

追加字符串时,先判断剩余空间够不够,不够就扩容:

  • 新长度 <1M :预分配空间 = 新长度 ×2 (+1 留给\0)
  • 新长度 ≥1M :预分配空间 = 新长度 +1M(+1 留给\0)

目的:减少多次内存 realloc 分配开销

4. SDS 四大优点

  1. 获取长度 O (1):直接读取len字段,不用遍历
  2. 二进制安全 :依靠len判断字符串结束,不是\0,可存二进制
  3. 动态扩容 + 内存预分配,减少内存分配次数
  4. 兼容 C 语言字符串函数:buf 末尾自带\0

二、IntSet(整数集合,Set 集合底层编码之一)

Redis Set 底层的整数专用压缩存储 ,只在集合全部是整数、元素数量不多时使用;一旦不符合条件,自动转哈希表。

1. 结构体

复制代码
typedef struct intset {
    uint32_t encoding;  // 编码类型:INT16 / INT32 / INT64
    uint32_t length;    // 集合元素总个数
    int8_t contents[];  // 有序升序数组,存放整数
} intset;
  • 三种编码:
    • INTSET_ENC_INT16:每个元素占 2 字节
    • INTSET_ENC_INT32:每个元素占 4 字节
    • INTSET_ENC_INT64:每个元素占 8 字节
  • 特点:contents数组升序排列,查找用二分查找。

2. IntSet 升级机制(单向升级,不能降级)

场景:原有集合是 INT16,新增数字超出 int16 范围 升级 4 步:

  1. 升级编码到更大类型(例:INT16 → INT32),扩容数组
  2. 倒序拷贝原有元素(防止覆盖未拷贝数据)
  3. 将新元素放到数组末尾
  4. 修改encoding和length字段

重点考点:只能从小类型升级到大类型,升级后无法回退降级。

3. IntSet 适用条件

  • 集合内全部都是整数
  • 元素数量较少;新增非整数元素,会直接转为 hashtable
相关推荐
用户094248568031 小时前
Redis 实战修炼与原理进阶专栏大纲
redis·快应用·源码阅读
Lysander.Jovian3 小时前
Redis使用
redis
救救孩子把3 小时前
AI面试八股文-03_3-RAG 系统面试题
人工智能·redis·面试·agent·rag
hweiyu004 小时前
Redis命令:LPUSHX
redis·缓存
hweiyu004 小时前
Redis命令:LRANGE
redis·缓存
蓝胖的四次元口袋4 小时前
Redis知识梳理(5)
数据库·redis·缓存
for_ever_love__4 小时前
半同步复制:数据安全和服务可用之间怎么权衡
redis·mysql·缓存·一致性·数据·半同步复制·方式
Anastasiozzzz5 小时前
InnoDB 为什么不用跳表,Redis 为什么不用 B+树?一场“磁盘”与“内存”的终极对决
数据库·redis·b树
Thomas.Sir7 小时前
第29课:微服务异步调用、线程池优化 & 事件驱动开发
java·redis·微服务