Redis对象(一) String

定义

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 是如何对症下药,解决问题的:

  1. 增加长度字段 len,快速返回长度;
  2. 增加预留空间,为后续追加数据留余地;
  3. 不再以 '\0' 作为判断标准,二进制安全。

SDS 的预留空间大小规则如下。

  • len 小于 1M 的情况,alloc = 2*len,即预留 len 大小的空间;
  • len 大于 1M 的情况,alloc = 1M+len,即预留 1M 大小的空间。

常见问题

  • Set 一个已有的数据会发生什么?
  • 浮点型在 String 中用什么表示?
  • String 可以有多大?
  • Redis 字符串是怎么实现的?
  • SDS 有什么用?
Redis对象(二) List
掀起你的盖头来,让我看看HTTP的内容协商