1.[redis 数数据实现源码走读] maxmemory 数据淘汰策略
2.redis源码学习-quicklist篇
3.挖一挖 Redis 所有数据类型的底层数据结构
4.Redis数据结构(二)-List、Hash、据类Set及Sorted Set的型源结构实现
5.Redis 源码分析字典(dict)
6.Redis教程——数据类型(基数统计、地理空间、类型位域)
[redis 原理源码走读] maxmemory 数据淘汰策略
Redis 是一个内存数据库,通过配置 `maxmemory` 来限定其内存使用量。数数据实现魔域源码泄露当 Redis 据类主库内存超出限制时,会触发数据淘汰机制,型源以减少内存使用量,类型直至达到限制阈值。原理
当 `maxmemory` 配置被应用,数数据实现Redis 据类会根据配置采用相应的数据淘汰策略。`volatile-xxx` 类型配置仅淘汰设置了过期时间的型源数据,而 `allkeys-xxx` 则淘汰数据库中所有数据。类型若 Redis 原理主要作为缓存使用,可选择 `allkeys-xxx`。
数据淘汰时机发生在事件循环处理命令时。有多种淘汰策略可供选择,从简单到复杂包括:不淘汰数据(`noeviction`)、随机淘汰(`volatile-random`、`allkeys-random`)、采样淘汰(`allkeys-lru`、`volatile-lru`、`volatile-ttl`、`volatile-freq`)以及近似 LRU 和 LRU 策略(`volatile-lru` 和 `allkeys-lru`)。
`noeviction` 策略允许读操作但禁止大多数写命令,返回 `oomerr` 错误,仅允许执行少量写命令,如删除命令 `del`、`hdel` 和 `unlink`。
`volatile-random` 和 `allkeys-random` 机制相对直接,随机淘汰数据,策略相对暴力。
`allkeys-lru` 策略根据最近最少使用(LRU)算法淘汰数据,优先淘汰最久未使用的数据。
`volatile-lru` 结合了过期时间与 LRU 算法,优先淘汰那些最久未访问且即将过期的数据。
`volatile-ttl` 策略淘汰即将过期的数据,而 `volatile-freq` 则根据访问频率(LFU)淘汰数据,pidtask源码考虑数据的使用热度。
`volatile-lru` 和 `allkeys-lru` 策略通过采样来近似 LRU 算法,维护一个样本池来确定淘汰顺序,以提高淘汰策略的精确性。
总结而言,Redis 的数据淘汰策略旨在平衡内存使用与数据访问需求,通过灵活的配置实现高效的数据管理。策略的选择应基于具体应用场景的需求,如数据访问模式、性能目标等。
redis源码学习-quicklist篇
Redis源码中的quicklist是ziplist优化版的双端链表,旨在提高内存效率和操作效率。ziplist虽然内存使用率高,但查找和增删操作的最坏时间复杂度可能达到O(n^2),这与Redis高效数据处理的要求不符。quicklist通过每个节点独立的ziplist结构,降低了更新复杂度,同时保持了内存使用率。
quicklist的基本结构包括:头节点(head)、尾节点(tail)、entry总数(count)、节点总数(len)、容量指示(fill)、压缩深度(compress)、以及用于内存管理的bookmarks。节点结构包括双向链表的prev和next,ziplist的引用zl,ziplist的字节数sz、item数count、以及ziplist类型(raw或lzf压缩)和尝试压缩标志(attempted_compress)。
核心操作函数如create用于初始化节点,insert则根据需求执行头插法或尾插法。delete则简单地从链表中移除节点,释放相关内存。quicklist的优化重点在于ziplist,理解了ziplist的工作原理,quicklist的数据结构理解就相对容易了。
挖一挖 Redis 地摊源码所有数据类型的底层数据结构
Redis,这款高效的数据存储系统,提供了多种数据类型的底层实现,以满足不同场景下的高效处理需求。让我们深入探究一下这些核心数据结构:
首先,字符串(String)是Redis中最基础的数据类型,它以键值对的形式存储数据,底层实现通常是连续的内存空间,便于快速读取和修改。
哈希表(List)则支持存储一系列有序或无序的元素,每个元素关联一个唯一的键。在Redis中,它使用双向链表来保持数据的顺序,提供了高效的元素插入、删除和查找操作。
集合(Set)存储不重复的元素,Redis通过哈希表实现,确保了元素的唯一性,查找和添加操作非常迅速。
有序集合(Sorted Set)结合了哈希表和有序列表的特点,每个元素有唯一的分数值,可以对元素进行排序和范围查询,它底层通常采用跳表或者区间树来提高性能。
更复杂的数据结构如Bitmaps(位图)用于高效地存储大量布尔值,通过位操作实现快速的集合操作。HyperLogLog(基数估计)则用于近似计数,适用于海量数据的统计,其占用空间小,但精度稍有牺牲。
Geospatial(地理空间索引)则支持基于地理位置的数据存储和查询,它利用空间数据结构如R-Tree,使得地理位置相关的数据查找和分析变得简单高效。
总的来说,Redis通过这些巧妙的数据结构设计,提供了强大且灵活的数据管理能力,适应了从简单的键值对存储到复杂的数据分析的各种应用场景。
Redis数据结构(二)-List、Hash、Set及Sorted Set的快马源码结构实现
List类型通常被用作异步消息队列、文章列表查询等;存储有序可重复数据或作为简单的消息推送机制时,可以使用Redis的List类型。这类数据的存储通常会使用链表或者数组作为存储结构。如果能够将链表和数组的特点结合起来,就能够很好地处理List类型的数据存储。 Redis在早期使用了ZipList作为List类型的存储结构。ZipList是一个连续的内存块,由表头、若干个entry节点和压缩列表尾部标识符zlend组成。通过一系列编码规则,提高了内存的利用率,适用于存储整数和短字符串。每次增加和删除数据时,所有数据都在同一个ZipList中进行搬移操作。如果将一个组数据按阈值进行拆分出多个数据,就能保证每次只操作某一个ZipList。3.2之后,Redis开始使用QuickList作为更有效的List实现。 QuickList维护了一种宏观上的双端链表,每个节点为对ZipList的包装,即quicklistNode。每个quicklistNode都会通过前后指针相互指向,QuickList包含头、尾quicklistNode的指针。QuickList使用每个ziplist的最大容量、数据压缩范围和单个ziplist节点最大存储量来提升数据存取效率。通过设置这些参数,可以调整数据压缩的程度,以优化性能。例如,-5表示最大容量为KB,适用于非正常工作负载;-4表示最大容量为KB,不推荐;-3表示最大容量为KB,可能不推荐;-2表示最大容量为8KB,较好;-1表示最大容量为4KB,较好。 Redis的链表实现具有以下特性: 1. 通过快速增加或减少节点,链表可以自动调整大小,sweet源码以适应存储的数据量变化。2. QuickList允许在链表的头部和尾部进行高效插入和删除操作。
3. 通过链表的结构,可以实现快速的数据访问,尤其是对于需要频繁访问数据的场景。
Hash
Hash数据结构在存储一个对象时,可以直接将该对象进行序列化后使用String类型存储,然后通过反序列化获取对象。对于只需要获取对象的某个属性的场景,可以将每个属性分别存储,但这样会导致Redis的dict中存在大量key,影响键的生命周期管理效率。使用Map结构可以将属性与值关联起来,减少存储空间,提高效率。 Redis的Hash数据结构也是使用dict实现的。当数据量较小或单个元素较小时,底层使用ZipList存储。配置如下:ziplist元素个数超过时,将改为hashtable编码。
单个元素大小超过字节时,将改为hashtable编码。
Set
Set类型适合用于对不重复集合的操作,可以判断元素是否存在于集合中。Set数据结构底层实现为value为null的dict,当数据可以使用整型表示时,Set集合将被编码为intset结构。整数集合是一个有序的、存储整型数据的结构,可以保存大范围的整型数据,并保证集合中不会有重复数据。Sorted Set
Sorted Set是一种有序集合,连续空间存储数据,每次增加数据都会对全量数据进行搬运。对于有序链表查找指定元素,只能通过头、尾节点遍历方式进行查找。如果将每个数据增加不定层数的索引,索引之间相互关联,就可以通过遍历层级的索引来确定元素所处范围,减少空间复杂度。跳跃表是一种可以对有序链表进行近似二分查找的数据结构,Redis在两个地方使用了跳跃表,一个是实现有序集合,另一个是在集群节点中用作内部数据结构。 ZSet数据结构底层实现为字典(dict) + 跳跃表(skiplist)。跳跃表通过在每个节点中维持多个指向其他节点的指针,实现快速访问节点的目的。它支持平均O(logN)、最坏O(N)复杂度的节点查找,并且还可以通过顺序性操作来批量处理节点。数据量较少时,使用ziplist编码结构存储;数据量较多或有序集合中元素是较长字符串时,Redis使用跳跃表作为有序集合键的底层实现。 配置如下:元素个数超过时,用skiplist编码。
单个元素大小超过字节时,用skiplist编码。
总结
Redis提供了多种数据结构,包括List、Hash、Set和Sorted Set。这些数据结构在不同的应用场景中具有独特的优点,能够高效地处理不同类型的数据操作。通过合理选择和配置存储结构,可以优化Redis的性能,满足各种业务场景的需求。 京东云开发者社区提供了丰富的学习资源和交流平台,欢迎开发者们积极参与学习和讨论,共同提升技术水平。更多关于Redis数据结构的知识和实践,可以参考相关文档和社区讨论。Redis 源码分析字典(dict)
Redis 的内部字典世界:从哈希表到高效管理的深度解析
Redis,作为开源的高性能键值存储系统,其内部实现的字典数据结构是其核心组件之一。这个数据结构采用自定义的哈希表——dictEntry,巧妙地存储和管理着键值对。让我们一起深入理解这一强大工具的运作机制。
首先,Redis的字典是基于哈希表的,通过哈希函数将键转换为数组索引,实现高效查找。dictEntry结构巧妙地封装了键(key)、值(value)以及指向下一个节点的指针,构成了数据存储的基本单元。同时,dict包含一系列操作函数,包括哈希计算、键值复制、比较以及销毁操作,这些函数的指针类型(dictType)和实际数据结构共同构建了其高效性能。
在字典的管理中,rehash是一个关键概念,它标志着哈希表的重新分布过程。rehash标志是一个计数器,用于跟踪当前哈希表实例的状态,确保在负载过高时进行扩容。当ht_used[0]非零,且满足特定条件(如元素数量超过初始桶数),服务器会触发resize操作,这通常在serverCron定时任务中进行,以避免磁盘I/O竞争。
rehash过程中,Redis采取渐进式策略,通过dictRehash函数,逐个移动键值对到新哈希表,确保操作的线程安全。为了避免长时间阻塞,这个过程被分散到函数中,并通过serverCron定时任务,以毫秒级的步长进行,确保在无磁盘写操作时进行。
在处理过期键时,dictRehashMilliseconds()函数扮演重要角色,它在rehash时监控时间消耗,确保性能。rehash过程中,dictAdd负责插入新哈希表,而dictFind和dictDelete则需处理ht_table[0]和ht_table[1]的键值对。
Redis的默认哈希算法采用SipHash,保证了数据的分布均匀性。在持久化时,负载因子默认设置为5,而rehash后,数据结构会采用迭代器的形式,分为安全和非安全两种,以满足不同场景的需求。
在实际操作中,如keysCommand,会选择安全模式以避免重复遍历,而在处理大规模数据时,如scan命令,可能需要使用非安全模式,但需注意可能带来的问题。
总的来说,Redis的字典数据结构是其高效性能的基石,通过精细的哈希管理、rehash策略以及迭代器设计,确保了在高并发和频繁操作下的稳定性和性能。深入理解这些内部细节,对于优化Redis性能和应对复杂应用场景至关重要。
Redis教程——数据类型(基数统计、地理空间、位域)
Redis教程——数据类型详解
在前文介绍了Redis的数据类型(有序集合和位图)后,本文继续探讨基数统计、地理空间和位域等重要数据类型。基数统计:HyperLogLog
HyperLogLog是一种高效的基数统计算法,当处理大量元素时,使用KB内存即可处理接近2^个不同元素。它专注于基数计算,而非元素存储,因此无法返回每个元素,只能统计去重后的数量,常用于统计IP访问、搜索关键词和用户搜索词条。基本操作
使用pfadd命令创建基数统计类型,例如:pfadd key value...
通过pfmerge合并数据:pfmerge destination key...
地理空间:GEO
GEO类型用于存储地理位置信息,支持添加、获取和计算距离等操作。如:geoadd key longitude latitude name...
获取地理位置
利用zrange命令(需开启raw模式)获取元素:zrange key [start] [end] WITHSCORES
位域:bitfield
bitfield命令支持对连续位进行操作,如获取字节:bitfield key command
修改和增删位:set key offset value
incrby key offset increment
溢出控制有多种方式:bitfield key command [flags]
总结
本期介绍了Redis的基数统计、地理空间和位域功能,下一节将转向流数据类型的学习。关注公众号“白巧克力LIN”,获取更多Python、数据库等技术文章更新。Redis的数据类型-Stream
接上一版: Redis的数据类型-Stream
3)范围查发现:XRANGE命令
功能:返回流中满足给定ID范围的条目。范围由最小和最大ID指定。所有ID在指定的两个ID之间或与其中一个ID相等(闭合区间)的条目将会被返回。XRANGE命令的反转版本是XREVRANGE。
语法:XRANGE key start end [COUNT count]
返回值:key :队列名;start :开始值,-表示最小值;end :结束值, +表示最大值;count :数量。
4)消息长度:XLEN命令
功能:返回Stream中的条目数。如果指定的键不存在,则返回0。注意,0长度流是可能的,因此需调用TYPE或EXISTS来检查键是否存在。
一旦流内部没有条目(例如在XDEL调用之后),流不会自动删除,因为流可能具有与之关联的使用者组。
5)删除:XDEL命令
功能:从流中删除指定的条目,并返回已删除的条目数。在流中不存在某些指定ID的情况下,返回的数字可能小于传递给命令的ID数。删除操作有助于遵守隐私政策。
Redis流的内存效率体现在使用基数树来索引宏节点,通常情况下,删除条目后,流不会立即回收内存,而是标记该条目为已删除。只有当宏节点中的所有条目都被标记为已删除时,才会销毁节点和回收内存。
四、消费者命令
1)创建消费组:XGROUP CREATE命令
功能:创建一个具有唯一标识符的新使用者组,该组用于存储在流中的数据。给定的流中有唯一的组名称。如果已有相同名称的使用者组存在,命令将返回错误。
语法:XGROUP CREATE key group [MKSTREAM][ENTRIESREAD entries-read]
2)读取队列的消息:XREADGROUP命令
功能:从指定的消费者组读取消息。无需预先创建消费者。
语法:XREADGROUP GROUP group consumer [COUNT count][BLOCK milliseconds][NOACK] STREAMS key [key ...] id [id ...]
3)记录未确认的消息:XPENDING命令
功能:跟踪挂起消息列表,以解决消息丢失问题。允许检查组内消息状态、待消费消息数量和消息空闲时间。
语法:XPENDING key group [[IDLE min-idle-time] start end count [consumer]]
4)通知确认:XACK命令
功能:确认已处理的消息,一旦消息被XACK确认,表示消息已处理完毕。
语法:XACK key group id [id ...]
5)消息转移:XCLAIM命令
功能:转移未处理消息的所有权。当消费者失败时,其他消费者可以使用XCLAIM来获取所有权,继续处理消息。
语法:XCLAIM key group consumer min-idle-time id [id ...][IDLE ms][TIME unix-time-milliseconds][RETRYCOUNT count][FORCE][JUSTID][LASTID lastid]
6)查看流和消费者组信息:XINFO命令
功能:提供流和消费者组的相关信息,用于调试和管理。
语法:XINFO key [GROUP group] [CONSUMER consumer] [STREAM stream]
返回值:视命令执行的不同,返回流和消费者组的详细信息。