Redis 的 IO 多路复用,学习研究

 

基础知识

操作系统

操作系统本身可以看做一个特殊的软件,只有操作系统能直接接触计算机硬件,其他软件要访问硬件都必须通过操作系统

操作系统对硬件做抽象,封装接口给软件调用

程序员

软件

操作系统(在内存中)

IO设备(网卡、磁盘、键盘、鼠标等)

 

常见的操作系统有:
Windows、Linux、Mac

内核和用户空间

首先,内核和用户空间都在内存中

内核:

只要计算机处于开启状态,操作系统(记住它是一种特殊的软件)就会把它的程序和数据放入内存中,由于操作系统的重要性,它会独占内存中的一块区域,这块区域就称之为内核

即,内核就是操作系统常驻内存的区域

用户空间

而用户空间,就是某个进程启动后,被分配到的一块内存区域

注:

具体的涉及到虚拟地址空间的概念,想要详细了解的童鞋可以看下《深入理解计算机系统》第三版的第十章“虚拟存储器”

IO

具体到 IO,操作系统提供了一些 IO 操作,用于操作 IO 设备的数据,然后应用软件对其进行封装

数据流转:

网络IO:网卡 → 内核 → 用户空间(用户内存)

磁盘IO:磁盘 → 内核 → 用户空间(用户内存)

 

各个操作系统分别提供了哪些 IO 操作?有哪几种 IO 模型?

IO 操作:

select、poll、epoll、kqueue、evport

IO 模型:

以 Linux 为例,它有五种 IO 模型

阻塞IO模型、非阻塞IO模型、IO复用模型、信号驱动IO模型以及异步IO模型

可参考此链接中的内容,讲的很细:

Redis

Redis 是怎么对操作系统提供的 IO 操作进行封装的?

可参考:

为什么 Redis 使用了单线程 IO 多路复用?为什么那么快?

1、cpu 处理相比于 IO 可以忽略
每个客户端建立连接时,都需要服务端为其 创建 socket 套接字,建立连接
然后该客户端的每个请求都要经历以下几步:
(1)等待请求数据数据从客户端发送过来
(2)将请求数据从内核复制到用户进程的缓冲区(buffer)
(3)对请求数据进行处理(对于 redis 而言,一般就是简单的 get/set)
由于操作简单+只涉及内存,所以第(3)步的处理很简单、很快,主要时间耗在(1)步,所以,如果采用普通 BIO 模式,每个请求都要经历这几步,那么处理十万条数据,就要在(1)步花费大量的时间,这样的话,qps 一定很低。所以就采用了更高效的 IO 多路复用模式,即,将(1)步统一交给第三方(也就是操作系统,操作系统提供了 select、poll、epoll、kqueue、iocp等系统调用函数),结合 redis 的单线程,现在整个处理流程是这样的:
一下子来了一堆请求,线程将这些请求都交给操作系统去处理,让操作系统帮忙完成第(1)步,等到这些请求里的一个或多个走完了第(1)步,就将一个集合交给这个线程,并说,我这里收集到了几个走完第一步的请求,你去走(2)、(3)步吧,于是线程拿着这个集合去遍历,等遍历结束之后。又去检查操作系统那儿有没有(这个线程自己维护了一个 while 循环)走完第(1)步的请求,发现又有一些了,拿到后继续遍历进行(2)、(3)步,如此循环往复。
注:有些 IO 模式是将(1)(2)步都交给操作系统处理了,线程本身只需处理第(3)步

2、瓶颈在带宽,而不在 cpu

由于 数据存放在内存中+处理逻辑简单,导致即使是单线程,Redis 可支持的 qps 也相当大,而当 qps 相当大的时候,首先限制性能的是带宽,即不需要把 cpu 的性能挖掘出来,因为在这之前,带宽就不够用了。所以没有必要为了提高 cpu 利用率而使用多线程处理业务逻辑。

参考资料

1、

2、

3、

4、《深入理解计算机系统》第三版

原文地址:https://www.cnblogs.com/shoshana-kong/p/14072796.html