Redis从入门到精通之底层数据结构压缩列表(ZipList)详解

简介: Redis中的压缩列表(ZipList)是一种特殊的数据结构,用于存储一系列的连续元素。ZipList是Redis中的底层数据结构之一,常用于存储列表和哈希表等数据类型的底层实现。在本文中,我们将深入了解Redis中的压缩列表,包括ZipList的结构和操作等。

Redis中的压缩列表(ZipList)是一种特殊的数据结构,用于存储一系列的连续元素。ZipList是Redis中的底层数据结构之一,常用于存储列表和哈希表等数据类型的底层实现。在本文中,我们将深入了解Redis中的压缩列表,包括ZipList的结构和操作等。

1. 压缩列表的结构

Redis中的压缩列表(ZipList)是由一系列的节点(entry)组成的。每个节点可以是一个字节数组(byte array)、一个整数或者一个指针。在ZipList中,每个节点的大小是不固定的,取决于节点所包含的数据类型和数据大小。ZipList中节点的个数也是不固定的,可以根据需要动态增加或减少。

ZipList的结构如下图所示:

+--------+--------+--------+--------+--+-----+
| zlbytes| zltail | zllen  |entry1  |..|entryN|
+--------+--------+--------+--------+--+-----+
  • zlbytes字段的类型是uint32_t, 这个字段中存储的是整个ziplist所占用的内存的字节数
  • zltail字段的类型是uint32_t, 它指的是ziplist中最后一个entry的偏移量. 用于快速定位最后一个entry, 以快速完成pop等操作
  • zllen字段的类型是uint16_t, 它指的是整个ziplit中entry的数量. 这个值只占2bytes(16位): 如果ziplist中entry的数目小于65535(2的16次方), 那么该字段中存储的就是实际entry的值. 若等于或超过65535, 那么该字段的值固定为65535, 但实际数量需要一个个entry的去遍历所有entry才能得到.
  • zlend是一个终止字节, 其值为全F, 即0xff. ziplist保证任何情况下, 一个entry的首字节都不会是255

其中,zlbytes是压缩列表的长度(包括所有的字节),zltail是指向压缩列表尾部的指针,zllen是压缩列表中节点的个数,entry1到entryN是压缩列表中的所有节点。

节点结构

在压缩列表中,每个节点的结构如下:

+--------+--------+
| prevlen| encoding| data  |
+--------+--------+

prevlen是前一个节点的长度(单位为字节),encoding是数据的编码方式,data是节点的实际数据。在压缩列表中,prevlen和encoding都是可选的。当节点的前一个节点的长度小于254字节时,prevlen字段被省略,encoding字段存储在数据之前,否则prevlen字段占用5个字节,encoding字段存储在prevlen后面的5个字节中。

根据不同的数据类型,压缩列表中节点的编码方式也有所不同,下面是常用的节点编码方式:

  • 字节数组(byte array):
+--------+--------+---------------+
| prevlen| 0xc000 |    length     |
+--------+--------+---------------+
|              data               |
+---------------------------------+

其中,0xc000是一个特殊的编码方式,用于标识节点存储的是字节数组。length是字节数组的长度,data是字节数组的实际数据。

  • 整数:
+--------+--------+--------+
| prevlen|  int   |   int  |
+--------+--------+--------+

其中,int是一个整数,可以是8位、16位或32位的有符号整数。

  • 指针:
+--------+--------+--------+
| prevlen|  0x01  |  ptr   |
+--------+--------+--------+

其中,0x01是一个特殊的编码方式,用于标识节点存储的是指针。ptr是一个指针,可以指向任意的内存地址。

2. 压缩列表的操作

Redis中的压缩列表支持以下常用的操作:

  • 压缩列表的创建
unsigned char *zl = ziplistNew();
  • 压缩列表的添加
zl = ziplistPush(zl, s, len, ZIPLIST_TAIL);

其中,s是一个字节数组,len是字节数组的长度,ZIPLIST_TAIL表示在压缩列表的尾部添加节点。

zl = ziplistPushInt(zl, value);

其中,value是一个整数,表示在压缩列表的尾部添加整数节点。

  • 压缩列表的删除
zl = ziplistDelete(zl, &p);

其中,p是一个指向要删除的节点的指针。

  • 压缩列表的遍历
unsigned char *p = ziplistIndex(zl, index);
unsigned char *entry = NULL;
unsigned int entry_len = 0;
long long entry_int = 0;
int ret = ziplistGet(p, &entry, &entry_len, &entry_int);

其中,index是节点的下标,p是指向节点的指针,entry是节点的数据(字节数组或整数),entry_len是字节数组的长度,entry_int是整数的值,ret表示节点的数据类型(字节数组或整数)。

  • 压缩列表的长度
