当谈到 redis 时,我们通常会联想到一个关键词:“速度” 。然而 , 你是否曾思考过 Redis 之所以如此迅猛,到底在哪里呢?实际上 , 这其中有一个关键特性:Redis 能够在微秒级别内找到数据并快速执行操作 。
文章插图
那么,Redis 为何在众多数据库中脱颖而出呢?这其中有几个关键因素 。首先,Redis 是一种内存数据库,它的所有操作都在内存中进行,而内存的访问速度本身就非常快 。此外,Redis 还依赖于高效的数据结构 。这是因为 Redis 的键值对实际上是按照特定的数据结构组织的,因此键值对的操作实际上是对数据结构进行增删改查操作,高效的数据结构是 Redis 处理数据的基础 。在这节课中,我们将深入探讨这些数据结构 。
也许你会说:“这些我都知道,这不就是 Redis 的数据类型吗?包括字符串、列表、哈希、集合和有序集合?”不过 , 这些只是 Redis 键值对中值的数据类型,也就是数据的存储方式 。而在这里,我们所说的数据结构,指的是要深入了解它们的底层实现原理 。
以简单明了的方式来描述,总共有 6 种底层数据结构,它们与数据类型之间存在如下对应关系,具体如下图所示:
文章插图
可以看到,String 类型的底层实现只有一种数据结构,也就是简单动态字符串 。而 List、Hash、Set 和 Sorted Set 这四种数据类型 , 都有两种底层实现结构 。通常情况下 , 我们会把这四种类型称为集合类型 , 它们的特点是一个键对应了一个集合的数据 。
看到这里 , 其实有些问题已经值得我们去考虑了:
- 这些数据结构都是值的底层实现,键和值本身之间用什么结构组织?
- 为什么集合类型有那么多的底层结构 , 它们都是怎么组织数据的,都很快吗?
- 什么是简单动态字符串,和常用的字符串是一回事吗?
我们先来看看键和值之间是用什么结构组织的 。
键和值用什么结构组织?为了实现从键到值的快速访问,Redis 使用了一个哈希表来保存所有键值对 。
一个哈希表,其实就是一个数组,数组的每个元素称为一个哈希桶 。所以 , 我们常说 , 一个哈希表是由多个哈希桶组成的,每个哈希桶中保存了键值对数据 。
看到这里,你可能会问了:“如果值是集合类型的话,作为数组元素的哈希桶怎么来保存呢?”其实,哈希桶中的元素保存的并不是值本身,而是指向具体值的指针 。这也就是说,不管值是 String,还是集合类型,哈希桶中的元素都是指向它们的指针 。
在下图中,可以看到,哈希桶中的 entry 元素中保存了*key和*value指针,分别指向了实际的键和值,这样一来 , 即使值是一个集合 , 也可以通过*value指针被查找到 。
文章插图
因为这个哈希表保存了所有的键值对 , 所以,我也把它称为全局哈希表 。哈希表的最大好处很明显,就是让我们可以用 O(1) 的时间复杂度来快速查找到键值对——我们只需要计算键的哈希值,就可以知道它所对应的哈希桶位置,然后就可以访问相应的 entry 元素 。
你看,这个查找过程主要依赖于哈希计算,和数据量的多少并没有直接关系 。也就是说 , 不管哈希表里有 10 万个键还是 100 万个键,我们只需要一次计算就能找到相应的键 。
但是,如果你只是了解了哈希表的 O(1) 复杂度和快速查找特性,那么,当你往 Redis 中写入大量数据后 , 就可能发现操作有时候会突然变慢了 。这其实是因为你忽略了一个潜在的风险点 , 那就是哈希表的冲突问题和 rehash 可能带来的操作阻塞 。
为什么哈希表操作变慢了?当你往哈希表中写入更多数据时 , 哈希冲突是不可避免的问题 。这里的哈希冲突,也就是指,两个 key 的哈希值和哈希桶计算对应关系时,正好落在了同一个哈希桶中 。
推荐阅读
- Nginx配置指南:快速安装与反向代理设置
- 你愿意为“生成式AI”付费吗?
- "白酒圈公认6款性价比超高白酒,你的酒柜里缺了哪几瓶?"
- 六十岁退不了?交社保可以补发吗?你想知道的答案来了!
- 大闸蟹公母有啥区别,哪个更好,你选对了吗?
- 微信分身怎么登录第二个微信?我猜你不清楚这3种微信多开方法
- 想知道手机怎么拍照翻译吗?
- 快速提升记忆力的穴位董氏奇穴 按一个穴位马上记忆力变强
- 难以超越的5部古装探案剧,你若是一部没看,那就太可惜了
- 少年的你经典名句,牧羊少年奇幻之旅经典语录