redis系列之数据结构详解(String,List,Hash,Set,Zset)

redis系列之数据结构详解

  • String(字符串)
    • String(字符串)与bitmap(位图)
  • List(列表)
    • List(列表)底层存储
  • Hash(字典)
  • Set(集合)
  • Zset(有序列表)

redis的数据类型的基本使用在 redis系列(一)------基本数据类型以及持久化(RDB、AOF) 中已经讲述了。
链接: https://blog.csdn.net/qq_39188134/article/details/119513301.

String(字符串)

字符串是redis里面最简单的一种数据结构,如图所示,内部就是一个字符数组,redis所有的数据结构都以唯一的key字符串来获取相应的value数据。不同类型的数据结构的差异在于value的结构不一样。
字符串结构使用非常广泛,一个常见的用途就是缓存用户信息,我们将用户信息结构体使用JSON序列化成字符串,然后将序列化后的字符串塞进Redis来缓存,同样取用户信息会经过一次反序列化的过程。

String(字符串) 在redis内部的表示如下图所示:

索引 0 1 2 3 4 5
hello字符串 h e l l o w

Redis的字符串是动态字符串,是可以修改的字符串,内部结构的实现类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配,如下图所示:
在这里插入图片描述

  • redis内部为字符串分配的实际空间capacity一般要高于实际字符串的长度len。
  • 字符串长度小于1MB时,扩容都是加倍现有的空间。
  • 如果字符串长度长度超过1MB,扩容时只会扩容1MB的空间。
  • redis限制字符串长度最大长度为512MB。

String(字符串)与bitmap(位图)

字符串是由多个字符组成,每个字符由字节组成,每个字节由8个bit组成,这便是bitmap(位图)。
例如:
a 的二进制表示是:

索引 0 1 2 3 4 5 6 7
a的二进制 0 1 1 0 0 0 0 1

b的二进制表示是:

索引 0 1 2 3 4 5 6 7
b的二进制 0 1 1 0 0 0 1 0

我们可以通过将b的二进制索引为6对应的1改为0,索引为7对应的0改为1,就可以得到 01100001 也就是a。
具体可以参照ASIIC码表查询具体字符对应的ACII码。

List(列表)

Redis的List(列表)相当于java中的LinkleList即双向链表。
插入和删除快,查询慢。
Redis的列表结构常用来做异步队列,队列结构:右边进,左边出,先进先出,具有顺序性

List(列表)底层存储

Redis中的List不是一个简单地LinkedList,而是一个称为"快速链表"(quicklist)的结构。

  • List元素较少时:使用一块连续的内存存储,这个结构称为ziplist(压缩列表)。
  • List元素较多时:会使用quicklist(快速列表),使用不连续的内存来存储数据。

list底层结构如图所示:
在这里插入图片描述

Hash(字典)

  • Redis中的字典相当于Java中的hashMap,无序字典,如下图所示。
    redis系列之数据结构详解(String,List,Hash,Set,Zset)_第1张图片

  • Redis中的字典内部存储的是键值对(key-value),结构上与hashmap一样,都是数组+链表二维结构。第一维的hash的数组位置碰撞时,就会将碰撞的元素使用链表串接起来。如图所示:
    redis系列之数据结构详解(String,List,Hash,Set,Zset)_第2张图片

  • Redis中的字典存储的值都是字符串类型,另外他们的rehash的方式不一样,在Java中HashMap在字典很大时,需要一次性全部rehash,非常耗时,Redis为了追求高性能,不能堵塞服务,采用的是渐进式rehash策略。

    • 渐进式rehash会在rehash同时保留新旧两个hash结构,查询时会同时查询两个hash结构,然后在后续的定时任务以及hash操作指令中,循序渐进地将旧hash的内容逐步迁移到新hash结构中,当迁移完成,就会使用新hash代替旧hash。
      redis系列之数据结构详解(String,List,Hash,Set,Zset)_第3张图片
  • hash结构的缺点是存储消耗高于单个字符串,使用hash或者字符串需要根据实际情况选择使用。

Set(集合)

  • Redis中Set(集合)相当于Java中hashSet,无序且不重复。
  • Redis中Set(集合)内部实现相当于一个特殊的HashSet,所有的value都是一个NULL。如图所示:
    redis系列之数据结构详解(String,List,Hash,Set,Zset)_第4张图片

Zset(有序列表)

  • Zset是Redis提供的最有趣的数据结构,类似Java中SortSet和HashMap的结合体,一方面它是一个set,保证了value的唯一性,另一方面它又给每一个value赋予一个score,score代表了value的排序权重。内部实现使用了一种叫做" 跳跃列表"的数据结构。
  • Zset可以用来排序,例如:存储粉丝列表,value值是粉丝的ID,score是关注时间,可以根据关注时间对粉丝列表进行排序。
  • 跳跃列表
    • 跳跃列表的数据结构非常特殊,同时也比较复杂。
    • zset需要支持随机的插入和删除,所以不宜使用数组(数组长度是固定的),先看下普通单向链表结构:
      在这里插入图片描述
      我们需要将这个链表按照score 值进行排序时,意味着当有新元素需要插入时,要定位到特定位置的插入点,才能保证链表是有序的,通常我们可以通过二分查找法来找到插入点,但是二分查找的对象必须是数组,只有数组才支持快速查找特点位置,链表做不到。
      跳跃列表采用的思想就是层级制,最底层元素都会串联在一起,然后每隔几个元素挑选出一个代表,再将这几个元素使用另外一级指针串起来,然后再在这些代表里面再挑出一个代表,再串起来。如下图所示:
      redis系列之数据结构详解(String,List,Hash,Set,Zset)_第5张图片
      定位插入点时,现在最顶层定位,然后再潜入下一层,一直潜入到最底层找到合适的位置,将新元素插入进去。
      在上图中,value3身兼数职,跳跃列表采用了随机策略决定某个元素可以兼职到第几层,首先L0层概率肯定是100%,而兼职到L1是50%,兼职到L2是25%,以此类推,一直到L31层。

你可能感兴趣的:(笔记)