面试:Redis为什么这么快?

Redis作为高性能的内存数据存储,其速度得益于完全基于内存的读写、单线程模型以避免并发控制开销,以及使用I/O多路复用技术提高并发能力。它采用动态字符串、zipList、quicklist、skipList和intset等高效数据结构,并通过渐进式rehash解决哈希冲突,确保快速响应。此外,Redis还利用预分配空间和惰性释放策略优化内存管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

官方数据QPS(每秒请求数量)可达到10万

1.完全基于内存

        不论读写都是在内存中完成,吊打磁盘读写,直接由CPU控制和内存对接。

2.单线程模型

        网络IO(6以后也使用多线程)和键值对指令读写是由一个线程来执行。

        持久化,数据同步,异步删除是用其他线程执行的

        为什么不使用多线程来充分利用cpu

                1.多线程需要不停的并发读写,这是特别消耗资源的

                2.如果并发读写的话,就需要保护共享资源

        好处:

                不用因为创建线程导致性能消耗

                避免上下文切换引起CPU消耗,没有多线程切换的开销

                避免了线程之间的竞争问题,比如添加锁,释放锁,死锁等 ,不需要考虑锁的问题

                代码更清晰,逻辑更简单

3.IO多路复用

        

        Redis 采用 I/O 多路复用技术,并发处理连接。采用了 epoll + 自己实现的简单的事件框架。

        epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 IO 上浪费一点时间。

        Redis 线程不会阻塞在某一个特定的监听或已连接套接字上,也就是说,不会阻塞在某一个特定的客户端请求处理上。正因为此,Redis 可以同时和多个客户端连接并处理请求,从而提升并发性。

相关参考链接:

(55条消息) io多路复用的原理和实现_彻底理解 IO 多路复用实现机制_weixin_39934085的博客-优快云博客

4.底层高效的数据结构

        Redis 一共有 5 种数据类型,String、List、Hash、Set、SortedSet

不同的数据类型,底层用一种或多种不同的数据结构支撑。

动态字符串(String):

        空间预分配:不仅会分配所需要的必须空间,还会额外分配未使用空间

        惰性空间释放:SDS缩短,不回收多余的内存空间,直接用free字段记录下来,后续append

直接使用,不用在分配。

zipList(List,Hash,SortedSet):

        只有少量数据,要么是长度比较短的字符串,内存紧凑节省空间

quicklist(List,Hash,SortedSet)

        后续版本对linkedList和ziplist改造,quicklist代替了ziplist和linkedlist,将linkedlist按段儿拆分,每一段用ziplist来紧凑,多个list使用双向指针连链接。

skipList(sortSet)

        sortSet类型的排序功能就是通过跳表来实现的

        跳表是一种有序的数据结构,每个节点中维持多个指向其他节点的指针

        增加多层级索引,通过多次跳转来快速定位数据位置 

整型数组(intset)

        当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现,节省内存。

5.Redis 全局 hash 字典

        Redis 整体就是一个 哈希表来保存所有的键值对,无论数据类型是 5 种的任意一种。哈希表,本质就是一个数组,每个元素被叫做哈希桶,不管什么数据类型,每个桶里面的 entry 保存着实际具体值的指针。

        

而哈希表的时间复杂度是 O(1),只需要计算每个键的哈希值,便知道对应的哈希桶位置,定位桶里面的 entry 找到对应数据,这个也是 Redis 快的原因之一。

 hash冲突怎么办?

        Redis 通过链式哈希解决冲突:也就是同一个 桶里面的元素使用链表保存。但是当链表过长就会导致查找性能变差可能,所以 Redis 为了追求快,使用了两个全局哈希表。用于 rehash 操作,增加现有的哈希桶数量,减少哈希冲突。

开始默认使用 「hash 表 1 」保存键值对数据,「hash 表 2」 此刻没有分配空间。当数据越来越多触发 rehash 操作,则执行以下操作:

  1. 给 「hash 表 2 」分配更大的空间;
  2. 将 「hash 表 1 」的数据重新映射拷贝到 「hash 表 2」 中;
  3. 释放 「hash 表 1」 的空间。

值得注意的是,将 hash 表 1 的数据重新映射到 hash 表 2 的过程中并不是一次性的,这样会造成 Redis 阻塞,无法提供服务。

