
redis 是 key-value 型数据库,key 的数据类型 string,value 的数据类型有五种(常见的)string、list、hash、set、zset。五种数据类型与底层数据结构的对应关系如下图:

一、哈希表
redis 使用全局哈希表存储库中键值对关系,全局哈希表类似一个数组,每一个元素称为一个哈希桶,桶中存储两个指针*key和*value,分别指向 key 和 value。这样一来,即使值是一个集合也可以通过*value找到。

哈希冲突:数据量过大时,会出现多个值落在同一个桶中的情况。
链式哈希:同一个哈希桶中的多个元素用一个链表来保存,它们之间依次用指针连接。
redis 采用链式哈希的方式解决哈希冲突。但如果冲突过多,链过长,导致效率降低。rehash操作解决这个问题
1.rehash
rehash 操作是指增加现有的哈希桶的数量,使增多的 entry 元素在更多的桶之间分散保存。
操作流程:
- 使用两个全局哈希表。哈希表 1 和哈希表 2,刚插入数据时,默认使用哈希表 1,此时哈希表 2 并没有被分配空间;
- 随着数据增多,给哈希表 2 分配更大的空间,把哈希表1中的数据重新映射并拷贝到哈希表 2 中;
- 释放哈希表 1 的空间;
2.渐进式rehash
rehash 操作拷贝过程涉及大量数据拷贝,可能会造成 redis 主线程阻塞,采用渐进式rehash解决。

原理:在数据拷贝时,Redis 仍然正常处理客户端请求,每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表2中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entries。
二、压缩列表
压缩列表类似一个数组,数组中每一个元素保存一个数据。表头三个字段zlbytes、zltail 和zllen,分别表示列表长度、列表尾的偏移量和列表中的 entry 个数,表尾zlend字段表示列表结束。
每个 entry 中三个字段previous_entry_length、encoding、content,分别表示前一个节点的长度、数据类型和编码格式、节点的值。

面试题-压缩列表相比传统数组的优势是什么?

内存节省到极致!
- 传统数组。数组存储不同长度的字符时,会选择最大的字符长度作为每个节点的内存大小。如果只有一个元素的长度超大,但是其他的元素长度都比较小,那么所有元素的内存都用超大的数字就会导致内存的浪费;
- 压缩列表。数组中每个节点的大小就是实际内容的大小;
三、跳跃表
跳跃表是在链表的基础上,增加多级索引,通过索引位置的跳转,实现数据的快速定位。如下图:

面试题-跳跃表相比红黑树等平衡树的优点是什么?
- 插入速度非常快速,因为不需要进行旋转等操作来维护平衡性;
- 更容易实现;
- 支持无锁操作;