数据类型的底层数据结构sds?
每次在Redis数据库中创建一个键值对时,至少会创建两个对象,一个是键对象,一个是值对象,而Redis中的每个对象都是由 redisObject对象,对象的属性有type类型,encoding编码,*ptr指向底层数据结构的指针,refcount引用计数,lru记录最后一次被程序访问的时间
对象的type属性记录了对象的类型,就是前面讲的五大数据类型,在Redis中,键总是一个字符串对象,而值可以是字符串、列表、集合等对象。对象的 prt 指针指向对象底层的数据结构,而数据结构由 encoding 属性来决定,refcount引用计数用作内存回收机制:创建一个新对象,属性 refcount 初始化为1,对象被一个新程序使用,属性 refcount 加 1,对象不再被一个程序使用,属性 refcount 减 1,当对象的引用计数值变为 0 时,对象所占用的内存就会被释放。
字符串是Redis最基本的数据类型,不仅所有key都是字符串类型,字符串的长度不能超过512M。
①、编码:字符串对象的编码可以是int,raw或者embstr。int 编码是用来保存整数值,raw编码是用来保存长度大于44字节长字符串,而embstr是用来保存长度小于44字节短字符串。其实 embstr 编码是专门用来保存短字符串的一种优化编码,embstr与raw都使用redisObject和sds保存数据,区别在于,embstr的使用只分配一次内存空间(因此redisObject和sds是连续的),而raw需要分配两次内存空间(分别为redisObject和sds分配空间)。因此与raw相比,embstr的好处在于创建时少分配一次空间,删除时少释放一次空间,以及对象的所有数据连在一起,寻找方便。而embstr的坏处也很明显,如果字符串的长度增加需要重新分配内存时,整个redisObject和sds都需要重新分配空间,因此redis中的embstr实现为只读。说明:Redis中对于浮点数类型也是作为字符串保存的,在需要的时候再将其转换成浮点数类型。
②、编码的转换:当 int 编码保存的值不再是整数,或大小超过了long的范围时,自动转化为raw。对于 embstr 编码,由于 Redis 没有对其编写任何的修改程序(embstr 是只读的),在对embstr对象进行修改时,都会先转化为raw再进行修改,因此,只要是修改embstr对象,修改后的对象一定是raw的,无论是否达到了44个字节。
list 列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边),它的底层实际上是个链表结构。
①、编码:列表对象的编码可以是 ziplist(压缩列表) 和 linkedlist(双端链表)。
②、编码转换:当同时满足列表保存元素个数小于512个,每个元素长度小于64字节条件时,使用ziplist(压缩列表)编码,不能满足这两个条件的时候使用 linkedlist 编码。这两个条件可以在redis.conf 配置文件中的 list-max-ziplist-value选项和 list-max-ziplist-entries 选项进行配置。
哈希对象 哈希对象的键是一个字符串类型,值是一个键值对集合。
①、编码:哈希对象的编码可以是 ziplist 或者 hashtable。当使用ziplist,也就是压缩列表作为底层实现时,新增的键值对是保存到压缩列表的表尾。hashtable 编码的哈希表对象底层使用字典数据结构,哈希对象中的每个键值对都使用一个字典键值对。
说明:压缩列表是Redis为了节省内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型数据结构,相对于字典数据结构,压缩列表用于元素个数少、元素长度小的场景。其优势在于集中存储,节省空间。
②、编码转换:当同时满足列表保存元素个数小于512个,每个元素长度小于64字节条件时,使用ziplist(压缩列表)编码,不能满足这两个条件的时候使用 hashtable 编码。这两个条件可以在redis.conf 配置文件中的 set-max-intset-entries 选项进行配置。
集合对象 集合对象 set 是 string 类型(整数也会转换成string类型进行存储)的无序集合。注意集合和列表的区别:集合中的元素是无序的,因此不能通过索引来操作元素;集合中的元素不能有重复。
①、编码:集合对象的编码可以是 intset 或者 hashtable。intset 编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合中。hashtable 编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,这里的每个字符串对象就是一个集合中的元素,而字典的值则全部设置为 null。这里可以类比Java集合中HashSet 集合的实现,HashSet 集合是由 HashMap 来实现的,集合中的元素就是 HashMap 的key,而 HashMap 的值都设为 null。
②、编码转换:集合对象中所有元素都是整数,集合对象所有元素数量不超过512,不能满足这两个条件的就使用 hashtable 编码。第二个条件可以通过配置文件的 set-max-intset-entries 进行配置。
有序集合 有序集合为每个元素设置一个分数(score)作为排序依据。
①、编码:有序集合的编码可以是 ziplist 或者 skiplist。ziplist 编码的有序集合对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个节点保存元素的分值。并且压缩列表内的集合元素按分值从小到大的顺序进行排列,小的放置在靠近表头的位置,大的放置在靠近表尾的位置。skiplist 编码的有序集合对象使用 zet 结构作为底层实现,一个 zset 结构同时包含一个字典和一个跳跃表。字典的键保存元素的值,字典的值则保存元素的分值;跳跃表节点的 object 属性保存元素的成员,跳跃表节点的 score 属性保存元素的分值。这两种数据结构会通过指针来共享相同元素的成员和分值,所以不会产生重复成员和分值,造成内存的浪费。
说明:其实有序集合单独使用字典或跳跃表其中一种数据结构都可以实现,但是这里使用两种数据结构组合起来,原因是假如我们单独使用 字典,虽然能以 O(1) 的时间复杂度查找成员的分值,但是因为字典是以无序的方式来保存集合元素,所以每次进行范围操作的时候都要进行排序;假如我们单独使用跳跃表来实现,虽然能执行范围操作,但是查找操作有 O(1)的复杂度变为了O(logN)。因此Redis使用了两种数据结构来共同实现有序集合。
②、编码转换:有序集合对象同时满足保存的元素数量小于128,保存的所有元素长度都小于64字节时,对象使用 ziplist 编码,不能满足两个条件的使用 skiplist 编码。两个条件通过Redis配置文件zset-max-ziplist-entries 选项和 zset-max-ziplist-value 进行修改。
5412

被折叠的 条评论
为什么被折叠?



