图解Redis之数据结构篇——压缩列表
前言
同整数集合一样压缩列表也不是基础数据结构,而是 Redis 自己设计的一种数据存储结构。它有点儿类似数组,通过一片连续的内存空间,来存储数据。不过,它跟数组不同的一点是,它允许存储的数据大小不同。
一、压缩列表
听到“压缩”两个字,直观的反应就是节省内存。之所以说这种存储结构节省内存,是相较于数组的存储思路而言的。我们知道,数组要求每个元素的大小相同,如果我们要存储不同长度的字符串,那我们就需要用最大长度的字符串大小作为元素的大小(假设是20个字节)。存储小于 20 个字节长度的字符串的时候,便会浪费部分存储空间。

数组的优势占用一片连续的空间可以很好的利用CPU缓存访问数据。如果我们想要保留这种优势,又想节省存储空间我们可以对数组进行压缩。

但是这样有一个问题,我们在遍历它的时候由于不知道每个元素的大小是多少,因此也就无法计算出下一个节点的具体位置。这个时候我们可以给每个节点增加一个lenght的属性。

如此。我们在遍历节点的之后就知道每个节点的长度(占用内存的大小),就可以很容易计算出下一个节点再内存中的位置。这种结构就像一个简单的压缩列表了。
二、Redis压缩列表
压缩列表(zip1ist)是列表和哈希的底层实现之一。
当一个列表只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做列表的底层实现。
当一个哈希只包含少量键值对,比且每个键值对的键和值要么就是小整数值,要么就是长度比较短的字符串,那么Redis就会使用压缩列表来做哈希的底层实现。
2.1 Redis压缩列表的构成
压缩列表是Redis为了节约内存而开发的,是由一系列特殊编码的连续内存块组成的顺序型(sequential)数据结枃。一个压缩列表可以包含任意多个节点(entry),每个节点可以保存一个字节数组或者一个整数值,如下图。

示例:

如上图,展示了一个总长为80字节,包含3个节点的压缩列表。如果我们有一个指向压缩列表起始地址的指针p,那么表为节点的地址就是P+60。
2.2 Redis压缩列表节点的构成
每个压缩列表节点可以保存一个字节数组或者一个整数值。其中,字节数组可以是以下三种长度中的一种。
- 长度小于等于63(2^6-1)字节的字节数组;
- 长度小于等于16383(2^14-1)字节的字节数组
- 长度小于等于4294967295(2^32-1)字节的字节数组
整数值可以是以下6种长度中的一种
- 4位长,介于0至12之间的无符号整数
- 1字节长的有符号整数
- 3字节长的有符号整数
- int16_t类型整数
- int32_t类型整数
- int64_t类型整数

节点的 previous_entry_length属性以字节为单位,记录了压缩列表中前一个节点的长度。 previous_entry_length属性的长度可以是1字节或者5字节。
- 如果前一节点的长度小于254字节,那么 previous_entry_length属性的长度为1字节,前一节点的长度就保存在这一个字节里面。
- 如果前一节点的长度大于等于254字节,那么 previous_entry_length属性的长度为5字节:其中属性的第一字节会被设置为0xFE(十进制值254),而之后的四个字节则用于保存前一节点的长度.
节点的encoding属性记录了节点的content属性所保存数据的类型以及长度。
- 一字节、两字节或者五字节长,值的最高位为00、01或者10的是字节数组编码这种编码表示节点的 content属性保存着字节数组,数组的长度由编码除去最高两位之后的其他位记录。
- 一字节长,值的最高位以11开头的是整数编码:这种编码表示节点的content属性保存着整数值,整数值的类型和长度由编码除去最高两位之后的其他位记录。
节点的content属性负责保存节点的值,节点值可以是一个字节数组或者整数,值的类型和长度由节点的encoding属性决定。

