拓冰建站拓冰建站
首页 / 资讯中心 / 正文

面试官:Redis 单线程为什么还这么快?这道题答错的人真不少

先说结论。Redis 快不是因为「单线程」本身快而是三件事叠在一起数据在内存、单线程避开了上下文切换和锁竞争、IO 多路复用让一个线程扛住海量连接。前两条面试官基本不会深问。那问题来了——第三点 IO 多路复用才是真正的考点。下面把它一次讲透。一、快的三条根因第一数据在内存。这是最主要的原因。内存读写是纳秒级磁盘是毫秒级差了几个数量级。Redis 所有操作都基于内存天然就快。第二单线程反而省了开销。多线程听着快但线程数超过 CPU 核数就要上下文切换切换本身耗性能。更麻烦的是线程安全多线程共享数据就得上锁锁竞争又会把并行逼成串行。Redis 干脆单线程执行命令没有切换、没有锁简单直接。第三IO 多路复用 非阻塞 IO。这是它能用单线程扛高并发的关键也是下面要展开的重点。二、瓶颈在网络不在执行要理解第三点先建立一个判断既然命令都是内存操作执行本身就极快那 Redis 的性能瓶颈其实不是 CPU而是网络延迟。说白了慢的不是「算」是「等数据来、等数据走」。所以优化的方向不是多开线程去算而是别让线程干等网络。IO 多路复用解决的就是这件事。三、IO 效率的两个敌人讲清多路复用之前得先知道 IO 慢在哪。Linux 下进程分用户空间和内核空间用户空间权限低不能直接操作网卡、磁盘这些硬件必须借助内核空间的接口。发一条消息数据要从用户缓冲区拷到内核缓冲区再由内核写进网卡收一条消息反过来从网卡读到内核缓冲区再拷回用户缓冲区。整个过程里拖慢 IO 的有两件事无效等待内核还没收到数据用户进程只能干等。数据拷贝用户态和内核态之间来回拷拷贝期间进程也是阻塞的。后面几种 IO 模型都是在和这两件事较劲。四、三种 IO 模型阻塞、非阻塞、多路复用模型第一阶段等数据第二阶段拷数据问题阻塞 IO阻塞干等阻塞两阶段都卡一个连接卡住全卡非阻塞 IO非阻塞但轮询阻塞轮询造成 CPU 空转IO 多路复用阻塞在监听但一次管多个阻塞单线程同时管多个连接效率高阻塞 IO 最直白等数据就绪要等数据从内核拷到用户也要等两个阶段都阻塞。更糟的是它一次只能盯一个连接这个连接在等数据后面排队的连接全得跟着等。非阻塞 IO 把第一阶段变成「不停轮询」内核没数据就立刻返回进程反复问「好了没」。表面不阻塞了但本质是盲等CPU 被空转耗光性能也没起来。IO 多路复用换了个思路一个线程同时监听一堆 Socket谁就绪通知谁不用傻等也不用盲问。五、select/poll 与 epoll 的差别多路复用在 Linux 上有三种实现select、poll、epoll。前两个是一路人epoll 是升级版。打个比方。餐厅里很多桌客人要点餐select / poll像每张桌上装了个按钮全连到服务员头顶的一盏灯。任意一位按了灯就亮但服务员不知道是谁按的只能一桌一桌去问「你要点餐吗」找到为止。连接越多遍历越慢。epoll像按钮直接连到服务员面前的屏幕谁按了屏幕上直接显示「3 号桌就绪」。服务员不用遍历直接去处理。差别就在这select/poll 只告诉你「有 Socket 就绪」但不说是哪个你只能逐个翻epoll 在通知的同时把就绪的 Socket 直接交给你省掉了遍历。这也是 Redis 在高并发下依然稳的关键。六、Redis 的网络模型多路复用 事件派发Redis 的网络模型就是 IO 多路复用再叠一套自己的事件派发机制。多路复用负责监听客户端连接每一个 Socket 连接。连接上之后会有不同事件有读请求有写请求。多路复用把就绪的连接和事件捞出来派发给对应的事件处理器连接应答处理器处理客户端的连接应答。命令请求处理器接收客户端参数、转成 Redis 指令、执行、产出结果。命令回复处理器把结果响应回客户端。一句话请求进来交给多路复用做事件监听提前定义好各种处理器什么事件就派发给什么处理器。七、Redis 6.0 之后为什么又有多线程注意上面说的都是单线程模型。Redis 6.0 引入了多线程但只加在两处网络 IO 上接收网络请求、解析命令时多线程并行把客户端发来的字节流解析成 Redis 命令。响应结果输出时多线程并行把结果写回网络。命令的执行仍然是主线程串行跑线程安全、基于内存、不影响性能。真正拖慢的是「收字节」和「发字节」这两段网络 IO所以多线程只加在这里。到这里就能回答面试官了Redis 用单线程执行命令靠 IO 多路复用 事件派发扛住高并发6.0 后又把网络收发的 IO 多线程化进一步压榨网络延迟带来的损耗。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门