导读跟大家讲解下有关详解Redis中的数据结构,相信小伙伴们对这个话题应该也很关注吧,现在就为小伙伴们说说详解Redis中的数据结构,小编也
跟大家讲解下有关详解Redis中的数据结构,相信小伙伴们对这个话题应该也很关注吧,现在就为小伙伴们说说详解Redis中的数据结构,小编也收集到了有关详解Redis中的数据结构的相关资料,希望大家看到了会喜欢。
在实际开发Redis
使用会频繁那么在使用过程中我们该如何正确抉择数据类型呢哪怎么用手机开通黄钻些场景下适用哪些数据类型。而且在面试中也很常会被面试官问到Redis数据结构方面的问题:
Redis为什么快呢为什么查询操作会变慢了Redis Hash rehash过程为什么使用哈希表作为Redis的索引
当我们分析理解了Redis
数据结构可以为了我们在使用Redis
的时候正确抉择数据类型使用提升系统性能。【相关推荐:Redis视频教程】
Redis
底层数据结构
Redis
是一个内存键值key-value
数据库且键值对数据保存在内存中因此Redis
基于内存的数据操作其效率高速度快;
其中Key
是String
类型Redis
支持的value
类型包括了String
、List
、Hash
、Set
、Sorted Set
、BitMap
等。Redis
能够之所以能够广泛地适用众多的业务场景基于其多样化类型的value
。
而Redis
的Value
的数据类型是基于为Redis
自定义的对象系统redisObject
实现的
typedef struct redisObject{ //类型 unsigned type:4; //编码 unsigned encoding:4; //指向底层实现数据结构的指针 void *ptr; ….. }
redisObject
除了记录实际数据还需要额外的内存空间记录数据长度、空间使用等元数据信息其中包含了 8 字节的元数据和一个 8 字节指针指针指向具体数据类型的实际数据所在位置:
其中指针指向的就是基于Redis
的底层数据结构存储数据的位置Redis
的底层数据结构:SDS
双向链表、跳表哈希表压缩列表、整数集合实现的。
那么Redis底层数据结构是怎么实现的呢
Redis底层数据结构实现
我们先来看看Redis
比较简单的SDS
,双向链表整数集合。
SDS
、双向链表和整数集合
SDS
使用l寒假趣事作文en
字段记录已使用的字节数将获取字符串长度复杂度降低为O(1)而且SDS
是惰性释放空间的你free
了空间系统把数据记录下来下次想用时候可直接使用。不用新申请空间。整数集合在内存中分配一块地址连续的空间数据元素会挨着存放不需要额外指针带来空间开销其特点为内存紧凑节省内存空间查询复杂度为O(1)效率高其他操作复杂度为O(N);
双向链表 在内存上可以为非连续、非顺序空间通过额外的指针开销前驱/后驱指针串联元素之间的顺序。
其特点为节插入/更新数据复杂度为O(1)效率高查询复杂度为O(N);
Hash
哈希表
哈希表其实类似是一个数组数组的每个元素称为一个哈希桶每个哈希桶中保存了键值对数据且哈希桶中的元素使用dictEntry
结构
因此哈希桶元素保存的并不是键值对值本身而是指向具体值的指针所以在保存每个键值对的时候会额外空间开销至少有增加24个字节特别是Value
为String
的键值对每一个键值对就需要额外开销24个字节空间。当保存数据小额外开销比数据还大时这时为了节省空间考虑换数据结构。
那来看看全局哈希表全图:虽然哈希表操作很快但Redis
数据变大后就会出现一个潜在的风险:哈希表的冲突问题和rehash
开销问题这可以解释为什么哈希表操作变慢了
当往哈希表中写入更多数据时哈希冲突是不可避免的问题 Redis 解决哈希冲突的方式就是链式哈希同一个哈希桶中的多个元素用一个链表来保存它们之间依次用指针连接如图所示:
当哈希冲突也会越来越多这就会导致某些哈希冲突链过长进而导致这个链上的元素查找耗时长效率降低。
为了解决哈希冲突带了的链过长的问题进行rehash
操作增加现有的哈希桶数量分散单桶元素数量。那么rehash
过程怎么样执行的呢
Rehash
为了使rehash
操作更高效使用两个全局哈希表:哈希表 1 和哈希表 2具体如下:
将哈希表 2 分配更大的空间把哈希表 1 中的数据重新映射并拷贝到哈希表 2 中;释放哈希表 1 的空间
但由于表1和表2在重新映射复制时数据大如果一次性把哈希表 1 中的数据都迁移完会造成 Redis
线程阻塞无法服务其他请求。
为了避免这个问题保证Redi
s能正常处理客户端请求Redis
采用了渐进式rehash
。
每处理一个请求时从哈希表 1 中依次将索引位置上的所有 entries 拷贝到哈希表 2 中把一次性大量拷贝的开销分摊到了多次处理请求的过程中避免了耗时操作保证了数据的快速访问。
在理解完Hash
哈希表相关知识点后看看不常见的压缩列表和跳表。
压缩列表与跳表
压缩列表在数组基础上在压缩列表在表头有三个字段 zlbytes、zltail 和 zllen分别表示列表长度、列表尾的偏移量和列表中的 entry 个数;压缩列表在表尾还有一个 zlend表示列表结束。
优点:内存紧凑节省内存空间内存中分配一块地址连续的空间数据元素会挨着存放不需要额外指针带来空间开销;查找定位第一个元素和最后一个元素可以通过表头三个字段的长度直接定位复杂度是 O(1)。
跳表 在链表的基础上增加了多级索引通过索引位置的几个跳转实现数据的快速定位如下图所示:
比如查询33
特点:当数据量很大时跳表的查找复杂度为O(logN)。
综上所述可以得知底层数据结构的时间复杂度:
数据结构类型时间复杂度哈希表O(1)整数数组O(N)双向链表O(N)压缩列表O(N)跳表O(logN)
Redis
自定义的对象系统类型即为Redis
的Value
的数据类型Redis
的数据类型是基于底层数据结构实现的那数据类型有哪些呢
Redis数据类型
String
、List
、Hash
、Sorted Set
、Set
比较常见的类型其与底层数据结构对应关系如下:
数据类型数据结构StringSDS(简单动态字符串)List双向链表压缩列表Hash压缩列表<br/>哈希表Sorted Set压缩列表<br/>跳表Set哈希表<br/>整数数组
数据类型对应特点跟其实现的底层数据结构差不多性质也是一样的,且
String
基于SDS实现适用于简单key-value
存储、tnx key value
实现分布式锁、计数器(原子性)、分布式全局唯一ID。
List
按照元素进入List
的顺序进行排序的遵循FIFO(先进先出)规则一般使用在 排序统计以及简单的消息队列。
Hash
是字符串key
和字符串value
之间的映射十分适合用来表示一个对象信息 特点添加和删除操作复杂度都是O普通话时间(1)。
Set
是String
类型元素的无序集合集合成员是唯一的这就意味着集合中不能出现重复的数据。 基于哈希表实现的所以添加删除查找的复杂度都是 O(1)。
Sorted Set
是Set
的类型的升级 不同的是每个元素都会关联一个 double 类型的分数通过分数排序可以范围查询。
那我们再来看看这些数据类型Redis Geo
、HyperLogLog
、BitMap
Redis Geo
将地球看作为近似为球小说言情推荐体基于GeoHash 将二维的经纬度转换成字符串来实现位置的划分跟指定距离的查询。特点一般使用在跟位置有关的应用。
HyperLogLog
是一种概率数据结构它使用概率算法来统计集合的近似基数 错误率大概在0.81%。 当集合元素数量非常多时它计算基数所需的空间总是固定的而且还很小适合使用做 UV 统计。
BitMap
用一个比特位来映射某个元素的状态 只有 0 和 1 两种状态非常典型的二值状态且其本身是用 String 类型作为底层数据结构实现的一种统计二值状态的数据类型 优势大量节省内存空间可是使用在二值统计场景。
在理解上述知识后我们接下来讨论一下根据哪些策略选择相对应的应用场景下的Redis
数据类型
选择合适的Redis
数据类型策略
在实际开发应用中Redis可以适用于众多的业务场景但我们需要怎么选择数据类型存储呢
主要依据就是时间/空间复杂度在实际的开发中可以考虑以下几个点:
数据量数据本身大小集合类型统计模式支持单点查询/范围查询特殊使用场景数据量数据本身大小
当数据量比较大数据本身比较小使用String
就会使用额外的空间大大增加因为使用哈希表保存键值对使用dictEntry
结构保存会导致保存每个键值对时额外保存dictEntry
的三个指针的开销这样就会导致数据本身小于额外空间开销最终会导致存储空间数据大小远大于原本数据存储大小。
可以使用基于整数数组和压缩列表实现了List
、Hash
和Sorted Set
因为整数数组和压缩列表在内存中都是分配一块地址连续的空间然后把集合中的元素一个接一个地放在这块空间内非常紧凑不用再通过额外的指针把元素串接起来这就避免了额外指针带来的空间开销。而且采用集合类型时一个 key 就对应一个集合的数据能保存的数据多了很多但也只用了一个 dictEntry
这样就节省了内存。
集合类型统计模式
Redis
集合类型统计模式常见的有:
聚合统计( 交集、差集、并集统计 ): 对多个集合进行聚合计算时可以选择Set
;排序统计(要求集合类型能对元素保序):Redis
中List
和Sorted Set
是有序集合List
是按照元素进入List
的顺序进行排序的Sorted Set
可以根据元素的权重来排序;二值状态统计( 集合元素的取值就只有 0 和 1 两种 ):Bitmap
本身是用String
类型作为底层数据结构实现的一种统计二值状态的数据类型 Bitmap通过 BITOP 按位 与、或、异或的操作后使用 BITCOUNT 统计 1 的个数。基数统计( 统计一个集合中不重复的元素的个数 ):HyperLogLog
是一种用于统计基数的数据集合类型 统计结果是有一定误差的标准误算率是 0.81% 。需要精确统计结果的话用 Set 或 Hash 类型。
Set
类型适用统计用户/好友/关注/粉丝/感兴趣的人集合聚合操作比如
统计手机APP每天的新增用户数两个用户的共同好友
Redis
中List
和Sorted Set
是有序集合使用应对集合元素排序需求 比如
最新评论列表排行榜
Bitmap
二值状态统计适用数据量大且可以使用二值状态表示的统计比如:
签到打卡当天用户签到数用户周活跃用户在线状态
HyperLogLog
是一种用于统计基数的怎么瘦腿最快最有效数据集合类型 统计一个集合中不重复的元素个数 比如
统计网页的 UV 一个用户一天内的多次访问只能算作一次支持单点查询/范围查询
Redis
中List
和Sorted Set
是有序集合支持范围查询但是Hash
是不支持范围查询的
特殊使用场景
消息队列使用Redis
作为消息队列的实现要消息的基本要求消息保序、处理重复的消息和保证消息可靠性方案有如下:
基于 List 的消息队列解决方案基于 Streams 的消息队列解决方案基于List基于Strems消息保序使用LPUSH/RPOP
使用XADD/XREAD
阻塞读取使用BRPOP
使用XREAD block
重复消息处理生产者自行实现全局唯一IDStreams自动生成全局唯一ID消息可靠性使用BRPOPLPUSH
使用PENDING
List自动留存消息适用场景消息总量小消息总量大需要消费组形式读取数据
基于位置 LBS 服务使用Redis
的特定GEO
数据类型实现GEO
可以记录经纬度形式的地理位置信息被广泛地应用在 LBS 服务中。 比如:打车软件是怎么基于位置提供服务的。
总结
Redis
之所以那么快是因为其基于内存的数据操作和使用Hash
哈希表作为索引其效率高速度快而且得益于其底层数据多样化使得其可以适用于众多场景不同场景中选择合适的数据类型可以提升其查询性能。
更多编程相关知识请访问:编程视频!!
以上就是详解Redis中的数据结构的详细内容!
来源:php中文网
本文发布于:2023-02-23 13:11:31,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/167712909214013.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:互联网常识:详解Redis中的数据结构.doc
本文 PDF 下载地址:互联网常识:详解Redis中的数据结构.pdf
留言与评论(共有 0 条评论) |