Redis源码其实没那么复杂,跟着一起慢慢拆解看看吧
- 问答
- 2026-01-19 18:31:30
- 3
(引用来源:文章“Redis源码其实没那么复杂,跟着一起慢慢拆解看看吧”)
今天我们来聊一聊Redis的源码,很多人一听到“源码”两个字,尤其是像Redis这样知名项目的源码,可能第一反应就是头大,觉得里面肯定充满了高深莫测的数据结构和精妙绝伦的算法,不是一般人能看懂的,但其实,如果我们换一个角度,不抱着“我要一下子读懂所有”的心态,而是像拆解一个有趣的玩具一样,从一个最简单的地方开始,跟着它的脉络慢慢摸索,你会发现,Redis的源码并没有想象中那么复杂。
我们从哪里开始呢?就从Redis最核心、最基础的数据结构——简单动态字符串(SDS)开始吧,这可能是我们进入Redis世界最好的一扇门。
(引用来源:文章中对SDS的介绍)

你可能会想,字符串有什么好看的?C语言里不是有现成的吗?没错,C语言有以\0结尾的字符数组,但Redis为什么要自己再造一个轮子呢?原因就在于,原生的C字符串在很多场景下效率不高,甚至不安全。
举个例子,我们想获取一个字符串的长度,对于C字符串,我们需要从头到尾扫描整个数组,直到遇到那个标志结束的\0字符才行,这个操作的时间复杂度是O(N),也就是说,字符串越长,耗时就越久,这对于追求极致性能的Redis来说,是不可接受的,想象一下,对一个很长的键名执行STRLEN命令,如果每次都要遍历一遍,那得多慢啊。
那Redis的SDS是怎么解决这个问题的呢?它的做法非常直接:给自己“记个小本本”,在SDS的结构体里,除了存储字符串本身的内容之外,它还额外记录了两个非常重要的信息:一个是当前字符串的实际长度,叫做len;另一个是为这个字符串分配的总空间大小,叫做alloc。
(引用来源:文章中对SDS结构体的描述)

这个设计看似简单,却带来了巨大的好处,获取字符串长度变得轻而易举,Redis只需要看一眼那个len字段,就能立刻知道长度,时间复杂度是O(1),是常数时间,不管字符串多长,速度都一样快,这就像你看一本书,直接翻到最后一页看页码就知道总页数,而不是一页一页地去数。
这个设计避免了缓冲区溢出,在C语言中,如果使用strcat函数拼接字符串,必须确保目标数组有足够的空间,否则就会覆盖掉相邻的内存,造成不可预知的问题,而SDS在每次进行修改操作时,会先检查alloc(分配的空间)是否够用,如果不够,它会自己先悄悄地分配更多的内存,然后再进行修改,这样,我们使用SDS的API来操作字符串时,就再也不用担心缓冲区溢出的问题了,安全性大大提高。
SDS还减少了修改字符串时带来的内存重分配次数,内存分配是一个比较耗时的系统调用,C字符串每次增长或缩短,几乎都需要重新分配一次内存,SDS通过预分配空间和惰性空间释放两种策略来优化这个问题。
预分配指的是,当SDS需要扩容时,它不仅仅分配刚好够用的空间,还会多分配一些预留空间,这样,如果下次还需要追加内容,很可能就不需要再次分配了,这就像你搬家时买了一个比当前物品体积稍大一点的箱子,为以后可能新添的东西留出余地。

惰性空间释放则相反,当SDS缩短时,它并不会立即把多出来的空间还给系统,而是只是更新len字段,把多出来的空间标记为未使用,这样,如果这个字符串很快又变长了,就可以直接使用这些闲置空间,避免了再次分配的消耗。
SDS依然是二进制安全的,因为它依赖len字段来判断字符串的结束,而不是\0字符,字符串中间完全可以包含\0这样的特殊字符,可以用来存储任何二进制数据,比如一张图片或者一个序列化后的对象,而C字符串遇到中间的\0就认为结束了,无法处理这种情况。
你看,仅仅是Redis最基础的字符串实现,里面就蕴含了这么多实用的设计思想,它没有使用什么黑科技,就是通过增加一些额外的元信息(len和alloc),巧妙地解决了性能、安全和易用性的一系列问题。
通过拆解SDS这一个点,我们就像找到了一根线头,顺着它,你就能慢慢理解Redis是如何构建起整个庞大而高效的系统,它的其他数据结构,如双端链表、字典、跳跃表等,也都秉承着类似的设计哲学:在简单的基础上,通过精心的设计来优化性能。
别再对Redis源码望而却步了,下次,我们可以继续拆解它的另一个数据结构,比如字典(dict),看看Redis是如何实现键值对存储的,一步一步来,你会发现,读懂它并没有那么难。
本文由歧云亭于2026-01-19发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/83820.html
