定义
String 就是字符串,最大为 512 MB。
使用场景
存字节数据、文本数据、序列化后的对象数据等。
常用操作
创建、更新 语法:SET key value 设置一个 key 的值为 value,成功则返回 OK。
查询 语法:GET key 查询某个 key,存在就返回对应的 value,不存在返回 nil。
删除 语法:DEL key [key …] 删除一个或多个 key,返回值为成功删除几行。
底层实现
三种编码方式,如下。
- INT,存整型;
- EMBSTR,如果字符串小于等于阈值字节,使用 EMBSTR 编码;
- RAW,如果字符串大于阈值字节,使用 RAW 编码。
3.2 版本前,阈值是 39 字节,之后是 44 字节。
EMBSTR 和 RAW 都由 RedisObject 和 SDS 两个结构组成,区别在于 EMBSTR 下的 RedisObject 和 SDS 是连续内存,RAW 是分开的。
EMBSTR 的优点,可以一次性分配空间,缺点是如果重新分配空间,整体都需要再分配,因此,EMBSTR 设计为只读,任何写操作之后,EMBSTR 都会变为 RAW,理念是发送过修改的字符串通常认为是易变的。
随着我们的操作,编码可能会转换:
- INT -> RAW:存的内容不再是整数,或者大小超过了 long 类型;
- EMBSTR -> RAW:写操作之后。
字符串编码 EMBSTR 和 RAW 都包含了一个叫 SDS 的结构,它是 Simple Dynamic String 的缩写,下面详细介绍 SDS。
为什么需要 SDS
在 C 语言中,字符串用一个 '\0' 结尾的 char 数组表示,但对于 Redis 来说并不好用:
- 对字符串进行追加,需要重新分配内存;
- 每次计算字符串长度的时间复杂度为 O(N);
- 非二进制安全,二进制安全是指公平对待每一个字符,不特殊处理某个字符。 在 Redis 内部,字符串追加和长度计算很常见,不应该成为性能瓶颈,于是 Redis 封装了一个 SDS 的字符串结构,解决上述问题。
SDS 的结构中,有两个关键字段,一个是 len,表示已使用的内存;一个是 alloc,表示一共分配了多少内存。alloc - len 的差值就是预留空间大小。通过 SDS 的结构可以看出 SDS 是如何对症下药,解决问题的:
- 增加长度字段 len,快速返回长度;
- 增加预留空间,为后续追加数据留余地;
- 不再以 '\0' 作为判断标准,二进制安全。
SDS 的预留空间大小规则如下。
- len 小于 1M 的情况,alloc = 2*len,即预留 len 大小的空间;
- len 大于 1M 的情况,alloc = 1M+len,即预留 1M 大小的空间。
常见问题
- Set 一个已有的数据会发生什么?
- 浮点型在 String 中用什么表示?
- String 可以有多大?
- Redis 字符串是怎么实现的?
- SDS 有什么用?