为什么Redis那么快

数据库有很多,为什么Redis能有如此突出的表现呢?一方面,因为它是内存数据库,所有操作都在内存上完成。另外一方面就要归功于他的数据结构。高效的数据结构是Redis快速处理的基础。今天我们就来聊聊了Redis的数据类型以及对应的数据结构。 

       首先Redis有5大基本类型:

1.String(字符串)

2.List(列表)

3.Hash(哈希)

4.Set(集合)

5.Zset(Sorted Set 有序集合)

他们的底层实现简单来说一共有6种,分别是简单的动态字符串、双向链表、压缩列表、哈希表、跳表以及整数数组。他们和数据类型的对应关系如下所示:

图片

可以看到这些数据结构都是值的底层实现,那键和值之间是用什么数据结构来进行组织的呢?为了实现从键到值的快速访问,Redis使用了一个哈希表来保存所有的键值对。

图片

哈希表的最大好处很明显,就是可以以O(1)的时间复杂度来快速查找到键值对。但他有一个潜在的风险点,当你往Redis里写入大量的数据就会出现哈希表的冲突问题以及rehash带来的操作阻塞问题。

Redis解决哈希冲突的方式,就是链式哈希。链式哈希很容易理解,就是指同一个hash桶中的多个元素用一个链表来保存。如下图所示:

图片

这就出现一个问题,哈希冲突链表上的元素只能通过指针逐一查找再操作。如果哈希表里写入的数据越来越多,哈希冲突也会越来越多,这就会导致某些哈希冲突链过长,进而导致链上的元素查找耗时长,效率低。这对求快的redis来说是不能接受的。

所以Redis会对哈希表做rehash操作。rehash也就是增加现有的哈希桶的数量,让逐渐增多的entry元素能在更多的桶之间分散保存,减少单个桶中的元素个数,从而减少冲突。

为了使rehash更高效,Redis默认使用2个全局哈希表:哈希表1和哈希表2。一开始,当你刚插入数据时,默认使用哈希表1,此时哈希表2并没有分配空间。随着数据的增多,Redis开始执行Rehash。主要分为以下3步:

  1. 给哈希表2分配更大的空间。

  2. 把哈希表1的数据重新映射并拷贝到哈希表2。

  3. 释放哈希表1的空间。

到此我们可以从哈希表1切换到哈希表2,用容量更大的哈希表2来保存更多的数据,而原来的哈希表1留做下一次rehash扩容备用。

可以看到第二步会涉及到大量的数据拷贝,如果一次性把哈希表1全部都迁移完,会造成Redis线程阻塞,无法服务其他请求。为了避免这个问题,Redis采用了渐进式的Rehash。简单来说就是在第二步拷贝数据时,仍然正常处理客户端的请求,每处理一个请求,从哈希表1的第一个索引位置开始,顺带着将这个索引位置上的所有entries拷贝到哈希表2中;等处理下一个请求时,再顺带拷贝哈希表1的下一个索引位置的entries。这样就避免了一次性大量的数据拷贝,保证了数据的快速访问。

目前为止,你已经了解了Redis的键和值是怎么通过哈希表来组织的了,对于String类型来说,找到哈希桶就能直接增删改查了,所以哈希表O(1)的时间复杂度就是它的复杂度,但是对于集合类型来说,即使找到哈希桶了,还需要在集合中进一步操作。接下来我们就分别聊聊集合类型的底层数据结构和操作复杂度。

我们在上面已经了解到集合类型的底层结构主要有5种:整数数组、双向链表、哈希表、压缩列表和跳表。

其中,哈希表的操作特点我们已经学过;整数数组和双向链表也很常见,主要是通过数组下标和链表指针逐个访问元素,操作复杂度是O(N),操作效率比较低。压缩列表实际上类似于一个数组,和数组不同的是,压缩列表在表头有三个字段zlbytes、zltail和zllen,分别表示列表的长度、列表尾的偏移量和列表中元素的个数;压缩列表在表尾还有一个zlend表示列表结束。在压缩列表中,如果我们要查找定位第一个元素和最后一个元素,可以通过表头直接定位,时间复杂度为O(1)。而查找其它元素时,就没有那么高效了,只能逐个查询,时间复杂度为O(N)。

