Redis之数据结构

217 阅读5分钟

redis重要的5种数据结构

image.png

RedisObject

image.png image.png

string(字符串)

应用场景

string 类型的应用场景非常广泛,比如:

  • 缓存数据,提高访问速度和降低数据库压力。
  • 计数器,利用 incr 和 decr 命令实现原子性的加减操作。
  • 分布式锁,利用 setnx 命令实现互斥访问。
  • 限流,利用 expire 命令实现时间窗口内的访问控制。

编码类型

在存储字符串的时候,redis会根据数据的长度判断使用哪种结构

  • 如果是可以转为整型,则用整数类型进行存储(REDIS_ENCODING_INT)
  • 如果长度小于等于44个字节,就会选择embstr(共64字节) 结构(REDIS_ENCODING_EMBSTR)
  • 如果长度大于44个byte,就会选择raw结构(REDIS_ENCODING_RAW)

SDS

简单动态字符串SDS(simple dynamic string),是Redis的默认字符串表示方式。 image.png

  • free 属性的值为 0 , 表示这个 SDS 没有分配任何未使用空间。
  • len 属性的值为 5 , 表示这个 SDS 保存了一个五字节长的字符串。
  • buf 属性是一个 char 类型的数组, 数组的前五个字节分别保存了 'R' 、 'e' 、 'd' 、 'i' 、 's' 五个字符, 而最后一个字节则保存了空字符 '\0' 。

embstr

embstr是一种将redisObject结构头和长度小于等于44字节的字符串存储在一块区域(64字节)统一申请内存的结构。 image.png

raw

当字符串长度大于44字节时,字符串与redisObject会分开存储,另行申请内存。 image.png

hash(哈希)

hash 是一个键值对集合,类似map或者dict,它可以存储多个字段和值,一个 hash 类型的键最多可以存储 2^32 - 1 个字段。 redis7.0后hash有两种底层编码结构,listpack与hashtable。当hash中元素个数少于等于max-hash-ziplist-entries(默认512)或者元素的key或者value长度小于等于hash-max-ziplist-value(默认64字节)时,hash的底层结构为listpack,否则为hashtable。

listpack

image.png

hashtable

hashTable是一种散列表结构,它将字段和值分别存储在两个数组中,并通过哈希函数计算字段在数组中的索引 image.png

rehash过程
  1. 为字典dict的ht[1]哈希表分配空间,其大小为2^N,具体大小取决于当前哈希表已保存节点数(ht[0].used):
    • 扩容:满足2^N >= ht[0].used * 2条件下N取最小
    • 缩容:满足2^N >= ht[0].used条件下N取最小
  2. 将字典中的属性rehashidx的值设置为0,表示正在执行rehash
  3. 将ht[0]中所有的键值对依次重新计算哈希值,并放到ht[1]数组对应位置,每完成一个键值对的rehash之后rehashidx的值需要自增1
  4. 当ht[0]中所有的键值对都迁移到ht[1]之后,释放ht[0],并将ht[1]修改为ht[0],然后再创建一个新的ht[1]数组,为下一次rehash做准备
  5. 将字典中的属性rehashidx设置为-1,表示此次rehash结束,等待下一次rehash
  6. 正在执行rehash操作时,如果服务器收到来自客户端的命令请求操作,则会先查询ht[0],查找不到结果再到ht[1]中查询

list(列表)

quickList

image.png

set(集合)

set是一个无序的字符串集合,它不允许重复的元素。一个 set 类型的键最多可以存储 2^32 - 1 个元素。 redis7.0后set的底层编码结构可能为intset、listpack、hashtable。

  • intset:元素为整型,元素个数小于等于set-max-intset-entries/(默认512)时
  • listpack:元素为字符串,元素个数小于等于set-max-listpack-entries或者元素大小大于(默认128)且元素大小小于等于set_max_listpack_value(默认64字节)时
  • hashtable:元素个数大于set-max-intset-entries/set-max-listpack-entries或者元素大小大于set_max_listpack_value

intset

intset是一种紧凑的数组结构,它只保存int类型的数据,它将所有的元素按照从小到大的顺序存储在一块连续的内存中。intset会根据传入的数据大小,encoding分为int16_t、int32_t、int64_t
image

zset(有序集合)

Redis中的 zset 是一种有序集合类型,它可以存储不重复的字符串元素,并且给每个元素赋予一个排序权重值(score)。Redis 通过权重值来为集合中的元素进行从小到大的排序。zset 的成员是唯一的,但权重值可以重复。一个 zset 类型的键最多可以存储 2^32 - 1 个元素。

应用场景

zset 类型的应用场景主要是利用分数和排序的特性,比如:

  • 排行榜,利用 zadd 和 zrange 命令实现分数的更新和排名的查询
  • 延时队列,利用 zadd 和 zpopmin 命令实现任务的添加和执行,并且可以定期地获取已经到期的任务
  • 访问统计,可以使用 zset 来存储网站或者文章的访问次数,并且可以按照访问量进行排序和筛选。

底层实现

image.png

当满足如下条件时,zset底层由listpack,否则为skiplist

  • 元素个数小于等于 zset-max-listpack-entries ,默认值为 128
  • 元素值的长度小于等于 zset-max_listpack-value ,默认值为 64

skiplist

image.png

*stream(流)

*geospatial(地理)

*bitmap(位图)

*bitfield(位域)

*hyperloglog(基数统计)