数据库有很多,为什么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)。

​​

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

redis为什么那么快?的更多相关文章

  1. 为什么说Redis是单线程的以及Redis为什么这么快!

    参考文章:https://blog.csdn.net/xlgen157387/article/details/79470556 redis简介 Redis是一个开源的内存中的数据结构存储系统,它可以用 ...

  2. 为什么说Redis是单线程的以及Redis为什么这么快!(转)

    文章转自https://blog.csdn.net/chenyao1994/article/details/79491337 一.前言 近乎所有与Java相关的面试都会问到缓存的问题,基础一点的会问到 ...

  3. Redis为什么这么快

    Redis为什么这么快 1.完全基于内存,绝大部分请求是纯粹的内存操作,非常快速.数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1): 2.数据结构简单, ...

  4. Redis性能解析--Redis为什么那么快?

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! Red ...

  5. 《为什么说Redis是单线程的以及Redis为什么这么快!》

    为什么说Redis是单线程的以及Redis为什么这么快!   一.前言 近乎所有与Java相关的面试都会问到缓存的问题,基础一点的会问到什么是“二八定律”.什么是“热数据和冷数据”,复杂一点的会问到缓 ...

  6. [转帖]Redis性能解析--Redis为什么那么快?

    Redis性能解析--Redis为什么那么快? https://www.cnblogs.com/xlecho/p/11832118.html echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加e ...

  7. 为什么说Redis是单线程的以及Redis为什么这么快!(转)

    一.前言 近乎所有与Java相关的面试都会问到缓存的问题,基础一点的会问到什么是“二八定律”.什么是“热数据和冷数据”,复杂一点的会问到缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级等问题,这些看似 ...

  8. 性能测试 | 理解单线程的Redis为何那么快?

    前言 Redis是一种基于键值对(Key-Value)的NoSQL数据库,Redis的Value可以由String,hash,list,set,zset,Bitmaps,HyperLogLog等多种数 ...

  9. Redis 为什么这么快?

    1. 纯内存操作,肯定快 数据存储在内存中,读取的时候不需要进行磁盘的 IO 2. 单线程,无锁竞争损耗 单线程保证了系统没有线程的上下文切换 使用单线程,可以避免不必要的上下文切换和竞争条件,没有多 ...

  10. Redis为什么这么快?

    Redis为什么这么快?

随机推荐

  1. C++知识点案例 笔记-5

    1.关系运算符重载 2.类型转换函数重载 3.转换构造函数 4.函数模板 5.显式实例化 6.类模板外定义模板函数 1.关系运算符重载 ==关系运算符重载== //直接(按分数)比较两个对象 #inc ...

  2. 10.4 route:显示或管理路由表

    route命令 可以显示或管理Linux系统的路由表,route命令设置的路由主要是静态路由. 路由的概念     计算机与计算机之间的数据传输必须得经由网络,而网络可以通过直接连接两台计算机的方式或 ...

  3. Java反射机制 之 获取类的 方法 和 属性(包括构造函数)(Day_06)

    把自己立成帆,才能招来凤. 运行环境 JDK8 + IntelliJ IDEA 2018.3  本文中使用的jar包链接 https://files.cnblogs.com/files/papercy ...

  4. 用户从控制台输入n个整数,比较并输出其中的最大值和最小值

    package judgment;import java.util.Scanner;/** * 用户输入n个整数,找出最大值和最小值并打印输出 */public class Judgment { pu ...

  5. GO学习-(20) Go语言基础之单元测试

    Go语言基础之单元测试 不写测试的开发不是好程序员.我个人非常崇尚TDD(Test Driven Development)的,然而可惜的是国内的程序员都不太关注测试这一部分. 这篇文章主要介绍下在Go ...

  6. Go语言协程并发---读写锁sync.RWMutex

    package main import ( "fmt" "sync" "time" ) /* 读写锁 多路只读 一路只写 读写互斥 */ / ...

  7. 3DPytorch-API NVIDIA Kaolin

    3DPytorch-API NVIDIA Kaolin NVIDIA Kaolin library provides a PyTorch API for working with a variety ...

  8. 如何在CPU上优化GEMM(上)

    如何在CPU上优化GEMM(上) (TL:DR)TVM提供了抽象接口,用户分别描述算法和算法的实现组织(所谓的调度).通常,在高性能调度中编写算法会破坏算法的可读性和模块性.尝试各种看似有希望的时间表 ...

  9. Autofac入门

    注意:本文为原创文章,任何形式的转载.引用(包括但不限于以上形式)等,须先征得作者同意,否则一切后果自负. 简介 Autofac 是一个令人着迷的.NET IoC 容器. 它管理类之间的依赖关系.当应 ...

  10. 手把手教你彻底理解MySQL的explain关键字

    数据库是程序员必备的一项基本技能,基本每次面试必问.对于刚出校门的程序员,你只要学会如何使用就行了,但越往后工作越发现,仅仅会写sql语句是万万不行的.写出的sql,如果性能不好,达不到要求,可能会阻 ...