unsigned int ziplistLen(unsigned char *zl);

以上是常用的压缩列表操作,还有其他的操作可以参考Redis源代码中的ziplist.h和ziplist.c文件。

3. 压缩列表的优缺点

3.1优点:

  • 紧凑的存储结构使得压缩列表的空间占用更小,可以在一定程度上减少内存碎片的发生。
  • 压缩列表支持动态增加和删除节点,可以随着数据的增长而自动扩容或缩容,不需要预先分配空间。
  • 压缩列表的节点采用紧凑的存储方式,使得节点访问和遍历的效率较高。同时,压缩列表支持从头和尾部两个方向同时遍历节点。

3.2缺点:

  • 节点大小不固定,当节点的大小随着数据的增长而不断变化时,可能会导致内存碎片的发生,从而增加了内存分配和释放的成本。
  • 压缩列表不支持快速的节点插入和删除操作,因为在插入或删除节点时,需要对后面的节点进行移动,会导致频繁的内存复制操作,从而影响性能。如果需要频繁进行插入和删除操作,建议使用链表等其他数据结构。
  • 压缩列表的节点的数据类型和大小有限制,不适合存储大量的大型数据。例如,压缩列表最大支持512MB的大小,单个节点最大支持64KB的大小,单个整数节点最大支持32位的有符号整数。如果需要存储大量的大型数据,建议使用其他数据结构,例如哈希表或有序集合。

4. 总结

本文详细介绍了Redis中的压缩列表(ZipList),包括ZipList的结构和操作等。压缩列表是Redis中的底层数据结构之一,常用于存储列表和哈希表等数据类型的底层实现。压缩列表具有紧凑的存储结构、支持动态增加和删除节点、支持快速的节点访问和遍历等优点,但也有节点大小不固定、不支持快速的节点插入和删除操作等缺点。在实际应用中,需要根据具体的需求选择合适的数据结构来存储数据。

目录
相关文章
|
存储 缓存 NoSQL
Redis 服务器全方位介绍:从入门到核心原理
Redis是一款高性能内存键值数据库,支持字符串、哈希、列表等多种数据结构,广泛用于缓存、会话存储、排行榜及消息队列。其单线程事件循环架构保障高并发与低延迟,结合RDB和AOF持久化机制兼顾性能与数据安全。通过主从复制、哨兵及集群模式实现高可用与横向扩展,适用于现代应用的多样化场景。合理配置与优化可显著提升系统性能与稳定性。
905 0
|
11月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
819 6
|
12月前
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
10月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
532 86
|
10月前
|
存储 消息中间件 NoSQL
Redis数据结构:别小看这5把“瑞士军刀”,用好了性能飙升!
Redis提供5种基础数据结构及多种高级结构,如String、Hash、List、Set、ZSet,底层通过SDS、跳表等实现高效操作。灵活运用可解决缓存、计数、消息队列、排行榜等问题,结合Bitmap、HyperLogLog、GEO更可应对签到、UV统计、地理位置等场景,是高性能应用的核心利器。
|
10月前
|
存储 缓存 NoSQL
Redis基础命令与数据结构概览
Redis是一个功能强大的键值存储系统,提供了丰富的数据结构以及相应的操作命令来满足现代应用程序对于高速读写和灵活数据处理的需求。通过掌握这些基础命令,开发者能够高效地对Redis进行操作,实现数据存储和管理的高性能方案。
323 12
|
10月前
|
存储 消息中间件 NoSQL
【Redis】常用数据结构之List篇:从常用命令到典型使用场景
本文将系统探讨 Redis List 的核心特性、完整命令体系、底层存储实现以及典型实践场景,为读者构建从理论到应用的完整认知框架,助力开发者在实际业务中高效运用这一数据结构解决问题。
|
10月前
|
存储 缓存 NoSQL
【Redis】 常用数据结构之String篇:从SET/GET到INCR的超全教程
无论是需要快速缓存用户信息,还是实现高并发场景下的精准计数,深入理解String的特性与最佳实践,都是提升Redis使用效率的关键。接下来,让我们从基础命令开始,逐步揭开String数据结构的神秘面纱。
|
存储 NoSQL 算法
Redis设计与实现——数据结构与对象
Redis 是一个高性能的键值存储系统,其数据结构设计精妙且高效。主要包括以下几种核心数据结构:SDS、链表、字典、跳跃表、整数集合、压缩列表。此外,Redis 对象通过类型和编码方式动态转换,优化内存使用,并支持引用计数、共享对象和淘汰策略(如 LRU/LFU)。这些特性共同确保 Redis 在性能与灵活性之间的平衡。
561 12

热门文章

最新文章