主题切换
Redis单线程高性能 + IO多路复用
一、Redis单线程速度快的核心原因
纯内存操作 数据全部驻留内存,避开低速磁盘IO,内存读写为纳秒级,性能瓶颈主要在网络传输。
单线程架构 无需处理多线程上下文切换、锁竞争与线程安全问题,CPU资源全部用于业务数据处理。
IO多路复用(epoll)非阻塞网络模型 单线程可同时监听大量客户端Socket,无空闲轮询空转,高效支撑海量并发连接。
二、Linux用户空间&内核空间
- 用户空间(Ring3):应用程序运行区域,无硬件操作权限,不能直接操作网卡、磁盘等硬件。
- 内核空间(Ring0):操作系统内核区域,拥有硬件操作特权,统一管理各类硬件设备。
- IO数据流转规则 读数据:硬件 → 内核缓冲区 → 用户缓冲区 写数据:用户缓冲区 → 内核缓冲区 → 硬件 所有IO操作都必须经过内核中转。
三、Linux四种IO模型对比
1. 阻塞IO Blocking IO
两个阶段全程阻塞: ① 等待数据到达内核缓冲区,进程挂起等待网络数据; ② 内核将数据拷贝至用户空间,进程继续阻塞。 缺点:单线程仅能处理一个连接,并发能力极低。
2. 非阻塞IO Non-Blocking IO
阶段一:无数据则直接返回错误码,进程持续轮询请求数据,造成CPU空转浪费; 阶段二:数据就绪后,内核拷贝数据阶段进程依旧阻塞。 缺点:频繁发起系统调用,CPU占用率高,不适合高并发场景。
3. IO多路复用(Redis采用epoll实现)
定义:单个线程监听一批Socket,任一Socket数据就绪后主动通知进程,杜绝无效轮询。
执行阶段 阶段1:进程调用
select/poll/epoll阻塞等待,内核监听批量Socket,有连接就绪则立即返回; 阶段2:遍历就绪Socket,调用recvfrom完成内核数据到用户空间的拷贝。select/poll/epoll 区别
实现 特点 select/poll 仅告知有连接就绪,不指定具体fd,用户需遍历全部Socket epoll(Redis默认) 直接返回就绪的Socket,无需全量遍历,海量连接下性能最优
四、Redis网络事件模型
1. 三大事件处理器
- 连接应答处理器(tcpAcceptHandler):监听服务端口,接收客户端TCP连接。
- 命令请求处理器(readQueryFromClient):读取客户端指令;Redis 6.0使用多线程做命令解析,命令执行依旧单线程串行。
- 命令回复处理器(sendReplyToClient):将执行结果返回客户端,Redis6及以上版本采用多线程异步回包。
2. 整体流程
客户端Socket → epoll事件监听 → 事件分发 → 三类处理器分工处理 → 执行结果写入缓冲区 → 多线程回包
五、面试简答总结
- Redis高性能三大原因:数据全存内存、单线程规避线程切换与锁开销、基于epoll的IO多路复用支撑高并发网络读写。
- IO多路复用:单线程监听海量Socket,仅在连接就绪时进行处理;epoll可精准定位就绪文件描述符,CPU利用率极高。
六、面试高频问题解析
问:为什么Redis单线程也能做到高性能?
答: 第一,数据全程存内存,读写速度极快;第二,单线程避免了多线程上下文切换、锁竞争等开销;第三,采用epoll IO多路复用模型,单线程可高效处理海量并发连接。
问:简单介绍IO多路复用以及epoll的优势?
答: IO多路复用指单线程同时监听多个网络连接,有数据就绪再处理。epoll相比select、poll,能够直接返回就绪的连接,不需要全量遍历,在海量连接场景下性能优势明显。
问:Redis6之后线程模型有什么变化?
答: Redis6引入多线程,命令解析、结果回包使用多线程处理,但核心命令执行逻辑仍然是单线程串行执行,保证线程安全。
问:简述阻塞IO和非阻塞IO的弊端?
答: 阻塞IO全程等待,单线程只能处理一个连接,并发差;非阻塞IO需要不断轮询,造成CPU空转、占用过高。