《Redis设计与实现》中说:redis列表对象有两种底层编码格式:ziplist、linkedlist,其中ziplist用压缩列表实现、linkedlist用双向链表实现

但我在实践中,没有发现linkedlist的使用,而发现了一种叫"quicklist"的type,意为一个由ziplist组成的双向链表

首先了解列表对象的结构

// redis对象内存分配,列出主要相关的属性
redisObject {
// 对于列表对象,type = REDIS_LIST
type
// 列表对象的底层编码格式,有三种:ziplist、linkedlist、quicklist
encoding
// 指向实际保存列表内容的空间
ptr
// 还有其他属性
......
}

上面的redisObject不实际保存列表内容,而是通过ptr指向实际保存列表内容的空间

根据编码格式的不同,ptr所指向的空间的结构会有所区别

ziplist编码

ziplist的实现为压缩列表,这个结构在redis中经常用到,

核心思想:能不用指针就不用指针,尽量依靠"记录各个节点、头尾之间的字节偏移量,来达到指针的效果"

一个基本的压缩列表其空间分配如下:

zlbytes:4字节,记录整个压缩列表占用的字节大小

zltail:4字节,记录"tail数据节点的起止地址"距离"整个压缩列表起始地址"的字节偏移量

zllen:2字节,记录节点数量(2直接最大只能存65536,所以当zllen<65536时是准确值,zllen=65536时,需要遍历才能知道准确值)

entryX:实际保存的数据,长度就不固定了

zlend:1字节,内容为0xFF,是压缩列表的结束标志

其中每个entryX,其内部结构由 previous_entry_length 、 encoding 、 content 三个部分组成

previous_entry_length:保存了前一个entry节点的总长度

  • 如果前驱的长度<254字节,那么previous_entry_length采用 1字节
  • 如果前驱的长度>=254字节,那么previous_entry_length采用 5字节,其中第一字节内容固定为0xFE(254),后四个字节来保存前驱的长度。(好像没有考虑过前驱超级长,比 2^8 * 5 还长的情况)

encoding:保存content中数据的类型

content:存数据。整数就直接是整数、字符串是字符串对象

ziplist这种结构的好处:

  • 数据连续且很紧凑,空间利用效率好

存在的问题:

  • 不利于增删数据,需要频繁修改内存
  • 存在"连锁更新"问题:
    1. 有这样一种情况,列表中有一串节点,大小比如都是253字节
    2. 突然在其中插入了一个大小为600字节的节点,这时其next节点本身只用1字节来保存pre节点的大小,现在不行了,需要改成5字节
    3. 改成5字节后,next节点大小变成了253-1+5=257字节,next的next也不能再用1字节了,也得扩
    4. ......
    5. 当在一串大小临界的节点中插入一个大数据时,会出现连锁更新现象,导致频繁分配内存
    6. 在一串大小刚刚超过254的节点中删除一个小数据时,也会出现类似的情况,频繁缩小内存
    7. 问题本身不常遇到

应用场景:

  • 列表较短,并且数据都是小整数值、短字符串
  • 当一个哈希键只包含少量kv对、且key和value都是小整数值、短字符串时,redis也会使用压缩列表来做
  • 127.0.0.1:> hmset profile "name" "jack" "age"
    OK
    127.0.0.1:> object encoding profile
    "ziplist"

linkedlist编码

没有很特别,ptr指向一个双端链表

quicklist编码

《Redis设计与实现》中没有具体写。其结构为 A doubly linked list of ziplists,一个由ziplist组成的双向链表

其本身还是一个双向链表,但链表的每个节点不只保存一个数据,而是保存着一个ziplist

我理解是ziplist和linkedlist的一种结合:从整体上看整个list是不连续的,每个节点之间依靠指针访问。从局部上看数据是连续的,每个节点内依靠压缩列表实现,提高空间利用效率

