Redis数据结构之字符串-SDS

C语言中,传统的字符串表示是以空字符结尾的字符数组,Redis的字符串没有直接使用该表示,而是选择构建了一种名为简单动态字符串(simple dynamic string, SDS)的抽象类型。

Redis中,C字符串只会作为字符串字面量(string literal)用在一些无需对字符串值进行修改的地方,例如打印日志等场景。

结构

struct SDS<T> {
    T capacity;      // 数组容量
    T len;           // 数组长度
    bytes flags;    // 特殊标识位
    bytes[] content; // 字节数组,存储字符串
};
  • capacity:分配给字节数组的长度

  • len:字节数组存储内容的实际长度

Redis规定字符串长度不能超过512M

绝大部分情况下,认为不会对字符串进行append操作,所以创建字符串时lencapacity一样长,即不分配冗余空间。

SDS对比C字符串

  • 获取字符串长度时间复杂度为O(1):直接使用len属性

  • 有效杜绝缓冲区溢出:APPEND操作先分配空间,再执行拼接

  • 减少修改字符串可能带来的内存重分配次数:空间预分配,动态扩容提供冗余空间

  • 二进制安全:SDS使用len的值而不是空字符来判断字符是否结束,所以字节数组可以用来保存一系列二进制数据

  • 兼容部分C字符串函数

扩容策略

Redis的字符串扩容策略主要根据字符串长度len来区分。

len小于1M时,采用加倍策略,即保留100%的冗余空间。

len超过1M之后,为避免加倍后的冗余空间过大而导致浪费,每次扩容只分配1M冗余空间。

embstrraw

Redis的字符串有两种存储方式:

  • embstr:将RedisObject对象头和SDS对象连续存在一起,使用malloc方法一次性分配

  • raw:使用两次malloc,两个对象头在内存地址上不连续

不同存储形式的转换:

  • 对于SDS字符串,如果长度小于等于39个,则使用embstr形式存储,否则使用raw形式存储

    •   
      >>> set a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      >>> STRLEN a
      39
      >>> OBJECT ENCODING a
      "embstr">>> set b aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
      >>> STRLEN b
      40
      >>> OBJECT ENCODING b
      "raw"
  • 对于embstr,该字符串实际上是只读的,对该对象执行任何修改命令后时,Redis会先将对象编码转为raw,然后执行修改命令

    •   

      >>> set a hello
      >>> OBJECT ENCODING a
      "embstr"
      >>> APPEND a world
      >>> OBJECT ENCODING a
      "raw"
posted @ 2019-08-31 17:08  Jeemzz  阅读(286)  评论(0编辑  收藏  举报