1.SDS

  • 没有使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS) 的抽象类型,并将SDS用作Redis的默认字符串表示。在Redis里,包含字符串值得键值对在底层都是由DS来实现的。
  • SDS还被用作缓冲区(buffer):AOF模块中的AOF缓冲区,以及客户端状态中的输入缓冲区,都是由SDS实现的。
SDS定义:
struct sdshdr{
  // 记录buf数组已使用字节数量
  int len;
  // 记录buf数组中未使用字节的数量
  int free;
  // 字节数组,用于保存字符串
  char buf[];
}

redis的sds好处 redis中的sds_Redis

SDS相比较于c字符串的好处
  1. 取字符长度,SDS直接读取len属性
  2. 杜绝缓冲区溢出。C字符串拼接时时假定已经为拼接的字符串预留了足够多的内存,如果这个假定不成立,那么就会产生缓冲区溢出。而SDS是这样做的:SDS的API会会先检查SDS的空间是否满足所需的要求,如果不满足,API自动将空间扩展至所需大小。
  3. 减少修改字符串长度时所需的内存重分配次数。
  4. 二进制安全。
  5. 兼容部分C字符串函数。

redis的sds好处 redis中的sds_redis的sds好处_02

SDS空间分配策略:
  • 通过未使用空间,SDS实现了空间预分配惰性空间释放两种优化策略。
  • 空间预分配: 用于优化SDS的字符增长操作:程序不仅会为SDS分配修改所必须要的空间,还会为SDS分配额外的未使用空间。(**具体:**1. len(SDS)< 1mB时,分配len(free)=len,2.如果len(SDS) >1mb,分配len(free)=1mb)
  • 惰性空间释放: 用于优化SDS字符缩短操作:当缩短字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待将来使用。

2. 对象系统

  • Redis基于以上数据结构创建了一个对象系统,每种对象都用到了至少一种之前介绍的数据结构。
  • 每次当我们在Redis中新创建一个键值对时,我们至少会创建两个对象,一个对象用作键值对的键(键对象),另一个对象用作键值对的值(值对象)。

使用对象系统的好处:

(1)在执行命令时,根据对象类型判断一个对象是否可以执行给定的命令

(2)针对不同的使用场景,为对象设置多种不同的数据结构,从而优化对象在不同场景下的使用效率;

(3)基于对象引用计数技术实现内存的回收;

(4)通过引用计数技术实现对象的共享;

在Redis中每个对象都由一个redisObject结构表示,包含了type,encoding,ptr属性:

/* 
 * Redis 对象 
 */  
typedef struct redisObject {  
    // 类型  
    unsigned type:4;  
    // 编码  
    unsigned encoding:4;  
    // 对象最后一次被访问的时间  
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */  
    // 引用计数  
    int refcount;  
    // 指向实际值的指针  
    void *ptr;  
} robj;
类型:

redis的sds好处 redis中的sds_数据结构_03

其中, 键总是一个字符串对象,而值可以是其上任意一种。

Type命令的实现方式: Type(键名) : 返回的结果为数据库键对应的值对象的类型。

redis的sds好处 redis中的sds_Redis_04

编码和底层实现:

ptr:指向对象的底层实现数据结构,而这些数据结构由对象的encoding属性决定。

encoding:记录了对象所使用的编码,也就是说这个对象使用了什么数据结构作为对象的底层实现,有如下:

redis的sds好处 redis中的sds_字符串_05

每种类型的对象至少使用了两种不同的编码,如下表所示对应关系:

redis的sds好处 redis中的sds_数据结构_06

使用OBJECT ENCODING命令可以查看一个数据库键的值对象的编码。

  • 使用encoding属性来设定对象所使用的编码,极大的提升了Redis的灵活性和效率。

3. 各对象对应的编码

  • String对象的编码可以是int、embstr、raw。
  • 列表对象的编码可以是ziplist或者linkedlist。
  • 哈希对象的编码可以是ziplist或者是hashtable。
  • 集合对象的编码可以是intset或者hashtable。
  • 有序集合的编码可以是ziplist或者skiplist。

参考:《Redis设计与实现》第二版—黄健宏