引言
Redis是一个高性能的开源内存数据库,以其快速的读写速度和丰富的数据结构支持而闻名。作为一个轻量级、灵活的键值存储系统,Redis在各种应用场景下都展现出了惊人的性能优势。无论是作为缓存工具、会话管理组件、消息传递媒介,还是在实时数据处理任务和复杂的分布式系统架构中,Redis均扮演了至关重要的角色。而Redis为什么快的原因也是我们尝尝遇见的高频面试问题。接下来我们就一起探讨一下Redis快的原因。
本文将深入探讨Redis之所以快速处理大规模数据的原因。我们将从Redis基于内存操作的特性、高效的内存数据结构、单线程模型、I/O多路复用技术、底层模型和优化技术、持久化机制以及网络通信协议等多个方面进行分析和讨论。通过深入了解Redis内部机制和性能优化技术,我们可以更好地理解Redis之所以快速的根本原因,以及如何在实际应用中充分发挥其优势。
image.png
完全基于内存
Redis作为一种内存导向型数据库系统,其关键特性在于将所有数据实体,包括键值对及其相关的复杂数据结构,完全寄宿于内存之中。相较于依赖磁盘存储的传统数据库系统,Redis巧妙地运用内存的高速读写特性,显著提升了系统的响应速率与整体性能表现。
内存相对于磁盘具备无可比拟的读写速度优势,使得Redis能够即时、高效地处理数据存取。在读取操作层面,Redis无需经过耗时的磁盘I/O过程,只需在内存空间内迅速定位所需数据,从而显著降低了访问延迟;而在写入操作时,Redis同样直接作用于内存区域,新数据能即刻生效,仅在执行持久化策略时,例如RDB快照或AOF日志记录,数据才会被异步地或按需地同步至磁盘,以确保即使在系统重启后数据仍能得以恢复,但此过程并不会妨碍Redis在常规操作中维持其卓越的性能表现。
说到这,我们就会想到,一台服务器的内存不是无限的,相反的是比较紧张的,Redis基于内存操作,那么Redis究竟是如何在有限内存空间中进行精细且高效的内存管理呢?
过期键删除
Redis支持为键设置过期时间(TTL),并且在键过期后会通过两种方式自动删除它们:
这两种方式结合起来,可以有效地管理和清理过期键,保证Redis的内存使用在合理范围内。同时,我们在日常开发中可以根据具体业务场景和需求调整过期策略的配置,以达到最佳的性能和内存利用率。
内存淘汰策略
内存淘汰策略是Redis用于释放内存空间的一种机制,当内存空间不足时(达到或超过了配置的maxmemory),Redis会根据预先设置的淘汰策略来选择要删除的键,从而释放内存空间。通过合理选择和配置内存淘汰策略,可以有效地管理内存使用,防止内存溢出,并保证系统的稳定性和性能。
常见的内存淘汰策略:
当Redis的内存使用达到配置的maxmemory限制时,就会触发内存淘汰策略,以释放内存空间。合理选择内存淘汰策略,并根据系统的需求设置maxmemory参数,可以有效地管理内存使用,保证系统的稳定性和性能。通过合理配置内存限制和内存淘汰策略,可以有效地管理Redis的内存使用,保证系统在内存空间不足时能够及时释放内存,避免因内存溢出而导致系统性能下降或者崩溃。
修改内存
maxmemory只需要在redis.conf配置文件中配置maxmemory-policy参数即可。
内存碎片管理
内存碎片整理是指对Redis中的内存空间进行重新排列和整理,以减少内存碎片的数量和大小。内存碎片是指已分配但不再使用的内存块,这些内存块虽然被标记为已分配,但实际上并未被有效利用,造成了内存的浪费。
在Redis中,由于数据的增删改查操作不断进行,会导致内存空间中出现大量的内存碎片。这些内存碎片虽然单个很小,但如果积累起来会导致内存碎片化,降低内存利用率,影响系统的性能和稳定性。
为了解决内存碎片化的问题,Redis会定期进行内存碎片整理操作。内存碎片整理过程包括以下几个步骤:
通过定期进行内存碎片整理操作,Redis可以保持内存空间的连续性,减少内存碎片化的程度,提高内存利用率,从而提高系统的性能和稳定性。但是,内存碎片整理过程可能会消耗一定的系统资源,尤其是在内存碎片较多的情况下。所以,通常情况下,Redis会选择在系统负载较低的时候进行碎片整理操作,以避免对系统性能产生不利影响。
高效的内存数据结构
Redis作为一个内存数据库系统,提供了丰富且高效的内存数据结构,包括字符串(String)、列表(List)、集合(Set)、有序集合(Sorted Set)、哈希(Hash)等。这些数据结构不仅具有简单易用的特点,还能够在内存中高效地存储和操作数据,为Redis的快速性能提供了坚实的基础。
image.png
动态字符串
动态字符串是一种能够动态扩展长度的字符串实现方式。在许多编程语言和数据结构中都有类似的实现,如C语言中的动态数组(dynamic array)。而SDS是Redis中的一种简单动态字符串结构,它是一种动态大小的字节数组,用于存储和操作字符串数据。SDS是Redis内部数据结构的基础,也是字符串数据结构的底层实现。它的结构如下:
/*
* redis中保存字符串对象的结构
*/
struct sdshdr {
//用于记录buf数组中使用的字节的数目,和SDS存储的字符串的长度相等
int len;
//用于记录buf数组中没有使用的字节的数目
int free;
//字节数组,用于储存字符串
char buf[]; //buf的大小等于len+free+1,其中多余的1个字节是用来存储’ ’的
};
在C语言中传统字符串是使用长度为N+1的字符数组来表示长度为 的字符串,并且字符串数组的最后一个元素总是空字符' '。
image.png
如果我们想要获取上述CODERACADEMY的长度,我们需要从头开始遍历,直到遇到 ‘