Redis核心技术与实战学习总结(一)
mhr18 2024-11-18 14:39 25 浏览 0 评论
写在开头
作为Key/Value键值数据库,Redis的应用非常广泛。在之前多年的工作生涯中,我也只是关注了零散的技术点,没有对Redis建立起一套整体观,但只有建立了系统整体观,才能更好地定位问题和解决问题,更重要的是应付面试。
刚好,极客时间推出了一门《Redis核心技术与实战》课程,于是我就入手了,这是我的学习总结,化繁为简,只留重点,分享与你。
KV数据库的基本架构
为了建立系统观,最好的方法就是对其总体架构和关键模块有一个全局认知,因此这门课在最开始便给出了一个简单的KV数据库的基本架构,它包括了:
- 访问框架
- 索引模块
- 操作模块
- 存储模块
SimpleKV - 来自极客时间
为了支持更加丰富的业务场景,其实 Redis 对这些组件或者功能进行了扩展,或者说是进行了精细优化,从而满足了功能和性能等方面的要求。
下图展示了从SimpleKV到Redis的变化:
SimpleKV to Redis - 来自极客时间
上图中展示了几点变化:
- 一是Redis主要使用网络框架来进行访问,使得Redis可以作为一个独立的基础网络服务;
- 二是Redis数据模型中的value类型更加丰富,可以提供更多的接口;
- 三是Redis扩展了持久化模块,提供日志(AOF)和快照(RDB)。
- 四是Redis提供了集群的支持,使得HA和可扩展成为可能。
Redis的数据结构
Redis之所以“快”,一方面因为它是内存数据库,所有操作都在内存上完成,内存的访问速度本来就快。另一方面则是因为高效的数据结构,使得操作键值效率较高。
总体来说,Redis使用了一个用来保存每个Key/Value的全局哈希表结构,其中Value类型又包括了支持集合类型的双向链表、压缩列表、跳表等五大底层结构。
K/V的组织结构:全局哈希表
Redis使用了一个全局维度的哈希表来保存所有的Key/Value,每个哈希表本质上都是一个数组,这个数组的每个元素称为一个哈希桶。
哈希桶中的元素保存的并不是Value本身,而是指向Value的指针,如下图所示:
由数据结构的知识可以知道,哈希表的时间复杂度为O(1),因此它非常适合快速查找的场景。
哈希冲突及其解决
当往哈希表中写入的数据变得很多时,哈希冲突问题就会出现。所谓哈希冲突,就是两个Key的哈希值正好落到了同一个哈希桶中(哈希桶的个数毕竟通常少于Key的个数)。
因此,和我们在数据结构课程学到的一致,Redis也采用了链式哈希来解决哈希冲突。所谓链式哈希,就是同一个哈希桶中的多个元素用一个链表来保存,它们之间依次用指针连接,如下图所示:
但是,如果哈希表里写入的数据越来越多,哈希冲突链也会进而变得很长,从而导致这个链条上的元素查找耗时长,效率降低。
因此,Redis还会对哈希表做rehash操作。所谓rehash,就是增加现有的哈希桶的数量,让逐渐增多的entry元素能够在更多的桶之间分散保存,减少单个桶中的元素数量,从而减少单个桶中的冲突。
在具体操作中,Redis会开辟一个新的哈希表(比如:大小为之前的两倍),然后把之前哈希表的数据重新映射到新的哈希表,最后释放之前的哈希表。
画外音:是不是跟.NET中的集合类型动态扩容的思想类似?
But,在拷贝之前哈希表数据到新哈希表时,涉及到数据量过大,有可能会造成Redis的线程阻塞,从而无法服务其他的请求。因此,Redis采用了渐进式哈希的解决方案。
简单来说,所谓渐进式哈希就是不一次性把老哈希表中的数据迁移完,而是在每次处理一个请求时,从老哈希表中的第一个索引位置开始,顺带着将这个索引位置上的所有entries拷贝到新哈希表中;等下一个请求时,再顺带拷贝下一个索引位置的entries。如此,便将一次性的大量拷贝的开销,分摊到多次处理请求的过程中,避免了耗时的操作 和 服务的中断。
渐进式哈希的示例流程如下图所示:
此外,渐进式rehash执行时,除了根据键值对的操作来进行数据迁移,Redis本身还会有一个定时任务在执行rehash,如果没有键值对操作时,这个定时任务会周期性地(例如每100ms一次)搬移一些数据到新的哈希表中,这样可以缩短整个rehash的过程。
底层数据结构概览
Redis的Key/Value是通过哈希表进行组织的,对于String类型,找到哈希桶就可以直接CRUD了,因此O(1)就是String类型的操作复杂度了。
但是,对于集合类型来说,还需要进一步操作。在此之前,我们先了解一下都有哪些底层数据结构。
我们所熟知的String、List、Hash、Sorted Set 和 Set其实只是Redis中数据的保存形式,而一般所说的数据结构其实是它们的底层实现。
如下图所示,Redis的底层数据结构一共有6种,其和常见数据类型的对应关系已经清晰地体现在了下面这张图片里(给个赞)。
Redis数据类型与底层数据结构 - 来自极客时间
除了String类型的底层实现只有一种,即简单动态字符串。其余数据类型(List、Hash、Sorted Set和Set)都有两种底层实现,他们又被称为集合类型,即一个键对应了一个集合的数据。
底层数据结构复杂度
通过上面的描述,我们可以知道哈希表的复杂度是O(1),而数组 和 双向链表 也很常见,其复杂度基本是O(N)。学习过数据结构课程的都知道,O(N)的操作效率并不高,因此Redis引入了压缩列表 和 跳表。虽然压缩列表和跳表并不为我们所熟知,但它俩却是对整数数组和双向链表所做的优化。
首先,来看压缩列表,压缩列表也类似于一个数组,但和数组不同的是,压缩列表在表头有三个字段,分别表示列表长度、列表尾的偏移量 和 列表中entry的个数。压缩列表在表尾还有一个字段,表示列表结束,如下图所示:
由上图可知,在压缩列表中定位第一个和最后一个元素,只需要通过表头三个字段即可直接定位,无须遍历一次,因此查找首元素和尾元素的复杂度为O(1)。而需要查找其他元素时,就只能遍历查找了,此情景的复杂度退化为O(N)。
然后,来看跳表。跳表是在链表的基础之上,增加了多级索引,通过索引位置的几个跳转,实现数据的快速定位。一个具体的查找案例,如下图所示:
从上图可以看到,这个查找过程其实是在多级索引上跳来跳去,最后定位到具体的要查找的元素。我们常听到,没有什么是一顿火锅解决不了的事情,如果不行,那就两顿。对于跳表来说,没有什么是增加索引解决不了的查询,如果不够快,那就再加一级索引。
当数据量非常大时,跳表的查找复杂度就是O(logN),学过数据结构的都知道,它比O(N)效率要高。因此,我们也可以知道Sorted Set类型在数据元素较少时采用压缩列表,而一旦超过阈值,就会转为跳表结构来保证查询效率不受影响。
End总结
本文总结了Redis的基础架构 和 底层数据结构,这部分内容通常也是后端开发面试中的常见内容,希望对你有所帮助。
解读人:EdisonTalk
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)