redis 有哪些数据结构?
redis 使用键值对的方式进行数据存储,key 的数据类型永远是 String,value 的数据类型包括 String(字符串)、List(列表)、Hash(哈希)、Set(集合) 和 Sorted Set(有序集合)
redis 有哪些底层数据结构?
redis 的底层数据结构包括 简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组
- 整数数组和双向链表都是顺序读写,通过数组下标或链表指针逐个访问,操作复杂度 O(N)
- 压缩列表类似数组,每个元素对应一个数据,如果要查第一个或最后一个,操作复杂度O(1),其余 O(N)
- 跳表是在链表的基础上增加多级索引,通过索引进行跳转,实现快速定位,操作复杂度 O(logN)
结构的对应关系?
数据结构 | 底层数据结构 | |
key | String | |
value | String(字符串) | 简单动态字符串 |
List(列表) | 压缩列表、双向链表 | |
Hash(哈希) | 压缩列表、哈希表 | |
Set(集合) | 哈希表、整数数组 | |
Sort Set(有序集合) | 压缩列表、跳表 |
dictEntry和RedisObject
redis 会使用一个全局哈希表来存储所有的键值对,一个键值对需要一个dictEntry,属于必须损耗
不同的数据类型都有相同的元数据要记录(例如最后一次访问时间,被引用的次数等),所以RedisObject结构体的开销也并非都是有效值的,指针指向的是实际数据存放的内存地址,即不同的底层数据结构
简单动态字符串(SDS)
SDS是"simple dynamic string"的缩写。redis中所有场景中出现的字符串,基本都是由SDS来实现的
- 所有非数字的key。例如 set msg"hello world" 中的key msg
- 字符串数据类型的值。例如 set msg "hello world" 中的value "hello wolrd"
- 非字符串数据类型中的“字符串值”。例如 RPUSH fruits"apple""banana""cherry"中的"apple" "banana" "cherry"
除了用来保存数据库中的字符串值之外, SDS 还被用作缓冲区(buffer): AOF 模块中的 AOF 缓冲区, 以及客户端状态中的输入缓冲区
SDS结构体
三种编码格式
为什么是44字节?(新版)len、alloc、flag各占1个字节,buf末尾\0占1个字节,RedisObject头部占16个字节,64-16-3-1=44
优点
- 查询字符串长度的操作复杂度为 O(1)
由于SDS结构体包含了 len,不需要遍历统计长度
- 内存预分配 jemalloc
在分配内存时,会根据我们申请的字节数 N,找一个比 N 大,但最接近 N 的2的幂次方作为分配空间,这样可以减少由于修改数据导致的频繁分配的次数
- 惰性空间释放
当我们执行完一个字符串缩减的操作,redis并不会马上收回空间,预防后面字符串添加的可能,但是当你再次操作还是没用到多余空间,Redis就会收回多余的空间