读《redis设计与实现》笔记--redis数据结构
redis五大数据结构:string,hash,list,set,zset(有序集合)
redis底层数据结构:简单动态字符串(SDS),链表,字典,跳表,整数集合,压缩列表
底层数据结构详解:
1.简单动态字符串:类似于c的结构体,但是SDS拥有记录已用长度(len)与剩余空间长度(free),当空间不足时会进行扩容。SDS最后会保存一个空字符
所以SDS获取字符串长度的时间复杂度为o(1),SDS自动扩容也不会像C一样产生溢出
利用未使用空间,SDS拥有空间预分配和惰性空间释放两种优化方法。
空间预分配:
修改SDS之后之后,如果len<1MB,将free修改为和len一样的长度,如果len>=1MB,将free修改为1MB。
例如:str = "redis"
如果拼接str与"cluster",那么修改之后len为5+6=11,11+11+1=23,len/free值都是11,加上最后一个空字符,总长为23。
要是str修改之后大小为20MB,那扩容之后就是20MB+1MB+1byte
将扩容需要的次数从最多n次变为至多n次。
惰性空间释放:
不会真正释放内存大小,例如删除redis中的字符e与d,那么str就变为ris,但是free=2。
这样减少释放空间的操作,将来扩容也会减少操作。
tips:SDS有专门的api可以真正释放空间,不用担心惰性释放带来空间的浪费。
二进制安全
C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据。
因此,为了确保Redis可以适用于各种不同的使用场景,SDS的API都是二进制安全的。
SDS和c的区别:
2.链表
应用:列表键的底层实现之一就是链表。当一个列表键包含了数量比较多的元素,又或者列表中包含的元素都是比较长的字符串时,Redis就会使用链表作为列表键的底层实现。
除了链表键之外,发布与订阅、慢查询、监视器等功能也用到了链表,Redis服务器本身还使用链表来保存多个客户端的状态信息,以及使用链表来构建客户端输出缓冲区。
一个链表结点:
链表:
3.字典(key-value)
字典在Redis中的应用相当广泛,比如Redis的数据库就是使用字典来作为底层实现的,对数据库的增、删、查、改操作也是构建在对字典的操作之上的。
字典还是哈希键的底层实现之一,当一个哈希键包含的键值对比较多,又或者键值对中的元素都是比较长的字符串时,Redis就会使用字典作为哈希键的底层实现。
Redis的字典使用哈希表作为底层实现,而每个哈希表节点就保存了字典中的一个键值对。
字典所用的哈希表结构:
每个dictEntry结构保存着一个键值对
dictEntry结构:
字典结构:
type属性是一个指向dictType结构的指针,每个dictType结构保存了一簇用于操作特定类型键值对的函数,Redis会为用途不同的字典设置不同的类型特定函数。
privdata属性则保存了需要传给那些类型特定函数的可选参数。
Redis的哈希表使用链地址法来解决键冲突。
扩展和收缩哈希表的工作可以通过执行rehash(重新散列)操作来完成。
Redis Bgsave 命令用于在后台异步保存当前数据库的数据到磁盘。
对哈希表进行扩展:1.正在执行bgsave,负载因子>=5 2.没有执行bgsave,负载因子>=1
对哈希表进行收缩:负载因子<0.1
渐进式hash:rehash动作并不是一次性、集中式地完成的,而是分多次、渐进式地完成的。
原因:如果哈希表里保存的键值对数量千万甚至亿个键值对,那么要一次性将这些键值对全部rehash的话,庞大的计算量可能会导致服务器在一段时间内停止服务。
所以rehash期间,更新,删除,查找在两个表里进行,旧表查找不到的话去新表查找。
而插入就直接在新表进行,所以旧表只减不增。
字典使用哈希表作为底层实现,每个字典带有两个哈希表,一个平时使用,另一个仅在进行rehash时使用。
4.跳跃表
Redis使用跳跃表作为有序集合键的底层实现之一,如果一个有序集合包含的元素数量比较多,又或者有序集合中元素的成员是比较长的字符串时,Redis就会使用跳跃表来作为有序集合键的底层实现。
Redis只在两个地方用到了跳跃表,一个是实现有序集合键,另一个是在集群节点中用作内部数据结构。
每个节点都有向前,向后的指针,向后的可能有多个(看有多少层有这个数据),向前的只有一个。
插入方法:从底层开始,每一层选择插入或者不插入,插入一层的话就停止。
所以第一层的插入概率1/2,第二次1/4...
5.整数集合
整数集合是集合键的底层实现之一。
整数集合的结构:
contents数组各个项在数组中按值的大小从小到大有序地排列,并且数组中不包含任何重复项。contents数组的真正类型取决于encoding属性的值。
升级:
每当我们要将一个新元素添加到整数集合里面,并且新元素的类型比整数集合现有所有元素的类型都要长时,整数集合需要先进行升级,然后才能将新元素添加到整数集合里面。
升级步骤:1.根据新数据类型,扩展底层数组大小 2.将其他数据设置为新数据类型 3.新元素添加到底层数组
升级好处:一个是提升整数集合的灵活性,另一个是尽可能地节约内存。
节约内存:有int_16,int_32,int_64三种类型,整数集合现在的做法既可以让集合能同时保存三种不同类型的值,又可以确保升级操作只会在有需要的时候进行,这可以尽量节省内存。
没有降级操作。
6.压缩列表
压缩列表是列表键和哈希键的底层实现之一。
一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,就会用压缩列表。
读《redis设计与实现》笔记--redis数据结构相关推荐
- Redis设计与实现笔记2
文章目录 1.主从复制 主从复制的作用 实现 同步 命令传播 心跳检测 2.Sentinel 3.集群 节点 槽指派 重新分片 ASK错误 故障检测和故障转移 参考<Redis设计与实现> ...
- Redis设计与实现-笔记(一)
文章目录 缓存理解 带来问题 本地缓存解决方案 分布式缓存 缓存读写模式/更新策略 正文 第一部分 数据结构与对象 第2章 简单动态字符串 2.1 SDS的定义 2.2 SDS与C字符串的区别 2.2 ...
- 结合redis设计与实现的redis源码学习-2-SDS(简单动态字符串)
上一次我们学习了redis的内存分配方式,今天我们来学习redis最基本的数据结构SDS,在redis的数据库里,包含字符产值的简直对在底层都是由SDS实现的. SDS的基本数据结构是sdshdr结构 ...
- Redis设计与实现 笔记 第十七章 集群 cluster
集群 Redis 集群是 Redis 提供的分布式数据库方案,集群通过分片来进行数据共享,并提供复制和故障转移功能 17.1 节点 一个 Redis 集群通常由多个节点组成,在刚开始的时候,每个节点都 ...
- [redis设计与实现][7]基本数据结构——对象
Redis对基础数据类型进行了封装,构建出上层的对象系统,这个系统包含:字符串对象.列表对象.哈希对象.集合对象和有序集合对象. Redis对象结构: [cce lang="c"] ...
- redis设计与实现 笔记(一)
Redis简单动态字符串 Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组,以下简称 C 字符串), 而是自己构建了一种名为简单动态字符串(simple dynamic st ...
- Redis设计与实现笔记
第一部分:数据结构与对象 简单动态字符串 链表 字典 跳跃表 整数集合 压缩列表 对象 第二部分:单机数据库的实现 数据库 RD ...
- [redis设计与实现][5]基本数据结构——整数集合
整数集合(intset)用于集合键.当一个集合只包含整数值元素,并且数量不多的时候,会使用整数集合作为集合键的底层实现.相对于直接保存字符串,整数集合能够很好地节约内存,但是由于是数组保存,需要特别关 ...
- python redis订阅_Python 学习笔记 - Redis
Redis 和Memcached类似 也是一个开源的内存存储系统,存储格式也是通过键值对的方式.不过和memcached比起来,memcached的value只支持字符串,而redis支持字符串,列表 ...
- 结合redis设计与实现的redis源码学习-8.2-t_string(字符串键)
t_string.c中定义了字符串键的实现过程. #include "server.h" #include <math.h> /* isnan(), isinf() * ...
最新文章
- SQL Server数据类型
- cad批量选择相同块_CAD如何批量重命名图块或样式
- 字节跳动内部学习资料泄露!mysql的安装与配置
- scrapy爬虫值Items
- MySQL For RedHat Linux(源码安装,附安装包)
- MYSQL 入门全套
- MySQL/InnoDB中,乐观锁、悲观锁、共享锁、排它锁、行锁、表锁、死锁概念的理解...
- 利用JS+Ajax实现下拉列表无刷联动,及其相关
- cocos2d-x将背景色改为白色
- dts双轨制会员积分系统,直销系统,分销系统
- 数据结构算法书籍推荐
- 请问 土壤粒径的多重分形维数怎么计算?有matlab计算代码吗?
- 路由器猫服务器未响应,怎么通过猫判断网络连接是否有问题
- Revit打印工具 RevitPrinter
- 苹果cms漫画小说模板
- python将汉字转为拼音字母_科学网—[转载]python中文汉字转拼音 - 陈明杰的博文...
- python sys stdout_Python-如何将sys.stdout复制到日志文件?
- 云原生周刊 | 使用 ChatGPT 协助解决 Prometheus 告警
- 基于多二维码识别的无人机运动真值获取
- Java-Eclipse折叠代码插件 code folding 使用方法
热门文章
- LeetCode 1151. 最少交换次数来组合所有的 1(滑动窗口)
- LeetCode 1120. 子树的最大平均值(DFS自底向上)
- LeetCode 921. 使括号有效的最少添加(栈)
- unity python_Unity引擎内嵌python
- java 工厂模式的写法_java工厂模式三种详解
- vue 图片拖动加载 类似于地图_前端性能优化之图片懒加载(附vue自定义指令)...
- python导入gif_Python之GIF图倒放,沙雕快乐源泉!我已经笑了一天了!
- Facebook提出生成式实体链接、文档检索,大幅刷新SOTA!
- Java多线程系列(五):线程池的实现原理、优点与风险、以及四种线程池实现
- 最强Java面试题全部合集,涵盖BAT大厂面试必考的9大技术!-强烈建议收藏