Redis-数据结构-对象

对象

        redis没有直接使用SDS、链表、字典、压缩列表、整数集合等数据结构来实现    键值对数据库,而是基于这些数据结构创建了一个对象系统,包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象 这五种类型的对象。   

1、对象的类型与编码

        redis使用对象来表示数据库中的键和值,对象包含字符串(string)、列表(list)、哈希(hash)、集合(set)、有序集合(z-set)5中类型。当在redis数据库中创建一个键值对时,至少创建两个对象,一个用作键(键对象),另一个用作值(值对象)。

        好处是:1)可以针对不同的使用场景,为对象设置多种不同的数据结构实现,从而优化不同场景下的使用效率。2)对象系统实现了基于引用计数的内存回收机制。3)通过引用计数实现了对象共享机制,在适当的条件下通过共享同一对象来节约内存。4)redis对象带有访问时间记录信息(最后访问的时间戳),在启动maxmemory功能的情况下,较长时间未访问的键可能会优先被服务器删除

 结构

type值

 encoding值

2、字符串对象

字符串对象的编码可以是 int、raw、或者 embstr

        如果一个字符串对象保存的是整数值,并且可以用long类型表示,那么字符串对象会将整数值保存在字符串对象结构的ptr属性里(将void*转换成long),并将字符串对象的编码设置为int;


        如果字符串对象保存的是一个字符串值,并且长度大于32字节,那么字符串对象将使用SDS来保存这个字符串值,并将编码设置为rew;

        如果字符串对象保存的是一个字符串值,并且长度小于等于32字节,那么字符串对象将使用embstr编码的SDS来保存之歌字符串值。

        embstr编码是专门用于保存短字符串的一种优化编码方式,和raw编码一样,都使用sdshdr结构来表示。但raw编码会调用两次内存分配分别创建redisObject结构和sdshdr结构,而embstr编码则动过调用一次内存分配来分配一块连续的空间,空间中依次包含redisObject和sdshdr两个结构。

embstr编码字符串对象在执行命令时,产生的效果和raw编码的字符串对象是相同的。

embstr编码的好处:

        1)embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降为一次;

        2)释放embstr编码字符串对象只需要调用一次内存释放函数;

        3)embstr编码字符串对象所有数据保存在一块连续内存内,能更好地利用缓存的优势。

long double类型表示的数在Redis中作为字符串值来保存,如果要保存一个浮点数到字符串对象,需要先将浮点数转换成字符串值,然后再保存转换所得的字符串值。

3、列表对象

列表对象的编码可以是 ziplist linkedlist

ziplist编码使用压缩列表作为底层实现,么个压缩列表节点(entry)保存一个元素。

linkedlist编码使用双端链表作为底层实现,每个双端链表节点(node)都保存一个字符串对象,么个字符串对象保存一个元素。

linkedlist编码的列表对象在底层的双端列表结构中包含了多个字符串对象,字符串对象是Redis五种类型对象中唯一会被其他四种类型对象嵌套的对象。

使用ziplist编码需要同时满足以下2个条件,否则使用linkedlist编码:

1)列表对象保存的所有字符串元素的长度都小于64字节;

2)列表对象保存的元素数量小于512个;

4、哈希对象

哈希对象的编码可以是 ziplist 或者 hashtable

ziplist编码 使用压缩列表作为底层实现,每当有新的键值对加入到哈希对象时,先将保存了键的节点推入列表表尾,再讲保存了值的节点推入列表表尾。1)保存了同一键值对的连个节点紧挨在一起,保存键的节点在前,保存值的节点在后;2)先添加到哈希对象的键值对会被放在压缩列表的表头方向,后添加的键值对会被放在压缩列表的表尾方向。

hashtable编码 的哈希对象使用字典作为底层实现,每个键值对使用一个字典键值对保存:字典的键都是一个字符串对象,保存哈希对象的键;字典的值都是一个字符串对象,保存键值对的值。

编码转换

哈希对象保存的所有键值对的键和值的字符串长度都小于64字节;

哈希对象保存的键值对数量小于512个;

同时满足以上2个条件使用ziplist编码;否则使用hashtable编码

5、集合对象

集合对象set的编码可以是 intset或者hashtable

intset编码的集合对象使用整数集合作为底层实现

hashtable编码的集合对象使用字典作为底层实现,字典的键保存集合元素,字典的值为null。


当集合对象同时满足以下两个条件时,使用intset编码

1)集合对象保存的所有元素都是整数值;

2)集合对象保存的元素数量不超过512个。

6、有序集合对象

