Redis数据类型的底层实现

199 阅读3分钟

本文介绍Redis的常用数据类型的底层实现。

1. 底层数据结构

1.1 SDS简单动态字符串

SDS简单动态字符串是String的底层实现。SDS简单动态字符串维护了字段len用来记录字符串长度,故而返回长度为O(1);维护了字段free记录空闲空间长度,用来实现惰性空间释放。

两个主要优势:

  1. 空间预分配:SDS简单动态字符串被修改后,程序不仅会为SDS分配所需要的必须空间,还会分配额外的未使用空间。
  2. 惰性空间释放:当对String进行删除或缩短操作时,程序并不会直接回收多余内存,而是将多余字符置为空字符,使用 free 字段将这些字节数量记录下来不释放,后面如果需要 append 操作时,则直接使用 free 中未使用的空间,减少了内存的分配。当添加字符串时,会判断空闲空间是否够用,若不够用则需要扩容,如果目前的字符串小于1M,则直接扩容双倍,如果目前的字符串大于1M,则直接添加1M。

1.2 zipList 压缩列表

压缩列表是 List、Hash以及Sorted Set 三种数据类型底层实现之一。

当一个列表只有少量数据的时候,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么 Redis 就会使用压缩列表来做列表键的底层实现。这样内存紧凑,节约内存。

1.3 linkedList 双向链表

List以前底层实现是linkedList+zipList,后来使用快表来代替前者。

1.4 quickList 快表

quicklist 是 ziplist 和 linkedlist 的混合体,它将 linkedlist 按段切分,每一段使用 ziplist 来紧凑存储,多个 ziplist 之间使用双向指针串接起来。

1.5 skipList 跳表

是Sorted Set的底层实现之一。可以理解为带多层索引的链表。最底层是有序链表,并增加了多层级索引,通过索引位置的区间查找,快速定位数据。

1.6 intSet 整数集合

当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现,节省内存。

1.7 hashTable 哈希表

Hash的底层实现,使用链地址法解决冲突,渐进式rehash扩容(复制出另外一个hash表,重新计算hashcode,分多次渐进完成,在此期间删除查找更新等操作会在两个hash表上进行,第一个没找到就会去第二个找,但是新增操作一定是在新的hash表上进行)。

2. 数据类型对应实现

类型编码
STRINGINT(整型)、EMBSTR(SDS)、RAW(SDS)
LISTQUICKLIST(快表)
SETINTSET(整数集合)、HASHTABLE(哈希表)
ZSETSKIPLIST(跳表)、ZIPLIST(压缩列表)
HASHZIPLIST(压缩列表)、HASHTABLE(哈西表)