一、Redis对象结构
Redis中的每个对象都由一个redisObject结构表示:

typedef struct redisObject {
unsigned type;//类型
unsigned encoding;//编码
void *ptr;//指向底层实现数据结构的指针
int refcount;//引用计数
unsigned lru;//对象最后一次被程序访问的时间
}

1. type:Redis对象类型
redisObject的'type'属性记录了对象的类型:

type命令:返回键对应的值对象的类型。

2. encoding:Redis对象编码和底层实现
redisObject的'encoding'属性记录了对象所使用的编码(记录对象底层实现的数据结构):

每种类型的对象都至少使用了两种不同的编码:

object encoding命令:查看一个数据库键的值对象的编码。

  通过'encoding'属性来设定Redis对象所使用的编码,而不是为特定类型的对象关联一种固定的编码,提升了Redis的灵活性和效率,因为Redis可以根据不同的使用场景来为一个对象设置不同的编码, 从而优化对象在某一场景下的效率。

  Redis服务器执行一个命令时,首先通过'type'属性进行类型检查,判断对象类型是否支持当前命令,然后再根据'encoding'属性判断对象的编码方式,选择正确的命令实现代码来执行命令。

3. refcount:Redis对象引用计数

  Redis对象通过其'refcount'属性实现对象内存回收与对象共享。当Redis需要创建一个键值对的时候,如果已经存在一个与需要创建的值对象完全相同的值对象,Redis不会创建一个新的值对象,而是将键对象的值指针指向这个现有的完全相同的值对象,同时将这个值对象的'refcount'属性值加一,从而实现对象共享,节约内存;当一个键对象不再指向这个值对象的时候,则值对象的'refcount'属性值减一,当'refcount'属性值为0的时候,则将对象释放,将内存回收。

  目前,Redis会在初始化服务器时,创建一万个字符串对象,这些对象包含了从0到9999的所有整数值,当服务器需要用到值为0到9999的字符串对象时,服务器就会使用这些共享对象,而不是新创建对象。创建共享字符串对象的数量可以通过修改redis.h/REDIS_SHARED_INTEGERS常量来修改。

  当服务器考虑将一个共享对象设置为键的值对象时,程序会先验证给定的共享对象和键想创建的目标对象是否完全相同,共享对象保存的值越复杂,验证所需的复杂度就越高,消耗的CPU时间也会越多,所以Redis只对包含整数值的字符串对象进行共享,其验证复杂度为O(1)。
引用计数查看命令:object refcount

4. lru:Redis对象最后一次被程序访问的时间
对象的空转时长 = 当前时间 - 对象的'lru'属性值
查看对象空转时长的命令:object idletime(这个命令不会改变对象的'lru'属性值)
  如果服务器打开了maxmemory选项,并且服务器用于回收内存的算法为volatile-lru或者allkeys-lru,那么当服务器占用的内存数超过了maxmemory选项所设置的上限值时,空转时长较高的那部分键会优先被服务器释放,从而回收内存(可以参考配置文件的maxmemory选项和maxmemory-policy选项)。

二、字符串对象
1. 字符串对象根据其值类型的不同,使用不同的编码方式,对应关系如下:
(1)可以用long类型表示的整数值:int
(2)小于等于39字节的字符串值:embstr(底层结构为embstr编码的SDS)
(3)大于39字节的字符串值:raw(底层结构为SDS)
注:浮点数在Redis中也是作为字符串值来保存的,只是在有需要的时候会将其转化为浮点数值,执行某些操作之后,存入Redis时又转换为字符串值。
2. 关于embstr编码
  embstr编码是专门用于保存短字符串的一种优化编码方式,这种编码和raw编码一样,都使用redisObject结构和sdshdr结构来表示字符串对象,但raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的空间,空间中依次包含redisObject和sdshdr两个结构。
使用embstr编码的字符串对象来保存短字符串值的好处:
(1)embst 编码将创建字符串对象所需的内存分配次数从raw编码的两次降低为一次。
(2)释放embstr编码的字符串对象只需要调用一次内存释放函数,而释放raw编码的字符串对象需要调用两次内存释放函数。
(3)因为embstr编码的字符串对象的所有数据都保存在一块连续的内存里面,所以这种编码的字符串对象比起raw编码的字符串对象能够更好地利用缓存带来的优势。
3. 三种编码的字符串对象结构
(1)int编码的字符串对象结构示例:

(2)raw编码的字符串对象结构示例:

(3)embstr编码的字符串对象结构示例:

