Redis基本数据结构

五种基本数据结构
  1. string(字符串)
    string是Redis中最简单的数据结构,string的内部表示就是一个字符数组。
    常见的用法是将高级语言中的对象通过JSON序列化成字符串,然后将序列化后的字符串存储到Redis。取对象时通过一次反序列化转换成应用中的对象。
    Redis中的字符串和Java中的不一样,Redis中的字符串是动态字符串,可以进行修改,内部结构的实现类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。


    string的内部结构

    上图中的capacity是string分配的空间实际大小,length指的是字符串的实际大小,当字符串的长度小于1MB的时候,扩容策略是是加倍现有空间。当字符串长度超过1MB的时候,每次扩容只会扩容1MB空间。

NOTE:字符串的最大长度为512MB

如果value是一个整数还可以进行自增操作(incr/incrby),自增操作是有范围的,它的范围在singled long的最大值和最小值之间[-2^63, 2^63],超出这个范围Redis会报错。

字符串由多个字节组成,每个字节由8bit位组成,因此可以将string结构当成bitmap(位图)数据结构来使用。

  1. list(列表)
    Redis的列表类似于Java中的LinkedList,底层实现是双向链表。因为是链表所以list的插入和删除操作非常快,时间复杂度是O(1),索引定位相对较慢,时间复杂度为O(n)。


    列表的内部结构

通过列表的一端进另一端出可以实现队列一样的结构,用于消息排队和异步逻辑处理,用来保证元素访问的顺序性。
通过列表的一端进一端出可以实现栈的结构,用Redis的列表数据结构当成栈使用场景比较少见。

深入来看Redis的列表并不是简单的一个双向链表,而是一个“快速链表”(quicklist)的结构。
首先在元素比较少的情况下,会使用一块连续的内存存储,这个结构是ziplist(压缩列表)。分配的是一块连续的内存,将所有的元素紧挨着一块存储。
当数据量比较多的时候会改成quicklist,快速列表是将链表和ziplist结合起来,在插入删除性能和空间冗余上面做了折中方案。


快速列表内部结构
  1. hash(字典)
    Redis的字典(hash)类似于Java中的HashMap,是无序字典,内部存储了许多键值对。


    hash

hash的结构和Java中HashMap的结构类似,都是“数组+链表”的二维结构,也就是说通过“链表法”去解决了hash冲突。


字典内部结构

和HashMap不同的是Redis的字典只能存储字符串(hash中的单个子key也可以用来计数),并且rehash的方式不一样,Redis为了高性能采用渐进式rehash策略。
渐进式rehash在rehash的时候,会保留新旧两个hash结构,会在后续的定时任务中渐进式的一点点将旧hash中的内容迁移到新的hash结构中,迁移完成后会用新的hash结构,旧hash结构内存被回收。

  1. set(集合)
    Redis的set类似于Java中的HashSet,内部的键值对是无序的、唯一的。内部实现相当于一个值为NULL的特殊字典。
    常常被用来实现业务中的去重功能
  2. zset(有序列表)
    zset是Redis提供的最具特色的数据结构,类似于Java中的SortedSet和HashMap的结合体。
    zset

    首先zset能保证内部value的唯一性,其次每个value都可以关联一个score(double类型会存在精度问题),score代表了value的排序权重值。zset的内部实现采用了一种“跳跃列表”的数据结构。
    zset实际上是一个复合结构,一方面使用了hash结构来存储了value和score的对应关系,另一方面需要表达出zset的顺序性,并且能够通过score的范围获取value,这就需要另外一种结构“跳跃列表”。
    跳跃列表
    首先zset需要支持随机插入和删除,所以需要链表的结构来存储数据,但是zset是根据socre排序的,当需要插入数据是要定位到指定位置插入数据,这样才能保证链表的有序。查找位置通常会采用二分法去查找,但是二分法只支持数组,所以需要采用基于链表的增强数据结构“跳跃列表”。
    跳跃列表底层结构

    上图中定位到一个红色的value-score对象,首先从header开始遍历它的向后指针,找到第一个score值小于要定位对象的score值的对象,然后循环执行上一个过程,形成如上图中红色的查找路径。

你可能感兴趣的:(Redis基本数据结构)