【后端面试总结】Redis字符串实现原理

字符串是我们平时接触频率最高的一个基础类型,但就是这么一个平平无奇的基本类型,在Redis里面也是经历了各种各样的优化,来优化它对内存的占用,了解这部分内容,与其说是"学习Redis",不如说是"向Redis学习",学习Redis从各个可能的角度,来优化内存使用的方法和不放过任何一个可能的内存优化项的态度。

Redis的字符串叫"SDS",也就是Simple Dynamic String。它的结构是一个带长度信息的字节数组。

Go 复制代码
struct SDS<T> {
    T capacity;        // 数组容量
    T len;             // 数组长度
    byte flags;        // 特殊标志位,不用理睬它
    byte[] content;    // 数组内容
}

上面的SDS结构使用了泛型T。为什么不直接用int呢?因为当字符串比较短时,len和capacity可以使用byte和short来表示,Redis为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示。

Redis的字符串有两种存储方式,在长度特别短时,使用embstr形式存储,而当长度超过44字节时,使用raw形式存储。

为了解释这种现象,我们首先来了解一下Redis对象头结构,所有的Redis对象都有下面的这个头结构。

Go 复制代码
struct RedisObject {
    int4 type;          // 4 bits
    int4 encoding;      // 4 bits
    int24 lru;          // 24 bits
    int32 refcount;     // 4 bytes
    void *ptr;          // 8 bytes, 64-bit system
}

不同的对象具有不同的类型type(4bit)。同一个类型的type会有不同的存储形式encoding(4bit)。为了记录对象的LRU信息,使用了24个bit来记录LRU信息。每个对象都有个引用计数,当引用计数为0时,对象就会被销毁,内存被回收。ptr指针将指向对象内容(body)的具体存储位置。这样一个RedisObject对象头结构需要占据16字节的存储空间。

接着我们再看SDS结构体的大小,在字符串比较小时,SDS对象头结构的大小是capacity+3

,至少是3字节。意味着分配一个字符串的最小空间占用为19(即16+3)字节。

Go 复制代码
struct SDS {
    int8 capacity;        // 1 byte
    int8 len;             // 1 byte
    int8 flags;           // 1 byte
    byte[] content;       // 内联数组,长度为capacity
}

embstr将RedisObject对象头结构和SDS对象连续存在一起,使用malloc方法一次分配,而raw存储形式不一样,它需要两次malloc方法,两个对象头在内存地址上一般是不连续的。

内存分配器jemalloc、tcmalloc等分配内存大小的单位都是2/4/8/16/32/64字节等,为了能容纳一个完整的embstr对象,jemalloc最少会分配32字节的空间,如果字符串再稍微长一点,那就是64自己的空间。如果字符串总体超出了64字节,Redis认为它是一个大字符串,不再适合使用embstr存储,而该使用raw形式。

当内存分配了64字节空间时,那这个字符串长度最大可以是多少呢?这个长度就是44字节。

为什么是44字节呢?64字节中,除了RedisObject的16字节和SDS的3字节,留给content的长度最多只有45(即64 - 19)自己饿了。字符串又是以NULL结尾,所以embstr形式最大能容纳的字符串长度就是44字节。

扩容策略:

在字符串长度小于1MB之前,扩容空间采用加倍策略,也就是保留100%的冗余空间。当字符串长度超过1MB之后,为了避免加倍后的冗余空间过大而导致浪费,每次扩容只会多分配1MB大小的冗余空间。

相关推荐
ocean21031 小时前
2025-2026年AI应用开发与Agent面试高频知识点洞察
人工智能·面试·职场和发展
笨鸟先飞的橘猫2 小时前
slg游戏面试复盘
学习·面试
测试19982 小时前
Jmeter接口自动化测试:Jmeter变量的使用
自动化测试·软件测试·测试工具·jmeter·职场和发展·测试用例·接口测试
letisgo52 小时前
JAVA 高级进阶05篇《Spring容器机制:Bean生命周期与三级缓存全解》
java·spring·面试·ioc·源码分析
ocean21032 小时前
2025-2026年Python大厂面试高频问题
python·面试·面试经验
爱从未走散3 小时前
面试八股题
java·面试·职场和发展
晚安日记wanna3 小时前
大文件分片上传的五层追问从 Blob 切片到秒传与弱网容错
前端·面试
晚安日记wanna3 小时前
只会答加索引MySQL 调优还能聊这 7 个点
数据库·面试
吃饱了得干活4 小时前
Redisson 进阶实战:看门狗机制与分布式锁完全指南
java·redis·后端
晚安日记wanna4 小时前
政务 Agent 面试真题五个得分点缺一就掉档
面试·架构