前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你确定不来了解一下Redis中List的原理吗

你确定不来了解一下Redis中List的原理吗

作者头像
大数据真好玩
发布2019-08-08 15:39:19
1.1K0
发布2019-08-08 15:39:19
举报
文章被收录于专栏:暴走大数据暴走大数据

前言

在上一章中我们介绍了 Hash的一些内部原理(《你确定不来了解一下Redis中Hash的原理吗》),在这一章中我们再来讨论在五种数据结构中 List 的基本使用和一些内部实现.

基本介绍

Redis的List 呢相当于 Java 中的 LinkedList,也是双向链表.具有一些和 LinkedList 同样的特征,比如插入和删除一条很快,时间复杂度为 O(1),获取头结点和尾节点也很快,时间复杂度也为 O(1),随机读取则相对较慢时间复杂度为 O(n).常用作消息队列.

当做队列使用时,遵循先进先出原则:

代码语言:javascript
复制
> rpush books python java golang
(integer) 3
> lpop books
"python"
> lpop books
"java"

当做栈使用时,遵循先进后出原则:

代码语言:javascript
复制
> rpush books python java golang
(integer) 3
> rpop books
"golang"
> rpop books
"java"

同时还可以通过 get(index)的方法获取:

代码语言:javascript
复制
> rpush books python java golang
(integer) 3
> lindex books 0
"python"
> lindex books -1
"golang"

index从 0 开始,可以为负数 -1 代表倒数第一个元素

内部实现

上述部分我们把 Redis 中的 List当做 Java 中的 LinkedList 操作,因为有很多相同的部分.但实际上在 Redis 中链表的内部实现可不是一个简单的双向链表.在数据量较少的时候它的底层存储结构为一块连续内存,称之为ziplist(压缩列表).当数据量较多的时候将会变成链表的结构.后来因为链表需要 prev 和 next 两个指针占用内存很多,改用 ziplist+链表的混合结构,称之为 quicklist(快速链表).在新的版本中 Redis 链表统一使用 quicklist来存储.下面我们就来详细介绍这种数据结构.

ziplist 压缩列表

先来看看 ziplist 的数据结构:

代码语言:javascript
复制
struct ziplist<T>{
    int32 zlbytes;            //压缩列表占用字节数
    int32 zltail_offset;    //最后一个元素距离起始位置的偏移量,用于快速定位到最后一个节点
    int16 zllength;            //元素个数
    T[] entries;            //元素内容
    int8 zlend;                //结束位 0xFF
}

如图所示:

有了 ztail_offset 就可以快速的定位到最后一个节点,这样就可以倒序遍历了.也就是说 ziplist支持双向遍历.

下面再来看下 entry 的内部实现:

代码语言:javascript
复制
struct entry{
    int<var> prevlen;            //前一个 entry 的长度
    int<var> encoding;            //元素类型编码
    optional byte[] content;    //元素内容
}

当 ziplist 倒序遍历的时候,就是通过这个pervlen定位到前一个元素位置的.

encoding 保存了 content 的编码类型.

content 则是保存的元素内容,它是optional 类型表示是这个字段是可选的.当content 是很小的整数时,他会内联到 encoding 字段的尾部.

quicklist 快速列表

quicklist 是 ziplist 和链表的混合体.下面是 quicklist和 node 的部分数据结构:

代码语言:javascript
复制
struct quicklist{
    quicklistNode* head;    //指向头结点
    quicklistNode* tail;    //指向尾节点
    long count;                //元素总数
    int nodes;                //quicklistNode节点的个数
    int compressDepth;        //压缩算法深度
    ...
}

为了节约空间 Redis 还会对 ziplist 使用 LZF 算法进行压缩,可以选择压缩深度.我们待会在说.

如上图所示,quicklist含有两个 quicklistNode 代表头结点和尾节点,其中每个head 和 tail 之间是双向链表.每个quicklistNode指向一个 ziplist.

代码语言:javascript
复制
struct quicklistNode{
    quicklistNode* prev;    //前一个节点
    quicklistNode* next;    //后一个节点
    ziplist* zl;            //压缩列表
    int32 size;                //ziplist大小
    int16 count;            //ziplist 中元素数量
    int2 encoding;            //编码形式 存储 ziplist 还是进行 LZF 压缩储存
    ...
}

在 quicklist 中每个 ziplist 默认大小是 8kb,超出这个字节就会增加一个 ziplist.这个默认大小是可配置的,由list-max-ziplist-size决定.

上面说到 ziplist 可以使用 LZF 算法压缩,通过list-compress-depth配置.默认情况下quicklist 的压缩深度是 0,也就是不压缩.配置为 1 的话代表从头/尾开始第 1 个ziplsit 进行压缩.

— THE END —

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大数据真好玩 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 内部实现
    • ziplist 压缩列表
      • quicklist 快速列表
      相关产品与服务
      云数据库 Redis
      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档