首页 > 自考资讯 > 高考百科

华为技术专家告诉你Redis为何这么快?

小条 2024-09-23

女士们在哪里?

当您收到键值对操作时,您可以在微秒级内检索数据并快速完成操作。

为什么Redis如此突出?

它是内存数据库,所以所有的操作都是在内存中完成的,内存本身的访问速度极快。

键值对按照特定的数据结构进行组织。操作键值对最终涉及到数据结构的添加、删除、修改和检查。因此,高效的数据结构是Redis快速处理数据的基础。 )而List、Hash、Set、Sorted Set只是Redis中键值对值的数据类型,或者说数据的存储格式。

本文中的数据结构旨在探索其底层实现。

底层数据结构有六种类型:简单动态字符串、双向链表、压缩列表、哈希表、跳跃列表和整数数组。

81dacddba0bb48ceb50405e25ccacd50~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1727664735&x-signature=Shyhrvlby7Y4VD9ZhXO74kuQErw%3D List、Hash、Set、Sorted Set四种数据类型有两种底层实现结构。通常称为集合类型。 K对应一组数据。

这些数据结构都是V的底层实现,K.V之间用什么组织的?

为什么集合类型有这么多底层结构,数据是如何组织的,它们都这么快吗?

什么是简单动态字符串,和常用的字符串一样吗?

Redis 有哪些潜在的“慢操作”来最大化其性能优势?

键和值用什么结构组织?

为了实现快速的K到V访问,Redis使用哈希表来存储所有KV对。

实际上,这是一个数组,数组元素称为哈希桶。哈希表由多个哈希桶组成,每个哈希桶存储KV对。

当值为集合类型时,如何存储数组元素的哈希桶?

哈希桶中的元素存储指向特定值的指针,而不是值本身。也就是说,哈希桶中的元素都是指向值的指针,无论它们是字符串还是集合类型。

哈希桶中的条目元素存储分别指向实际K和V的*key和*value。

即使value是一个集合,也可以通过*value指针找到。

d03967e818234a9ca09d016590d17db0~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1727664735&x-signature=uX4c9WfjHCydjukkj0OG3RXTlOE%3D该哈希表也称为全局哈希表,因为它存储了所有键值对。

全局引用Redis 数据库中由哈希表索引的所有kv。查询这个哈希表中的某个key就会找到对应的v。然后根据v的具体类型(hash、set、list等),通过v的底层数据结构读取具体的值数据。例如List通过双向链表读取数据。

使用哈希表,只需计算K的哈希值就可以知道对应哈希桶的位置,并访问对应的条目元素。

这个搜索过程主要依赖于哈希计算,与数据量没有直接关系。无论哈希表中有100,000 K还是1,000,000 K,一次计算就可以找到对应的K。

如果只了解哈希表的O(1) 复杂度和快速查找特性,向Redis 写入大量数据可能会导致操作突然变慢。

它忽略了由于哈希表争用问题或重新哈希而导致操作被阻止的潜在风险。

为什么哈希表操作变慢了?

将更多数据写入哈希表会导致哈希冲突。 Redis 通过链式哈希解决了这个问题。同一个哈希桶中的多个元素存储在一个链表中。

Entry1、entry2、entry3都存储在哈希桶3中。 Entry1 通过*next 指向条目2。以下同样适用。这就形成了一个链表,也称为哈希冲突链。

98c7b73a7f564ba7aab4cf4c07c13012~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1727664735&x-signature=o1QuV5yHtKcHxVh9LX4GOQN%2BXtM%3D

哈希表中的数据越多,就会导致哈希冲突越多,导致一些哈希冲突链变得更长,在链上查找元素的速度更慢、效率更低。这对于要求“速度”的Redis来说是无法接受的。

Redis 也是如此

由于HGET、HSET、HDEL操作的是哈希表,如果Set类型使用哈希表作为底层数据结构,SADD、SREM、SRANDMEMBER的复杂度也是O(1)。 set类型允许同时添加、删除、修改、检查元素,如:

哈希类型HMGET 和HMSETSet 类型SADD 还支持同时添加多个元素。这些操作的复杂度由单个元素操作的复杂度和元素的数量决定。例如,当HMSET添加M个元素时,复杂度从O(1)变为O(M)。

rehash

对集合类型的遍历操作可以返回集合中的所有数据,例如哈希类型HGETALL 或集合类型SMEMBERS,也可以返回某个范围内的部分数据,例如:

List 类型的LRANGEZSet 的ZRANGE 复杂度通常为O(N),应尽可能避免。

Redis从2.8版本开始提供了SCAN操作(HSCAN、SSCAN、ZSCAN)来实现渐进式遍历,并且每次只返回有限数量的数据。与HGETALL 和SMEMBERS 相比,这一次返回所有元素,避免了Redis 长时间阻塞。

集合数据操作效率

集合类型记录集合中所有元素的数量,例如LLEN 和SCARD。

当集合类型使用压缩列表、双向链表或整数数组等数据结构时,复杂度仅为O(1 )。

影响因素

某些数据结构中的特殊记录(例如压缩列表和双向链表)记录表的开始和结束偏移量。因此,List 类型的四种操作LPOP、RPOP、LPUSH 和RPUSH 的复杂度最低,因为它们在列表的开头和结尾添加和删除可以通过偏移直接定位的元素。 (1)可实现高速运行。

底层数据结构

这就是为什么Redis可以快速操作键值对。

O(1) 复杂度的哈希表广泛用于字符串、哈希、集合等。这些操作的复杂度基本上是由哈希表决定的。复杂度通常为O(N),因为必须遍历底层数据结构。

为了避免Redis中耗时的全集合遍历操作,我们建议使用其他命令,例如SCAN。

List的基本实现结构:双向链表和压缩列表的操作复杂度都是O(N)。

请根据当地实际情况使用列表类型。 POP/PUSH 非常高效,应该主要用于FIFO 队列场景,而不是用作可以随机读写的集合。

版权声明:本文转载于网络,版权归作者所有。如有侵权,请联系本站编辑删除。

猜你喜欢