String字符串与SDS(简单动态字符串)
1435597771 · Jul 1, 2026
Redis是键值对数据库,它提供了不同的数据类型,例如:String、Hash、List、Set和ZSet。其中String是最常用的一种,本篇文章我们来探讨一下Redis提供的数据类型String和他的底层实现。Redis String 看起来只是一个普通的字符串,但它的底层实现并没有那么简单。为了兼顾内存占用和操作效率,Redis 针对不同场景采用了不同的实现方式。下面我们从整体架构开始,一步步理解 Redis String 的实现原理。 先区分三个概念 在认识Redis String之前需要先理清楚三个容易混淆的概念: 1.Redis String:是Redis提供的一种数据类型 2.字符串:一连串字符,例如“Tom”,表示具体的数据内容 3.SDS: 简单动态字符串,Redis自己实现的字符串结构,也是Redis String的底层实现之一 理解了这三个概念,会更容易理解后面提到的INT、EMBSTR、RAW编码格式 RedisObject与Redis String的关系 RedisObject是Redis的对象机制,在Redis中所有的数据类型的表现形式都是RedisObject。本文重点关注RedisObject中的三个字段:type(类型),encoding(编码格式),ptr(指针,指向实际存储的数据)。我们说的Redis String就是指type为REDIS_STRING,也就是说,Redis String 并不是一个独立的数据结构,而是一个 type 为 REDIS_STRING 的 RedisObject。 Redis String的三种编码格式 Redis 的 String 对象有三种常见编码:INT、EMBSTR 和 RAW。其中,EMBSTR 和 RAW 都是基于 SDS 实现的,而 INT 则直接保存整数值。 先来说Int,选择用int是为了优化SDS在存储数字时,对数字运算的不便。举个例子,比如存储18,如果String的底层全部都是SDS,那么在底层他存储的为“1”,“8”两个字符),那么如果要对“18” +1,那么就需要先从字符串转换为数字,再+1,再转换为string,最后存入到数据库。那么为了优化这个问题,Redis选择将Int也作为String的底层编码之一。 前面提到,EMBSTR 和 RAW 都是基于 SDS(简单动态字符串) 实现的。那么,SDS 到底是什么? 首先它是一个字符串数据结构,其次他可以动态扩容。那么他简单在哪里?简单在他的设计上,SDS 的设计非常简单,它并没有采用复杂的数据结构,而是在字符数组的基础上增加了一些管理字段,例如len(长度),alloc(分配内存大小),flags(存储SDS的Header类型)。 Redis String 使用 SDS 时,有两种编码方式:EMBSTR 和 RAW。分别来说明,embstr是嵌入式字符串,如果一个字符串长度不超过44字节,那么redis通常用embstr编码的SDS来保存这个字符串。如果长度大于44字节,那么就用raw编码的SDS来保存这个字符串。 首先来说明embstr编码的sds,为什么他用来存储长度小于等于44字节的字符串?要明白这个问题,我们需要先来理解一下他的名字,emb是embedded的缩写,他的意思是嵌入,那么他嵌入在哪里?答案就是嵌入在给String类型分配内存上,如何理解? 我们前面简单讲过RedisObject中用ptr指向实际的值,那么也就意味着Redis在给string类型的值分配内存的时候,除了分配redisObject的内存,还需要分配值的实际地址。而embstr就是在分配内存的时候,把redisobject和实际的值分配在一块连续的内存中。这样能带来什么好处? 1.降低分配内存次数,将创建字符串对象的内存分配次数从给redisobject一次,SDS一次,降低为一次 2.释放内存也只需要一次。 3.因为redisobject和值都在一片连续的内存中,可以更好的利用CPU缓存提升性能 那么为什么是给小于等于44字节的字符串用embstr编码的SDS,大于的44字节的用raw编码的SDS呢?因为如果字符串的长度增加,与分配的内存空间不够存储字符串,那么需要给redisobject的内存和sds一起分配空间,要修改字符串会不方便。 所以在为了解决字符串扩容无法单独扩容SDS以及修改字符串不方便的问题,raw编码的sds就出来了。raw编码中分别为redisObject和ptr分配内存空间。如果要扩容字符串,那么只要扩容SDS就行了。 String的使用 要合理的在Redis中使用String类型,我们需要知道他的常用命令和使用场景。 常用命令有: Set:设置key-value的值 Get: 根据key获取对应的值 EXISTS: 判断某个key是否存在 STRLEN:返回key的长度 DEL: 删除某个key MSET:批量设置 MGET:批量获取 INCR:将key中存储的值固定+1 INCRBY:指定增加key中存储的值 DECR:固定将key中存储的值-1 DECRBY:指定减少key中存储的值 EXPIRE:设置过期时间 TTL: 查看还有多久过期 SETNX:不存在就插入 使用场景: 缓存对象:是最常用的场景,在数据库前增加一个缓存数据库,提升获取数据的速度。 常规计数:Redis 提供的 INCR 、 DECR 等命令都是原子操作,因此非常适合实现点赞数、阅读量、库存统计等计数场景。。 分布式锁:SETNX命令是不存在就插入,那么我们可以用插入成功表示加锁成功,用插入失败表示加锁失败。 共享Session信息:在分布式系统中,用redis来存储session信息,可以避免用户在登录时被分配到不同服务器找不到session的问题 这就是为Redis String的底层实现原理就介绍到这里,希望对你有帮助