图片

下面我们来重点看一下跳表。有序链表只能逐一查找元素,导致操作起来非常缓慢,于是就出现了跳表。跳表是在链表的基础上增加了多级索引,通过索引位置的几个跳转,实现数据的快速定位。如图所示:

图片

可以看到,这个查找过程就是在多级索引上跳来跳去,最后定位到元素。当数据量很大时,跳表的查找复杂度是O(logN)。

图片

好了,今天就分享到这里,如果有什么问题,可以在留言区留言。

了解更多内容,请关注公众号老韩随笔。

### 回答1: Redis之所以能够实现速的性能,是因为它是一种基于内存的键值存储,它将数据存储在内存中,可以比磁盘I / O更地访问数据。它还支持复杂的数据结构,如列表,集合,有序集合哈希表等,可以更地执行复杂的操作。 ### 回答2: Redis之所以那么,可以归结为以下几个原因: 1. 内存存储:Redis是基于内存存储的数据库,它的数据存储在内存中,通过避免了硬盘的读写操作,大大提高了读写速度。内存的随机访问速度比硬盘几个数量级。 2. 单线程模型:Redis采用单线程模型,避免了多线程带来的竞争和冲突,简化了问题复杂度,提高了数据处理的效率。虽然是单线程,但通过多路复用技术,可以处理多个连接的请求。 3. 高效的数据结构:Redis支持丰富的数据结构,如字符串、哈希表、列表、集合和有序集合。它们都是直接以二进制方式存储在内存中,没有复杂的键值映射和解析过程,提高了数据的访问效率。 4. 高效的网络通信:Redis使用自己的协议进行网络通信,这个协议是基于TCP的、基于文本的简单协议。相较于其他复杂的协议,这个协议的消息大小较小,传输效率较高。 5. 预分配内存和写时复制:Redis在启动时会提前分配好所需的内存空间,避免了运行过程中频繁的内存分配操作。此外,Redis还实现了写时复制技术,即在进行写操作时,会复制出一个新的副本,使得读操作和写操作可以同时进行,提高了并发性能。 总的来说,Redis之所以速,是通过内存存储、单线程模型、高效的数据结构、高效的网络通信、预分配内存和写时复制等技术手段的综合运用,使得其在各个方面都具备了卓越的性能表现。 ### 回答3: Redis之所以的原因有以下几点: 1. 内存存储:Redis将数据存储在内存中,内存的读写速度远远高于磁盘的读写速度,因此能够实现非常的数据访问。 2. 单线程处理:Redis采用单线程模型,避免了线程切换的开销和线程之间的同步问题。由于单线程不需要考虑并发操作的问题,使得Redis能够更加高效地利用CPU资源。 3. 非阻塞IO:Redis使用了异步的IO模型,在等待IO操作的同时,可以处理其他的请求。这样可以避免由于IO阻塞而导致的系统性能下降。 4. 数据结构简单高效:Redis支持多种数据结构,如字符串、列表、哈希表等,这些数据结构都经过了精心优化,使得其在存储和访问上更加高效。 5. 持久化支持:Redis提供了两种持久化的方式,分别为RDB(照)和AOF(追加日志),可以将数据持久化到磁盘,保证数据的安全性。 6. 网络模型:Redis使用一个单一的TCP连接来处理所有的请求和响应,减少了网络连接的开销,提高了网络性能。 综上所述,Redis之所以速是因为它通过内存存储、单线程处理、非阻塞IO、简单高效的数据结构、持久化支持以及优化的网络模型等多方面的优化措施,使得其能够高效地处理大量的读写请求,从而达到出色的性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值