- 编码的最高两位00表示节点保存的是一个字节数组。
- 编码的后六位001011记录了字节数组的长度11。
- content属性保存着节点的值"hello world"。
- 编码11000000表示节点保存的是一个int16_t类型的整数值;
- content属性保存着节点的值10086
2.3 常用操作的时间复杂度
| 操作 | 时间复杂度 |
|---|---|
| 创建一个新的压缩列表 | O(1) |
| 创建一个包含给定值的新节点,并将这个新节点添加到压缩列表的表头或者表尾 | 平均O(N),最坏O(N^2)(可能发生连锁更新) |
| 将包含给定值的新节点插人到给定节点之后 | 平均O(N),最坏O(N^2)(可能发生连锁更新) |
| 返回压缩列表给定索引上的节点 | O(N) |
| 在压缩列表中査找并返回包含了给定值的节点 | 因为节点的值可能是一个字节数组,所以检查节点值和给定值是否相同的复杂度为O(N),而查找整个列表的复杂度则为(N^2) |
| 返回给定节点的下一个节点 | O(1) |
| 返回给定节点的前一个节点 | O(1) |
| 获取给定节点所保存的值 | O(1) |
| 从压缩列表中删除给定的节点 | 平均O(N),最坏O(N^2)(可能发生连锁更新) |
| 删除压缩列表在给定索引上的连续多个 | 平均O(N),最坏O(N^2)(可能发生连锁更新) |
| 返回压缩列表目前占用的内存字节数 | O(1) |
| 返回压缩列表目前包含的节点数量 | 点数量小于65535时为O(1),大于65535时为O(N) |
本文重点
压缩列表是Redis为节约内存自己设计的一种顺序型数据结构。
- 压缩列表被用作列表键和哈希键的底层实现之一。
- 压缩列表可以包含多个节点,每个节点可以保存一个字节数组或者整数值。
添加新节点到压缩列表,或者从压缩列表中删除节点,可能会引发连锁更新操作,但这种操作出现的几率并不高。
参考
《Redis设计与实现》
《Redis开发与运维》
《Redis官方文档》
-----END-----
图解Redis之数据结构篇——压缩列表的更多相关文章
- 图解Redis之数据结构篇——链表
前言 Redis链表为双向无环链表! 图解Redis之数据结构篇--简单动态字符串SDS提到Redis使用了简单动态字符串,链表,字典(散列表),跳跃表,整数集合,压缩列表这些数据结构 ...
- 图解Redis之数据结构篇——简单动态字符串SDS
图解Redis之数据结构篇--简单动态字符串SDS 前言 相信用过Redis的人都知道,Redis提供了一个逻辑上的对象系统构建了一个键值对数据库以供客户端用户使用.这个对象系统包括字符串对象 ...
- 图解Redis之数据结构篇——字典
前言 字典在Redis中的应用非常广泛,数据库与哈希对象的底层实现就是字典. 系列文章 图解Redis之数据结构篇--简单动态字符串SDS 图解Redis之数据结构篇--链表 图解Redis之 ...
- 图解Redis之数据结构篇——跳跃表
前言 跳跃表是一种有序的数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的.这么说,我们可能很难理解,我们可以先回忆一下链表. 一.复习跳跃表 1.1 什么 ...
- 图解Redis之数据结构篇——整数集合
前言 整数集合(intset)并不是一个基础的数据结构,而是Redis自己设计的一种存储结构,是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时, Redis i ...
- Redis 底层数据结构之压缩列表
文章参考:<Redis 设计与实现>黄建宏 压缩列表 压缩列表 ziplist 是列表键和哈希键的底层实现之一.当一个列表键只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比 ...
- redis源码之压缩列表ziplist
压缩列表ziplist1.简介连续,无序的数据结构.压缩列表是 Redis 为了节约内存而开发的, 由一系列特殊编码的连续内存块组成的顺序型(sequential)数据结构. 2.组成 属性 类型 长 ...
- Redis学习之ziplist压缩列表源码分析
一.压缩列表ziplist在redis中的应用 1.做列表键 当一个列表键只包含少量列表项,并且每个列表项要么是小整数,要么是短字符串,那么redis会使用压缩列表作为列表键的底层实现 2.哈希键 当 ...
- 【Redis】ziplist压缩列表
压缩列表 压缩列表是列表和哈希表的底层实现之一: 如果一个列表只有少量数据,并且数据类型是整数或者比较短的字符串,redis底层就会使用压缩列表实现. 如果一个哈希表只有少量键值对,并且每个键值对的键 ...
随机推荐
- canvas多彩粒子星空背景
HTML5 canvas 实现多颜色粒子星空页面背景,喜欢的可以收藏.自己可以定义颜色,粒子透明度,粒子数量,粒子大小. 预览效果图如下: 1.获取canvas上下文,并且动态设置canvas尺寸和屏 ...
- Git 安装教程(2.21.0)
获取安装包地址 1.官网(较慢):https://git-scm.com/downloads 2.下载链接:http://down-ww3.newasp.net/pcdown/soft/soft1/g ...
- volatile的内存语义与应用
volatile的内存语义 volatile的特性 理解volatile特性的一个好方法是把对volatile变量的单个读/写,堪称是使用同一个锁对这些单个读/写操作做了同步. 锁的happens-b ...
- [常用命令]OSX命令
在mac os下,如何通过命令行来下载网络文件?如果你没有安装或wget命令,那么可以使用curl工具来达到我们的目的. curl命令参数: curl ‘url地址’ curl [选项] ‘url地址 ...
- STM32F072从零配置工程-串口USART配置
也是使用HAL库进行配置,通过STMCube生成代码,可以通过这个简单的配置过程看到STMCube生成代码的一种规范: 从main函数入手观察其外设配置结构: 首先是HAL_Init()进行所有外设的 ...
- Python重试模块retrying
Python重试模块retrying 工作中经常碰到的问题就是,某个方法出现了异常,重试几次.循环重复一个方法是很常见的.比如爬虫中的获取代理,对获取失败的情况进行重试. 刚开始搜的几个博客讲的有点问 ...
- Python 爬虫:豆瓣电影Top250,包括电影导演、类型、年份、主演
结果输出到文本文件中. import codecs import requests from bs4 import BeautifulSoup headers={'User-Agent': 'Mozi ...
- c++小游戏——三国杀
#include<iostream> #include<time.h> #include<stdio.h> #include <stdlib.h> us ...
- 「数据分析」Sqlserver中的窗口函数的精彩应用-问题篇
最近看到PowerBI圈子在讨论最大连续区间段的问题,即某人最大的全勤时间,某人的最长的连续打卡时间等问题的计算,佐罗老师给出了10万倍性能的答案.这个问题也引发了笔者一些兴趣,隐约记得以前看过Sql ...
- Hyperledger Fabric 之 Channel ,创建channel链接几项注意点
好长时间没有更新博客,网上也有很多fabric的部署资料,而且也都很不错,也比较全面.我就再想重复的工作暂时就不用做了,后面抽时间在做细化和分类:就将学习和工作中遇到和解决的问题经验,做一些分享. 而 ...