| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> Redis对象详解 -> 正文阅读 |
|
[大数据]Redis对象详解 |
文章目录五种基本数据类型Redis支持五种基本数据类型:String,Hash,List,Set,Zset / Sorted Set 首先,读者需要明白,Redis的数据类型是根据 Value来划分的,Key默认全都是String类型。所以以下的文章全都是针对Redis Key Value对中的Value进行讨论的。
Redis对象的组成既然Redis有这些数据类型,那么Redis内部使用时是如何管理这些数据类型的呢? Redis底层是C语言,那么肯定会有一个 struct 来管理这些数据类型。Redis中的每一个对象都有一个redisObject 结构来表示(这也是本文把基本数据类型称为对象的原因),该结构的属性保存了和对象有关的信息,此处只介绍三个重要的属性,分别是type属性、encoding属性和ptr属性
意义:Redis通过encoding属性来设定对象所使用的编码,而不是为特定类型的对象关联一种固定的编码,极大地提升了Redis的灵活性和效率,因为Redis可以根据不同的使用场景来为一个对象设置不同的编码,从而优化对象在某一场景下的效率。 下文便介绍一下各种数据类型的具体实现。 字符串对象字符串对象的编码可以是int、raw或者embstr。先简单介绍一下字符串对象 SDSSDS:Simple Dynamic String,简单动态字符串,是Redis里特有的字符串对象,那么为什么Redis不直接使用C语言的字符串呢? 原因就在于C 语言这种简单的字符串表示方式 不符合 Redis 对字符串在安全性、效率以及功能方面的要求。而Redis的SDS具有一些特殊的属性以及策略,这些使得SDS相比于C语言原生的字符串更符合Redis 追求极致响应速度 以及 操作安全性 和功能方面的要求。 我们来看看String类型的定义
C字符串和SDS之间的区别
C字符串与SDS之间的共性
不同编码的区别int编码当字符串对象值为整数,并且整数值可以用long类型来表示的时候,Redis直接使用 整数值来保存一个字符串对象。 embstr 和 raw这两种编码对应的数据结构都是SDS字符串,但是在内存中的存储方式不太一样。 raw编码会调用两次内存分配函数来分别创建redisObject 结构 和sds 结构 而embstr 编码则只调用一次内存分配函数来分配一块连续的空间,空间中依次包含redisObject 和 sdshdr两个结构 embstr编码的优点:
embstr编码的缺点:
Redis如何选择编码
列表对象列表对象的编码可以是ziplist 或者 linkedlist linkedlist编码如果是linkedlist编码,那么其实和Java中的LinkedList的底层实现很相似,都是使用双向链表作为底层实现的,每个双向链表节点都保存了一个字符串对象,并且具有 pre 和 next 指针。 ziplist编码如果是ziplist编码,那么底层数据结构就会是ziplist 压缩列表这种数据结构,我简单的介绍一下压缩列表。 压缩列表压缩列表是Redis为了节约内存而开发的,它不需要指针指向节点的地址,而是使用一组连续内存块组成的顺序型数据结构。一个压缩列表可以包含任意多个节点,每个节点可以保存一个字节数组或者一个整数值。 读者肯定会很好奇,为什么压缩列表能代替 双向链表 实现列表对象呢? 主要是和以下三点有关:
下面详细介绍一下 内存连续这是压缩列表在内存中的组成部分,各个部分都是利用的一块连续的内存空间,由于内存连续,所以如果知道了某一段 的长度,就可以直接跳过该段访问下一段,比如 A -> B ,如果已知 A的长度为 300 ,又已知 A的起始地址为 P,那么B的起始地址就为 P + 300。 压缩列表的构成
通过这些属性值,我们可以只需要O(1)的时间复杂度,完成许多列表的操作,比如获取节点数量,使用zllen;比如访问表尾节点,用起始地址 + zltail属性即可;至此,我们完成了和双向链表一样的获取表头表尾的操作,获取节点数量的操作,那么如何进行节点的遍历呢?依赖于压缩列表节点的构成。 压缩列表节点的构成压缩列表节点分为三个部分:
至此,我们便可以通过节点的 previous_entry_length 和 encoding 属性来进行列表前后的遍历,那么就基本实现了和双向链表一样的功能。 哈希对象哈希表的编码可以是ziplist或者hashtable ziplist编码这里不再介绍ziplist这种数据结构,主要介绍一下哈希对象如何通过ziplist实现 当哈希对象使用ziplist编码时,保存了同一键值对的两个节点总是紧挨在一起,保存键的节点在前,保存值的节点在后。 也就是说,当我想获取一个key对应的value时,我只需要两个节点两个节点的遍历这个压缩列表,就能遍历完所有的key,当找到对应的value。 hashtable编码使用hashtable编码的Hash对象会使用Redis字典作为底层实现 字典我们先看看Redis中定义的Hash表
从Hash表的结构上来说,我们可以看出来其实和Java 的HashMap实现大同小异。
再看看Redis 字典的数据结构
Redis的字典里主要就是包括了一个容量为2的哈希表数组,以及rehash索引,这也是它与Java HashMap一个关键的不同点,也就是不同的Rehash机制。 Rehash众所周知,传统Hash算法的Rehash一直都是臭名昭著,由于下标通过取余运算获取,一旦扩容,那么所有的节点都会发生Rehash,如此庞大的计算会使得Hash表在一段时间内完全不可用,这对于单线程的Redis无异于是毁灭性的打击,于是Redis采用了渐进式Rehash的优化方法。 过程:
总结:
集合对象集合对象的编码可以是intset 或者 hashtable,intset是一个整数集合,如果一个集合中的对象都是整数,那么就可以使用intset作为底层实现,如果是使用hashtable编码,那么集合对象的实现就和Java中HashSet的实现方式类似。 有序集合对象有序集合可以使用 ziplist 或者 skiplist实现 ziplist实现类似Hash对象的实现,将一个集合元素通过两个ziplist节点保存,第一个节点保存member,第二个节点保存score。遍历的时候也是两个节点一跳,就可以找到下一个集合元素。 为了实现zset有序的功能,ziplist中的集合元素按分值从小到大排序,并且在插入的时候,也会保证插入的节点处于对应分值大小的位置。 skiplist实现对于skiplist编码,显而易见就是用跳跃表作为实现的。除了跳跃表之外,还会使用字典。也就是说,底层是使用跳跃表+字典实现的。 为什么还要使用字典?如果我们使用跳跃表的话,跳跃表是根据score排序的,并且他的查找逻辑也是通过score进行的查找,也就是说,我们可以通过跳跃表,根据对应的score找到对应的member。但是如果是通过member,查找对应的score,我们就无法利用跳跃表快速查找,只能使用线性查找,O(N)级别的遍历跳跃表,在业务层面上来说,这种类似的需求十分常见,比如在排行榜中获取当前用户的积分,所以说如此低效的实现对于Redis而言无疑是一种灾难。 如果我们使用了字典,使用member 为 key,score为value,那么我们就可以通过字典快速的找到一个member对应的score,典型的空间换时间策略。 注意:Redis底层并不是直接使用score作为value,这会使得score的重复存储,所以Redis仅仅让字典的value保存了跳跃表节点的地址。 skiplist跳跃表的实现比较复杂,大致思路就是通过一些特殊实现,使得能在一个有序链表上进行类似二分查找的查找算法,查找的时间复杂度是O(logN)级别的。此处不再赘述跳表的实现,感兴趣的可以看这几篇文章。 Skip List–跳表(全网最详细的跳表文章没有之一) 至于为什么Redis不使用红黑树而是要使用跳表来实现有序集合,这里给出几点原因
小结程序员们除了关注Redis的API调用之外,也应该了解一些Redis底层实现,可以更好的帮助我们处理复杂业务的Redis设计,从而使得我们合理且高效的利用缓存这一高并发利器。 参考文献:
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 6:53:03- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |