Redis过期键删除策略
Redis 采用了 两种策略相结合 的方法来删除过期键,以达到在合理使用 CPU 时间和避免浪费内存空间之间取得平衡。 这两种策略是:惰性删除 和 定期删除。 此外,当内存不足时,Redis 还会采用 主动删除(逐出) 策略。 惰性删除这是默认的、在访问键时进行的删除策略。 核心思想:只有在访问一个键时,才会顺带检查它是否过期。如果过期,则立即删除。 工作原理: 当你执行 GET、HGET、LRANGE 等任何读写操作访问某个键时。 Redis 会首先检查这个键是否设置了过期时间。 如果设置了,再检查当前时间是否大于该键的过期时间。 如果已过期,则立即删除这个键,并返回 nil(或空值),就像这个键不存在一样。如果未过期,则正常返回键值。 优点: 对 CPU 友好:删除操作只会在访问键时发生,不会消耗额外的 CPU 时间去扫描大量可能永远不会被访问的过期键。 缺点: 对内存不友好:如果一个键已经过期,但之后再也没有被访问,那么它将一直占用着内存空间,成为僵尸键。这可以看作是一种内存泄漏。 为了解决惰性删除的缺点,Redis 还需要另一种策略来配合。 定期删除这...
Redis淘汰策略
Redis 为什么需要淘汰策略?Redis 是一个基于内存的数据库/缓存,当实际使用的内存量超过 maxmemory 参数设置的最大限制时,Redis 会根据配置的淘汰策略(Eviction Policy) 来移除一些键,以便为新数据腾出空间。 Redis 的淘汰策略有哪些?Redis 提供了 8 种淘汰策略,可以分为两大类: 第一类:处理过期键的策略(只针对设置了 TTL 过期的键)这组策略只在有过期时间的键中进行淘汰。 volatile-lru (Least Recently Used) 机制:从设置了过期时间的键中,淘汰最近最少使用的键。 理解:基于时间戳,认为最近没被访问的键以后也不太可能被访问。 volatile-lfu (Least Frequently Used) 机制:从设置了过期时间的键中,淘汰最不经常使用的键。 理解:基于访问频率计数器,认为访问次数最少的键是最不重要的。这是 Redis 4.0 及以上版本新增的策略。 volatile-random 机制:从设置了过期时间的键中,随机淘汰某个键。 理解:简单粗暴,没有开销,但效果不...
Redis ZSet类型解析
Redis 的 ZSet(有序集合)基础类型是一个非常有趣且高效的数据结构,它通过两种不同的内部编码(encoding)来实现其特性,在内存使用和性能之间做出了精妙的权衡。 我们主要关注以下几个方面: ZSet 的两种内部编码 数据结构定义 核心操作的源码逻辑 编码转换 总结 ZSet 的两种内部编码ZSet 并非由单一数据结构实现,而是根据一定的条件,在两种编码之间动态选择: OBJ_ENCODING_ZIPLIST (压缩列表): 在元素数量较少、元素值长度较小时使用。它是一种为节省内存而设计的紧凑型线性数据结构。所有元素(member)和分值(score)都按顺序紧密排列在同一个内存块中。 OBJ_ENCODING_SKIPLIST (跳跃表): 当元素数量或大小超过 zset-max-ziplist-entries 和 zset-max-ziplist-value 配置的阈值时,ZSet 会从 ZIPLIST 转换为 SKIPLIST。它结合了跳跃表(skiplist) 和字典(dict) 两种数据结构,以同时保证排序和高效查找。 这种设计哲学是 Redis 的...
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。 底层数据结构详解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 来解决特定问题。 基本数据结构String(字符串)描述:最基本的数据类型,一个 Key 对应一个 Value。它是二进制安全的,意味着可以存储任何数据,比如图片、序列化对象等。Value 最大不能超过 512MB。 常用命令:SET, GET, MSET, MGET, INCR, DECR, INCRBY, SETEX(设置过期时间)等。 典型应用场景: 缓存(Cache):这是最经典的场景。将数据库查询结果、...