4. 编码的转换
  int编码的字符串对象和embstr编码的字符串对象在条件满足的情况下,会被转换为raw编码的字符串对象。
  另外,因为Redis没有为embstr编码的字符串对象编写任何相应的修改程序(只有int编码的字符串对象和raw编码的字符串对象有这些程序),所以embstr编码的字符串对象实际上是只读的:当我们对embstr编码的字符串对象执行任何修改命令时,程序会先将对象的编码从embstr转换成raw,然后再执行修改命令;因为这个原因,embstr编码的字符串对象在执行修改命令之后,总会变成一个raw编码的字符串对象。

三、列表对象
1. 列表对象的编码可以是ziplist(底层结构为压缩列表)或者linkedlist(底层结构为双端链表)。
2. 列表对象结构
(1)使用ziplist编码的列表对象结构示例:

(2)使用linkedlist编码的列表对象结构示例:

其中双端链表中又嵌套了多个字符串对象,这里的‘StringObject’只是简化表示。

3. 编码转换
  当列表对象可以同时满足以下两个条件时, 列表对象使用ziplist编码:
(1)列表对象保存的所有字符串元素的长度都小于64字节(可由参数list-max-ziplist-value配置);
(2)列表对象保存的元素数量小于512个(可由参数list-max-ziplist-entries配置);
不能同时满足这两个条件的列表对象需要使用linkedlist编码。

四、哈希对象
1. 哈希对象的编码可以是ziplist(底层结构为压缩列表)或hashtable(底层结构为字典)。
2. 哈希对象结构
(1)使用ziplist编码的哈希对象结构示例:

其中压缩列表结构示例如下:

(2)使用hashtable编码的哈希对象结构示例:

3. 编码转换
  当哈希对象可以同时满足以下两个条件时, 哈希对象使用ziplist编码:
(1)哈希对象保存的所有键值对的键和值的字符串长度都小于64字节(可由参数hash-max-ziplist-value配置);
(2)哈希对象保存的键值对数量小于512个(可由参数hash-max-ziplist-entries配置);
不能同时满足这两个条件的哈希对象需要使用hashtable编码。

五、集合对象
1. 集合对象的编码可以是intset(底层结构是整数集合)或hashtable(底层结构是字典)。
2. 集合对象结构
(1)使用intset编码的集合对象结构示例:

(2)使用hashtable编码的集合对象结构示例:

(使用字典键值对中的键来存储集合元素,而值都被设置为NULL)
3. 编码转换
  当集合对象可以同时满足以下两个条件时,对象使用intset编码:
(1)集合对象保存的所有元素都是整数值;
(2)集合对象保存的元素数量不超过512个(可由参数set-max-intset-entries配置);
不能满足这两个条件的集合对象需要使用hashtable编码。

六、有序集合对象
1. 有序集合的编码可以是ziplist(底层结构为压缩列表)或skiplist(底层结构为跳跃表+字典)。
2. 有序集合对象结构
(1)使用ziplist编码的有序集合对象结构示例:

其中压缩列表结构示例如下:

(2)使用skiplist编码的有序集合对象
  使用skiplist编码的有序集合对象同时使用一个字典和一个跳跃表来实现。
结构定义:

结构示例:

其中zset结构示例如下:

  理论上有序集合完全可以单独使用字典或跳跃表其中一种数据结构来实现,但是性能上比同时使用这两种数据结构都会有所下降。使用跳跃表可以提高对有序集合进行范围型操作的效率,而使用字典则可以快速找到指定成员的分值,只使用其中一种数据结构会丢失另一种数据结构在对应操作上带来的效率。另外,有序集合中的字典和跳跃表会通过指针共享相同元素的成员和分值,并不会造成任何数据重复,也不会浪费额外内存。
3. 编码转换
  当有序集合对象可以同时满足以下两个条件时, 对象使用ziplist编码:
(1)有序集合保存的元素数量小于128个(可由参数zset-max-ziplist-entries配置);
(2)有序集合保存的所有元素成员的长度都小于64字节(可由参数zset-max-ziplist-value配置);
不能满足以上两个条件的有序集合对象将使用skiplist编码。