有序集合 zset 编码可以是ziplist或者skiplist

ziplist编码 每个集合元素使用两个相连的节点来保存,第一个节点保存元素成员(member),第二个元素保存元素的分值(score)。压缩列表内的集合元素按照分值的从小到大排序。

skiplist编码 使用zset机构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表。

zset结构中的zsl跳跃表按分值从小到大保存了所有集合元素,每个节点保存一个元素:跳跃表节点的object属性保存元素(member),跳跃表节点的score属性保存分值(score);zset结构中dict字典为有序集合创建了一个从成员到分值的映射,字典中每个键值对保存一个集合元素:字典的键保存元素成员(member),字典的值保存元素的分值(score),通过这个字典可以用O(1)复杂度查找给定成员的分值

当同时满足以下条件时,对象使用ziplist编码

1)由于集合保存的元素数量小于128个;

2)有序集合保存的所有元素成员的长度小于64字节。

7、类型检查与命令多态

        7.1 类型检查

Redis中用于操作键的命令基本上分为两种类型:

1)可以对任何类型的键执行,如DEL、EXPIRE、RENAME、TYPE、OBJECT

2)只能UI特定类型的键执行

    SET、GET、APPEND、STRLEN命令只能对 string类型执行

    HDEL、HSET、HGET、HLEN命令只能对 hash类型执行

    RPUSH、LPOP、LINSERT、LLEN 命令只能对 list类型执行

    SADD、SPOP、SINTER、SCARD命令只能对 set类型执行

    ZADD、ZCARD、ZRANK、ZSCORE命令只能对 zset类型执行

为了确保只有指定类型的键可以执行某些特定的命令,在执行一个类型特定的命令之前,Redis会先检查输入键的类型是否正确,然后再决定是否执行给定的命令。

类型检查通过redisObject结构的type属性来实现。


7.2 多态命令

Redis除了根据值对象的类型判断键是否能够执行命令之外,还会根据值对象的编码方式,选择正确的命令实现代码来执行命令。

DEL、EXPIRE 等命令是基于类型(type)的多态,一个命令可以同时用于处理多种不同类型的键

LLEN、SET等命令是基于编码(encoding)的多态,一个命令可以同时用于处理多种不同的编码


8、内存回收

Redis在自己的对象系统中构建了一个引用计数技术实现的内存回收机制。通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。

对象的引用计数会随着对象的使用状态而不断变化:

1)在创建一个新对象时,引用计数的值被初始化为1;

2)当对象被一个新程序使用时,它的引用计数值+1;

3)当对象不再被一个程序使用时,它的引用计数值-1;

4)当对象的引用计数值为0时,对象所占用的内存会被释放。

9、对象共享

除了用于实现引用计数内存回收机制之外,对象的引用计数属性还带有共享的作用。

在Redis中,让多个键共享同一个值对象需要执行以下两个步骤:

1)将数据库键的值指针指向一个现有的值对象;

2)将共享的值对象的引用计数+1。

Redis会在初始化服务器时,创建一万个字符串对象,包含了从 0 到 9999 的所有整数值,当服务器需要用到值为0到9999的字符串对象时,服务器就会使用这些共享对象。

共享对象不仅字符串键可以使用,嵌套了字符串对象的对象都可以使用这些共享对象。

Redis只对 0 到 9999 的字符串对象进行共享

10、对象空转时长

redisObject的 lru 属性记录了对象最后一次被命令程序访问的时间;

空转时长= 当前时间 - lru时间

OBJECT IDLETIME 命令在访问键的值对象时,不会修改值对象的lru属性。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • redis使用对象系统来构建键值对数据库,这个对象系统包括:字符串对象,列表对象,哈希对象,集合对象和有序集合对象...
    MontyOak阅读 378评论 0 0
  • Redis的内存优化 声明:本文内容来自《Redis开发与运维》一书第八章,如转载请声明。 Redis所有的数据都...
    meng_philip123阅读 18,881评论 2 29
  • 参考来源 Redis的内存优化 Redis所有的数据都在内存中,而内存又是非常宝贵的资源。对于如何优化内存使用一直...
    秦汉邮侠阅读 1,283评论 0 2
  • redis没有直接使用数据结构来实现键值对的数据库,而是基于这些数据结构创建了一个对象系统,包含字符串对象、列...
    忘记M阅读 400评论 0 0
  • 知识点 redis数据库中的每一个键值对的键和值都是一个对象 redis共有字符串、列表、哈希、集合、有序集合五种...
    wh4763阅读 176评论 0 0