redis源码之list结构的实现
时间:2022-07-25
本文章向大家介绍redis源码之list结构的实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
关于redis的list的常用命令就不多说了 常用的命令lpush,rpush,lpop,rpop,lrangge等,这个不错过多的演示,相信研究源码的同学应该都知道这些,唯一要说的就是在redis中有BRPOP等命令,这个是通过redisDb中的blocking_keys和ready_keys来实现,当然这个不是咱们这篇文章需要讨论的重点
typedef struct redisDb {
dict *dict; /* The keyspace for this DB 字典数据结构,非常重要*/
dict *expires; /* Timeout of keys with a timeout set 过期时间*/
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP) list一些数据结构中用到的阻塞api*/
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS 事务相关处理 */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
unsigned long expires_cursor;/* Cursor of the active expire cycle. */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;
对于redis的list来说,list是一个有序(按照加入的时序来排序)的数据结构,redis采用quicklist(双端链表)和ziplist作为list的底层实现 我们先来看看ziplist的结构图
具体各个属性的含义都在图片中有所说明,其实ziplist就是一个非常紧凑的数据结构,非常节省空间,但是它也存在对应的问题。比如我们在新加一个元素的时候,我们需要重新分配一块内存空间,然后再把数据全部拷贝过来,如果数据量小还好说,数据量大了非常影响性能,所以redis中在处理list的时候引入了quicklist的数据结构
其实quicklist的实现也比较简单,就是用了一个双向链表把各个ziplist给连接了起来。那么问题来了,每个quicklistNode中的ziplist是多大呢?根据什么来拆分呢?在redis.conf中
# Lists are also encoded in a special way to save a lot of space.
# The number of entries allowed per internal list node can be specified
# as a fixed maximum size or a maximum number of elements.
# For a fixed maximum size, use -5 through -1, meaning:
# -5: max size: 64 Kb <-- not recommended for normal workloads
# -4: max size: 32 Kb <-- not recommended
# -3: max size: 16 Kb <-- probably not recommended
# -2: max size: 8 Kb <-- good
# -1: max size: 4 Kb <-- good
# Positive numbers mean store up to _exactly_ that number of elements
# per list node.
# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size),
# but if your use case is unique, adjust the settings as necessary.
list-max-ziplist-size -2 //单个ziplist节点最多存储8kb,超过则进行分裂,将数据存储在新的ziplist节点中
双向链表的问题就是会造成很多不连续的内存碎片,于是就需要尽量减少list的片段,就需要进行压缩
# Lists may also be compressed.
# Compress depth is the number of quicklist ziplist nodes from *each* side of
# the list to *exclude* from compression. The head and tail of the list
# are always uncompressed for fast push/pop operations. Settings are:
# 0: disable all list compression
# 1: depth 1 means "don't start compressing until after 1 node into the list,
# going from either the head or tail"
# So: [head]->node->node->...->node->[tail]
# [head], [tail] will always be uncompressed; inner nodes will compress.
# 2: [head]->[next]->node->node->...->node->[prev]->[tail]
# 2 here means: don't compress head or head->next or tail->prev or tail,
# but compress all nodes between them.
# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail]
# etc.
list-compress-depth 0//0代表所有节点,都不进行压缩,1代表从头节点往后走一个,尾节点往前走一个不用压缩,2、3、4以此类推 这个目的主要是减少内存的碎片
- 一条sql语句的建议调优分析(r5笔记第73天)
- O API - REST APIs的替代品
- 【专业技术】从4行代码看右值引用
- 【专业技术】8大你不得不知的Android调试工具
- 数据刷新中的并行改进(二) (r5笔记第76天)
- Spring【AOP模块】就这么简单
- 【专业技术】如何写出优美的C 代码?
- StringUtils工具类常用方法
- 数据刷新中的并行改进(三) (r5笔记第79天)
- SSH【史上最详细整合】
- Github 项目推荐 | TensorFlow 项目模板架构最佳实践
- 两个死锁的实例 (r5笔记第90天)
- SSM【史上最详细整合】
- 终结 finalize()和垃圾回收(garbage collection)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 浅谈分词算法基于字的分词方法(HMM)
- 优雅的重启服务
- Go defer 会有性能损耗,尽量不要用?
- 带入gRPC:分布式链路追踪 gRPC + Opentracing + Zipkin
- 聊聊Golang逃逸分析
- 结构型设计模式:适配器模式和门面模式
- 结构型设计模式:代理模式
- kubernete中的原子调度单位:pod
- mybatis-generator在命令行及IEAD中的使用
- mybatis-generator在命令行及IDEA中的使用
- 70-STM32+ESP8266+AIR202基本控制篇-移植使用-移植单片机MQTT底层包到自己的工程项目
- springboot研究:springboot自带监控actuator
- springboot研究:springboot使用swagger自动构建api
- numpy/pandas瞎搞系列(一):OLS,WLS的numpy实现
- redis实战第三篇 redis sentinel安装和部署