Redis对象的设计与实现的更多相关文章

  1. Redis集群设计原理

    ---恢复内容开始--- Redis集群设计包括2部分:哈希Slot和节点主从,本篇博文通过3张图来搞明白Redis的集群设计. 节点主从: 主从设计不算什么新鲜玩意,在数据库中我们也经常用主从来做读 ...

  2. 面试官:你了解过Redis对象底层实现吗

    上一章我们讲了Redis的底层数据结构,不了解的人可能会有疑问:这个和平时用的五大对象有啥关系呢?这一章我们就主要解释他们所建立的联系. 看这个文件之前,如果对ziplist.skiplist.int ...

  3. Redis之对象篇——Redis对象系统简介

    Redis之对象篇--Redis对象系统简介 前言     之前几篇文章,简单介绍 Redis用到的所有主要数据结构,简单动态字符串(SDS).双端链表.字典.压缩列表.整数集合.跳跃表. 图解Red ...

  4. Redis对象——字符串

    文章导航-readme 前言     上一篇文章Redis之对象篇--Redis对象系统简介简单介绍了Redis的对象系统.Redis使用对象来表示数据库中的键和值每个对象都由一个redisObjec ...

  5. Redis键值设计(转载)

    参考资料:https://blog.csdn.net/iloveyin/article/details/7105181 丰富的数据结构使得redis的设计非常的有趣.不像关系型数据库那样,DEV和DB ...

  6. 【集群】Redis集群设计原理

    Redis集群设计包括2部分:哈希Slot和节点主从 节点主从: 主从设计不算什么新鲜玩意,在数据库中我们也经常用主从来做读写分离,直接上图: 图上能看得到的信息: 1, 只有1个Master,可以有 ...

  7. 三张图秒懂Redis集群设计原理

    转载Redis Cluster原理 转载https://blog.csdn.net/yejingtao703/article/details/78484151 redis集群部署方式: 单机 主从 r ...

  8. 【redis源码阅读】redis对象

    结构定义 在redis中,对象的数据结构定义如下: ​typedef struct redisObject { ​unsigned type:4; ​unsgined encoding:4; ​uns ...

  9. Redis对象类型

    Redis对象类型 Redis基于基础的数据结构创建的对象: 字符串对象. 列表对象. 哈希对象. 集合对象 有序集合对象. 对象回收:Redis对象系统实现了基于引用计数技术的内存回收机制,当程序不 ...

随机推荐

  1. 带二级目录的Nginx配置------目前找到的最简单的方法

    由于项目不知一个,所以不得不为每一个项目建一个专有的文件夹,这就导致了在配置nginx的时候会出现二级目录 目前找到的最简单的方法     - step1:修改 vue.config.js   添加配 ...

  2. 如何用node命令和webpack命令传递参数

    1. 比如在项目中我们的publicPath需要根据服务器环境的变化而变化,这时我们会写一个配置文件,在webpack.config.js中读取,可以 如何才能 取到变量呢? 这里介绍一种方法: 如果 ...

  3. 一个batch如何通过一个网络

    一个batch下所有的图片一起经过整个网络,不是说一张图片经过网络后再让下一张进入网络,这样一个batch一起通过网络计算速度比一张一张这样快

  4. CPP-基础:非静态成员函数后面加const,以及mutable修饰成员变量

    非静态成员函数后面加const(加到非成员函数或静态成员后面会产生编译错误),表示成员函数隐含传入的this指针为const指针,决定了在该成员函数中,任意修改它所在的类的成员的操作都是不允许的(因为 ...

  5. Active Directory网域

    Active Directory网域 3.1Windows网络的管理方式 3.1.1工作组模式 工作组由一组用网络连接在一起的计算机组成,他们将计算机内的资源共享给用户访问.工作组网络也被称为“对等式 ...

  6. Python基础篇 -- 字符串

    字符串 字符串是不可变的对象,任何操作对原字符串是不会有任何影响的. 索引和切片 索引 . 索引就是下标, 下标从 0 开始, 使用[] 来获取数据 s1 = "0123456" ...

  7. Mac 输入法小技巧

    相信使用Mac的朋友第一次使用Mac首先要考虑的就是输入法的问题,现在越来越多的第三方输入法都开始支持Mac平台,是否有同学仍然执着于看似“不符”国人习惯用法的OS X自带拼音输入法呢?自带的拼音输入 ...

  8. ThreadLocal类使用说明

      ThreadLocal类用于创建一个线程本地变量   在Thread中有一个成员变量ThreadLocals,该变量的类型是ThreadLocalMap,也就是一个Map,它的键是threadLo ...

  9. hihoCoder第一周---最长回文子串(1032)

    其实这就是mancher算法的板子题,贴个代码好了. 思想请见我的另一篇博客: https://blog.csdn.net/qq_41090676/article/details/86768361 # ...

  10. 降维算法-PCA主成分分析

    1.PCA算法介绍主成分分析(Principal Components Analysis),简称PCA,是一种数据降维技术,用于数据预处理.一般我们获取的原始数据维度都很高,比如1000个特征,在这1 ...