我们知道Redis的很快,一个原因是因为在内存上操作,另一个原因是本身的数据结构。而具体的五大类型就是如下:
键和值如何组织的
通过key找到value的过程,Redis使用了哈希表结构进行查找。具体就是根据key的hash值计算出对应的下表,然后指向对应的entry节点,entry节点保存的key和value的指针值。
比如我们操作set k1 v1, 但是get k1。就是通过哈希表结构进行查找的。
哈希表的优点:时间复杂度为O(1),只需计算hashkey的值就可以查找到,无论对于多大的数据量来说,是一种空间换时间思路。但是哈希表也存在一个问题就是大量key写入可能导致哈希表的冲突和rehash 以此带来操作上的阻塞。
哈希冲突如何解决
当出现大量的数据写入时,会造成哈希冲突,而哈希冲突就是不同的数据,key计算的hash值相同,导致写入到同一个hash桶中。解决方案一把采用链式法,也就是当entry1、entry2、entry3节点冲突之后,采用next阶段保存起来。
但是如果过多的hash冲突,肯定会导致查询效率下降。所以Redis会采用rehash的操作。
rehash的过程大概就是,redis默认有两个全局哈希表,哈希表1和哈希表2,哈希表1用来存储数据,哈希表2不存储数据。
1.当哈希表冲突达到一定阈值,就将哈希表2扩大2倍。
2.将哈希表1的数据拷贝到哈希表2中
3.哈希表1数据清除,以被下次rehash使用。
但是其实也可以发现,2中的步骤,其实非常耗费时间,可能会操作redis的阻塞。所以就有了渐进式reahsh
这个过程说白了就是,一次不全量复制,而是只复制某一个哈希桶的数据。将一次大量拷贝,进行分摊多次。
以上就是Redis 的键和值通过哈希表组织的过程,对于普通结构字符串就可以直接操作O(1),但是对于集合类型来说流程不一样。
集合数据操作效率
哈希表、整数数组、双向链表、压缩列表、跳表是集合类的主要集中数据结构底层结构。
整数数组、双向链表比较常见,操作复杂度是O(N)
跳表和压缩列表是Redis的重要结构
压缩列表
压缩列表其实就是一个压缩过后的数组结构,只不过有一些特殊的标识。
开头有zlbytes代表列表长度,zltail代表列表尾的偏移量,zllen列表中的entry个数。zlend代表列表结束。
在压缩列表中,如果想要定位第一个和最后一个元素可以通过计算得到,但是别的元素需要O(N)复杂度。
跳表
链表结构查询元素,需要逐一的查询,但是跳表作为一个有序链表,增加多个索引可以实现数据的快速定位。
跳表查询复杂度为O(logN)
不同操作的复杂度
- 单元素操作是基础;
- 范围操作非常耗时;统计操作通常高效;
- 例外情况只有几个
一般来说,我们针对单个元素的操作,时间复杂度都是可控的O(1),当涉及到对范围查询需要小心使用。
小结
Redis的基本使用,基本就是掌握几大数据结构的原理,这样在操作的时候才能以不变应万变。本篇主要介绍了key和value如何组织的,哈希冲突的问题,通过渐进式rehash类解决,而Redis的重要数据结构就是跳表和压缩列表。
针对于Redis专题来说。
- 数据库和缓存读写一致性问题
- bloomFilter
- 缓存雪崩 、击穿、穿透
- 分布式锁
- IO多路复用
Redis的基本使用
- 持久化机制
- Redis事务
- Redis复制
- Redis哨兵(sentinel)
- Redis集群