剖析Redis常用数据类型对应的数据结构
Redis:K-V,NoSQL
类型:字符串、列表、字典、集合、有序集合
列表(list)
-
压缩列表
- 存储数据量小
- 列表保存单个数据小于64字节
- 列表中数据个数小于512
-
双向循环链表
- 存储数据量大
- Redis双向链表额外定义一个list结构体,组织链表首尾指针,长度等信息,使用很方便
字典(hash)
- 压缩列表
- 存储数据量小
- 列表保存单个数据小于64字节
- 列表中数据个数小于512
- 散列表
-
MurmurHash2哈希算法运行速度快、随机性好作为哈希函数
- 哈希冲突:链表法
-
支持散列表动态扩容、缩容
-
数据动态增加,装载因子不停变大,为避免散列表性能下降,装载因子大于1Redis扩容,扩为原来2倍左右,具体要计算
-
数据动态减小,装载因子小于0.1缩容,缩小为字典中数据个数的2倍左右,具体源码
-
扩容缩容大量数据搬移和哈希值重新计算,耗时,使用渐进式扩容缩容策略,数据搬移分批进行,避免大量数据一次性搬移导致服务停顿
-
集合(set)
- 有序数组
- 都是整数
- 存储个数不超过512个
- 散列表
有序集合(sortedset)
- 数据量小:压缩列表
- 所有数据大小小于64字节
- 元素个数小于128
数据结构持久化
Redis经常用做内存数据库,也可以数据落盘,将内存中数据存储到硬盘。
散列表指针指向内存中存储地址,Redis如何将一个跟具体内存地址有关的数据结构存储到磁盘中?数据结构持久化,或者对象持久化问题,"持久化":"存储到磁盘"
如何将数据结构持久化到硬盘?
- 清除原有存储结构,只将数据存储到磁盘,需要还原再重新将数据组织为原来的数据结构
- 弊端:数据从硬盘到内存耗时,需要重新计算每个数据哈希值,如果10GB?
- 保留原来的存储方式,将数据按照原有格式存储到磁盘,可以避免重新计算哈希值
- 比如散列表,大小,每个数据被散列到的槽的编号都保存在磁盘,那就要耗硬盘内存了,不过也是快
思考
- Redis很多数据类型都是多种数据结构一起组合实现,为什么这样设计?用一种固定的数据结构不更简单吗?
- Redis数据结构由多种数据结构组合实现,主要出于时间和空间考虑,数据量小通过数组下标访问最快,占用内部才能最小,而压缩列表知识数组升级版
- 数据量大的时候需要用链表了,同时为了保证速度需要和数组结合,也就有了散列表
- 对于数据的大小和多少采用哪种数据结构,相信redis团队一定是根据大多数的开发场景而定的。
- 数据结构持久化有两种方法,对于二叉查找树我们如何将它持久化到磁盘中?
- 存储方式一:通过填充叶子结点形成完全二叉树,然后以数组形式存储到硬盘,数据还原也是非常高效的
数据量小采用连续内存的数据结构是为了CPU缓存读取连续内存来提高命中率,而限制数据结构数量和数据大小应该是考虑到CPU缓存的大小