而是采用了渐进式 rehash,每次处理客户端请求的时候,先从「 hash 表 1」 中第一个索引开始,将这个位置的 所有数据拷贝到 「hash 表 2」 中,就这样将 rehash 分散到多次请求过程中,避免耗时阻塞。

<think>好的,我现在需要帮助用户了解Redis的底层原理,特别是线程模型。用户提到了单线程、多线程、实现机制,以及可能用于面试的情况。首先,我应该回顾已有的引用内容,确保回答准确。 首先,引用[1]提到Redis是单线程还是多线程的问题,区分了6.0前后的不同。引用[2]详细解释了单线程模型的原理和优势,以及为何后来引入多线程。引用[3]和[4]则说明网络I/O是多线程化的原因,瓶颈在内存和网络,而不是CPU。 用户的问题主要集中在Redis的线程模型,所以需要分阶段说明。首先介绍单线程模型,包括其工作原理、优点(如避免上下文切换、原子性操作),然后转向多线程的变化,特别是6.0之后如何处理网络I/O。需要解释为什么单线程效率高,如内存操作、IO多路复用、避免竞争等。 可能需要注意面试中常见的问题,比如为什么单线程还为什么引入多线程,多线程是否安全。需要结合引用内容中的点,如网络I/O是瓶颈,多线程处理读写,但命令执行仍单线程保证安全。 还要确保回答结构清晰,分点说明,使用中文,符合用户要求。同时生成相关问题,帮助用户深入理解。例如,单线程的优缺点,多线程的具体实现,如何保证线程安全等。 最后,检查LaTeX格式是否正确,行内公式用$...$,独立公式用$$...$$。不过问题中可能数学公式较少,但如果有的话需要注意。比如提到性能分析时,可能需要公式,但根据引用内容,可能不需要。所以重点放在结构化和准确的信息传递上。</think>### Redis线程模型底层原理解析 #### 一、单线程模型(Redis 6.0之前) 1. **核心机制** Redis 6.0 之前采用**单线程事件循环模型**,通过 **I/O 多路复用**(如 `epoll`、`kqueue`)处理客户端请求。所有操作(包括命令解析、执行、响应)均在主线程中**串行执行**,且所有数据操作基于内存完成[^2][^4]。 2. **单线程的优势** - **避免上下文切换**:单线程无需处理多线程的上下文切换开销,提升 CPU 利用率[^2][^4]。 - **原子性保障**:所有操作天然原子性,无需锁竞争[^2]。 - **简化设计**:代码复杂度低,调试和维护成本小。 3. **高性能的关键** - **纯内存操作**:数据存储在内存中,读写速度极。 - **非阻塞 I/O 多路复用**:单线程同时监听多个客户端连接,高效处理并发请求[^2][^4]。 - **高效数据结构**:如哈希表、跳表等优化时间复杂度[^2]。 ```c // 简化的单线程事件循环伪代码 while (true) { events = epoll_wait(); // 监听网络事件 for (event in events) { if (event.type == READ) { read_data(event.fd); // 读取请求 parse_command(); // 解析命令 execute_command(); // 执行命令 } else if (event.type == WRITE) { send_response(event.fd); // 返回响应 } } } ``` --- #### 二、多线程模型(Redis 6.0之后) 1. **改进背景** 随着网络带宽提升,**网络 I/O 成为瓶颈**(占 80% 以上 CPU 时间)。Redis 6.0 引入多线程**仅用于网络 I/O**,命令执行仍保持单线程[^3]。 2. **多线程实现细节** - **网络读/写多线程化**:由后台线程并行处理数据读取(`read()`)和响应发送(`write()`)。 - **命令执行单线程化**:解析后的命令仍由主线程串行执行,确保原子性[^3]。 3. **性能提升效果** 多线程模式在高并发场景下可提升吞吐量 2-3 倍,但对延迟敏感场景影响较小[^4]。 --- #### 三、关键面试问题解析 1. **为什么单线程还能高效?** - 内存操作速度,I/O 多路复用减少等待时间,单线程避免锁竞争[^2][^4]。 2. **多线程是否线程安全?** - 是。命令执行仍由主线程完成,网络 I/O 线程仅处理数据读写,不涉及业务逻辑[^3]。 3. **Redis 6.0 多线程的局限性** - **CPU 非瓶颈**:若业务以简单命令为主,多线程提升有限[^4]。 - **配置需谨慎**:需通过 `io-threads` 参数调整线程数,默认关闭[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值