Redis Set类型解析
Redis的Set是一个无序的、元素唯一的集合。它支持高效的添加、删除、判断元素是否存在等操作,以及多个集合之间的交集、并集、差集运算。其强大的能力源于其精巧的内部实现。 Redis Set的底层实现主要使用了两种数据结构: intset(整数集合):当集合中的元素都是整数且元素数量较少时使用,以节省内存。 dict(字典,即哈希表):这是Set的默认和主力实现,可以存储任意类型的值。 这种根据条件选择不同底层结构的机制称为编码(Encoding)。Set类型的编码可以通过 OBJECT ENCODING your_set_key 命令查看。 核心源码文件Set的实现主要涉及以下文件: src/t_set.c:Set类型的所有命令的实现,如 SADD, SISMEMBER, SINTER 等。 src/intset.c 和 src/intset.h:整数集合 (intset) 的实现。 src/dict.c 和 src/dict.h:字典 (dict) 的实现(与Hash类型共用)。 底层实现之一:intset (整数集合)设计目标为了在特定场景下(元素全是整数且数量...
Redis Hash类型解析
Redis 的 Hash 基础类型一个非常经典的设计,完美体现了 Redis 在内存效率和性能之间所做的权衡。 我们将从以下几个核心方面进行剖析: 底层两种编码(实现)结构 两种编码的切换(转换)条件 核心操作命令的源码实现逻辑 设计思想与总结 底层两种编码结构Redis Hash 类型并不是用一种单一数据结构实现的,而是根据存储数据的具体情况,在两种编码之间动态选择: ziplist (压缩列表): 在数据量较小时使用,以节省内存。 hashtable (哈希表): 在数据量较大时使用,以保证操作效率。 你可以通过 OBJECT ENCODING your_hash_key 命令来查看一个 Hash 键使用的内部编码。 a) ziplist (压缩列表)ziplist 是 Redis 为了节约内存而设计的一种紧凑的、双向的顺序数据结构。它本质上是一个字节数组,可以包含任意多个 entry,这些 entry 会根据存储的内容长度不同而占用不同的字节数。 源码定义 (ziplist.c):虽然没有一个显式的结构体定义 ziplist,但其内存布局可以抽象为: 1<z...
Redis List类型解析
在 Redis 3.2 版本之前,List 类型的实现方式有两种: ziplist(压缩列表):当元素数量少、元素体积小时使用,旨在节省内存。 linkedlist(双向链表):当不满足 ziplist 条件时使用,支持高效的节点增删。 自 Redis 3.2 版本起,List 类型的实现被统一并优化为一种结构:quicklist(快速列表)。 它本质上是 ziplist 和 linkedlist 的混合体,将一个大的 linkedlist 拆分成多个小的 ziplist,然后用双向指针把它们连接起来。这种设计在时间效率和空间效率上取得了完美的平衡。 因此,我们的分析将围绕 quicklist 展开,并深入其基础——ziplist。 一、底层数据结构详解1. Ziplist (压缩列表)ziplist 是 Redis 为了极致地节省内存而设计的一种紧凑的、连续内存存储的数据结构。它不是一个基础数据结构(如链表或数组),而是一系列特殊编码的内存块。 a) 内存布局: 一个 ziplist 在内存中的结构如下所示: 1<zlbytes> <zltail>...
Redis String类型解析
Redis 的 String 类型并不仅仅用于存储文本字符串,它还可以存储数字、二进制数据(如图片序列化后的数据),最大长度可达 512MB。 其核心实现可以概括为两点: 动态字符串库:SDS (Simple Dynamic String) 智能的编码策略:根据值的内容和长度,选择最节省内存的编码方式 基石:SDS (Simple Dynamic String)Redis 没有直接使用 C 语言传统的字符串(以空字符 \0 结尾的字符数组),而是自己构建了一种名为 SDS 的抽象类型。所有键和字符串值都是用 SDS 实现的。 SDS 的数据结构 (源码 sds.h)SDS 的定义非常巧妙,它实际上是一个字节数组(char *),但在其头部隐藏了一个结构体来存储元信息。 12345678/* 注意:这是 Redis 5 及之后版本的结构。在 Redis 3.2 中引入了针对不同长度优化的多种 sdshdr 结构 */struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* 已使用的...
redisObject结构体详解
redisObject通过统一的结构管理多种数据类型,并在底层根据数据特征动态选择最合适的编码方式,力求在性能与内存效率之间找到最佳平衡。 redisObject 结构体详解redisObject 结构体(robj)定义如下(以 Redis 6.2.6 为例): 12345678#define LRU_BITS 24typedef struct redisObject { unsigned type:4; // 对象类型 unsigned encoding:4; // 编码方式 unsigned lru:LRU_BITS; // 用于LRU或LFU信息 int refcount; // 引用计数 void *ptr; // 指向底层实现的数据结构的指针} robj; 字段名 作用 备注 type 标识对象的 数据类型 例如 OBJ_STRING, OBJ_LIST, OBJ_SET, OBJ_ZSET, OBJ_HASH encoding 标识...
Redis五种基本数据类型
Redis 五种基本数据类型(String、List、Hash、Set、ZSet)的强大性能与其精巧的底层数据结构设计密不可分。Redis 并没有直接使用这些简单动态字符串(SDS)、链表、字典等数据结构,而是根据不同的使用场景,用一种上层建筑,下层基础的方式,为同一个数据类型提供了多种底层实现,并在合适的时机进行自动转换,以达到性能与空间的最优平衡。 String(字符串)String 是 Redis 中最基础的数据类型,但其底层实现并非只有一种简单的方式。 底层数据结构: RAW (SDS - Simple Dynamic String): 这是最标准的字符串表示方式。SDS 是 Redis 对 C 语言原生字符串的封装和增强。 结构定义:12345struct sdshdr { int len; // 记录buf数组中已使用字节的数量,等于SDS所保存字符串的长度 int alloc; // 记录buf数组中未使用字节的数量 char buf[]; // 字节数组,用于保存实际的字符串内容}; 优点: O(1) 时间复杂度获...
Redis数据结构和应用场景
Redis 之所以强大和受欢迎,很大程度上是因为它提供了丰富的数据结构,而不仅仅是一个简单的键值存储。这些数据结构让开发者可以直接在存储层解决许多问题,而无需在应用层进行复杂的处理。 Redis 的数据结构可以分为两大类: 基本数据结构:String(字符串)、List(列表)、Hash(哈希)、Set(集合)、Sorted Set(有序集合)。 特殊和高级数据结构: Bitmaps(位图)、HyperLogLogs(基数统计)、Geospatial Indexes(地理空间索引)、Streams(流)。这些通常是在基本数据结构之上实现的,但提供了独特的 API 来解决特定问题。 一、基本数据结构1. String(字符串)描述:最基本的数据类型,一个 Key 对应一个 Value。它是二进制安全的,意味着可以存储任何数据,比如图片、序列化对象等。Value 最大不能超过 512MB。 常用命令:SET, GET, MSET, MGET, INCR, DECR, INCRBY, SETEX(设置过期时间)等。 典型应用场景: 缓存(Cache):这是最经典的场景。将数据库...
Redis速度快的原因
Redis之所以如此快的原因,不仅仅是某一个特性的功劳,而是一系列精妙设计和权衡(Trade-offs)的共同结果。 可以将其原因归结为以下几个核心方面: 基于内存的数据存储这是最根本、最主要的原因。 直接访问 vs. 间接访问:Redis 的所有数据都存储在内存(RAM) 中。内存的读写速度(纳秒级别)远远快于磁盘(毫秒级别,相差10万倍甚至更多)。这意味着 Redis 完全避免了传统数据库(如 MySQL)昂贵的磁盘 I/O 操作。 简单的数据存取模型:对内存中的数据进行操作,就像我们直接操作一个程序中的变量或数据结构一样直接,无需经过复杂的解析器、优化器等层层关卡。 代价:因为数据在内存中,所以成本更高,且数据容量受限于单机内存大小(虽然现在有集群模式)。同时,数据易失,需要配合持久化机制来保证数据安全。 高效的数据结构Redis 不仅仅是简单的 Key-Value 存储,它的 Value 可以是多种数据结构。每种数据结构都经过极致优化,使其在时间和空间上都非常高效。 动态字符串(SDS, Simple Dynamic String):相比 C 语言原生...