redis_列表对象的更多相关文章

  1. redis 系列11 列表对象

    一. 列表对象概述 Redis列表是简单的字符串列表,按照插入顺序排序.你可以添加一个元素到列表的头部(左边)或者尾部(右边).一个列表最多可以包含 232 - 1 个元素 (4294967295, ...

  2. (63)Wangdao.com第十天_预处理、预解析_函数 上下文对象、参数列表对象

    预解析.预处理 1. 在全局代码执行之前,js 引擎 就会创建一个栈来存储管理所有的 执行上下文对象 2. 在 全局执行上下文 window 确定以后,进行压栈 3. 在 函数执行上下文对象 确定以后 ...

  3. JSON的String字符串与Java的List列表对象的相互转换

    1.JSON的String字符串与Java的List列表对象的相互转换 在前端: 1.如果json是List对象转换的,可以直接遍历json,读取数据. 2.如果是需要把前端的List对象转换为jso ...

  4. python之列表对象

    1. 获取列表中的某个值 描述:获取下标所对应的值 语法: print(li[0]) #[取索引值] 样例: li = list(['a','b','c']) val=(li[0]) #获取下标所对应 ...

  5. redis_字符串对象

    Redis总共支持五种数据类型:string,hash,list,set及zset.这里介绍字符串类型的实现 首先了解字符串对象的结构 // redis对象内存分配,列出主要相关的属性 redisOb ...

  6. java 8中列表对象多条件排序

    java 8 新加了 lambda 表达式,当接口是一个 @FunctionalInterface 时可以使用 lambda 表达式代替 Function典型的应用场景为:A. 1个只有1个方法的接口 ...

  7. python基础:11.列表对象属性排序

    def __lt__ def __gt__ def __repr__

  8. python 列表对象的增减

  9. springMVC List对象转换为json列表对象

    @ResponseBody @RequestMapping("xxx.do") public List<POJO> getList(){ return List< ...

随机推荐

  1. ELK日志分析平台搭建

    ELK平台介绍 在搜索ELK资料的时候,发现这篇文章比较好,于是摘抄一小段: 以下内容来自:http://baidu.blog.51cto.com/71938/1676798 日志主要包括系统日志.应 ...

  2. 数据仓库系列 - 缓慢渐变维度 (Slowly Changing Dimension) 常见的三种类型及原型设计

    在从 OLTP 业务数据库向 DW 数据仓库抽取数据的过程中,特别是第一次导入之后的每一次增量抽取往往会遇到这样的问题:业务数据库中的一些数据发生了更改,到底要不要将这些变化也反映到数据仓库中?在数据 ...

  3. 关于AVL树的思考

    AVL树即平衡二叉树,每个结点有一个平衡因子,即左子树高度减去右子树高.每插入一个结点时,从根部开始按二叉排序树的方法,与节点不断比较,按大小向左右子树插入.在与最后的节点比较后插入时,若有兄弟节点, ...

  4. pandas 中有关isin()函数的介绍,python中del解释

  5. 48 【golang】json的效率

    本文将主要做如下几方面的测试: 1,构造一个[100]struct的数组,然后来测试它的json编码后的字符串 或者([]byte),首先关心它的功能是否正常: 2,在很早之前,我们在使用golang ...

  6. Ubuntu 16.04 安装OpenCV 3.4.3

    cmake过程中可能遇到的问题:1.如果网络不好,出现ippicv_linux_20151201.tgz无法在终端下载的情况,则可以先单独下载 ippicv_linux_20151201.tgz之后, ...

  7. 使用Snappy将html或者url转成PDF文件

    这是一个操作简单的html文件或者url转PDF的php库 Github地址 https://github.com/KnpLabs/snappy 安装: $ composer require knpl ...

  8. matplotlib 绘图报错 RuntimeError: Invalid DISPLAY variable

    ssh 远程登录 Linux 服务器使用 matplotlib.pyplot 绘图时报错 原因: matplotlib 在 windows 下的默认 backend 是 TkAgg:在 Linux 下 ...

  9. GUI学习之二——PyQt控件初识

    一.控件概念 控件是一个程序界面上的各个独立的元素, 它具备用户点击.接收用户输入.展示不同内容.存放其他控件等功能. 二.控件分类 常用的控件按功能可以分为以下几种类 按钮 QPushButton— ...

  10. android shape 怎么在底部画横线

    使用layer-list可以,画了两层 1 2 3 4 5 6 7 8 9         <layer-list>             <!-- This is the lin ...