目录
IO大文件分批读取
DMA是什么
- DMA是直接存储器访问。
- DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储 器之间的高速数据传输。
- CPU无时无刻不在处理着很多的事情,但是有些事情却没有那么重要,比方说数据的复制和存储数据, 如果把这部分的CPU资源拿出来,然后让CPU去处理其它复杂的计算事务,从而能够更好的利用CPU 的资源。
- 因此转移数据,尤其是转移大量的数据,是可以不需要CPU的参与。比如希望外设A的数据拷贝到外 设B,只需要给两种外设提供一条数据通道,直接让数据由A拷贝到B然后不经过CPU的处理。
- DMA就是基于以上思想设计的,它的作用就是解决了大量数据的转移,过度消耗CPU的资源问题。
- 有了DMA可以使CPU去做更加实用的操作。
IO是什么
- IO就是输入和输出,也可以理解为读和写,针对不同的对象,IO模式可以划分为磁盘IO模型和网络 IO模型。
- IO操作会涉及到用户空间和内核空间的转换:
- 内存空间分为用户空间和内核空间,也称为用户缓冲区和内核缓冲区。
- 用户的应用程序不能直接操作内核空间,需要将数据从内核空间拷贝到用户空间才能使用。
- 无论是Read操作,还是Write操作,都只能在内核空间里执行。
- 不管是磁盘IO还是网络IO,请求加载到内存的数据都是先放在内核空间里面的。
- Read/Write操作:
- 读操作是指操作系统检查内核缓冲区有没有需要的数据,如果内核缓冲区已经有需要的数据了, 那么就直接把内核空间的数据Copy到用户空间,给用户的应用程序使用。如果内核缓冲区没有 需要的数据,对于磁盘IO,直接从磁盘中读取到内核缓冲区,这个过程可以不需要CPU的参与。 而对于网络IO,应用程序需要等待客户端发送数据,如果客户端还没有发送数据,对应的应用 程序将会被阻塞,直到客户端发送了数据,该应用程序才会被唤醒。
- 写操作是指用户的应用程序将数据从用户空间Copy到内核空间的缓冲区中,如果用户空间没有 相应的数据,则需要从磁盘—>内核缓冲区—>用户缓冲区依次读取,这时对于用户程序来说写 操作就已经完成了,至于什么时候再写到磁盘或者通过网络发送出去,由操作系统决定。除非 应用程序显示的调用了flush命令,立即把数据写入到磁盘。
磁盘IO
- 读操作是指当应用程序调用Read方法时,操作系统检查内核缓冲区中是否存在需要的数据,如果存在, 那么就直接把内核空间的数据Copy到用户空间,给用户的应用程序使用。如果内核缓冲区没有需要的 数据,通过DMA的方式从磁盘中读取数据到内核缓冲区,然后由CPU控制,把内核空间的数据Copy 到用户空间。这个过程会涉及到两次缓冲区Copy,第一次是从磁盘的缓冲区到内核缓冲区,第二次是 从内核缓冲区到用户缓冲区,第一次是CPU的Copy,第二次是DMA的Copy。
- 写操作是指当应用程序调用Write方法时,应用程序将数据从用户空间Copy到内核空间的缓冲区中, 如果用户空间没有相应的数据,则需要从磁盘—>内核缓冲区—>用户缓冲区依次读取,这时对用户程 序来说写操作就已经完成了,至于什么时候把数据再写到磁盘,由操作系统决定。除非应用程序显示 的调用了flush命令,立即把数据写入到磁盘。如果应用程序没准备好写的数据,则必须先从磁盘中读 取数据才能执行写操作,这时会涉及到四次缓冲区的Copy,第一次是从磁盘的缓冲区到内核缓冲区, 第二次是从内核缓冲区到用户缓冲区,第三次是从用户缓冲区到内核缓冲区,第四次是从内核缓冲区 回写到磁盘。前两次是为了读,后两次是为了写。这其中有两次CPU拷贝,两次DMA Copy。
- 磁盘IO的延迟:磁盘为了读或者写,磁头必须能移动到所指定的磁道上,并等待所指定的扇区开始位 置旋转到磁头下,然后再开始读或者写。
- 磁盘IO的延迟分为以下三部分:
- 寻道时间:把磁头移动到指定磁道上所经历的时间。
- 旋转延迟时间:指定扇区移动到磁头下面所经历的时间。
- 传输时间:数据的传输时间,也就是数据读出或者写入的时间。
网络IO
- 读操作是指网络的IO既可以从物理磁盘中读取数据,也可以从Socket中读取数据(从网卡中获取)。 当从物理磁盘中读取数据的时候,其流程和磁盘IO的读操作是一样的。当从Socket中读取数据的时候, 应用程序需要等待客户端发送数据,如果客户端还没有发送数据,对应的应用程序将会被阻塞,直到 客户端发送了数据,该应用程序才会被唤醒,从Socket中读取客户端发送的数据到内核空间,这个过 程也由DMA控制,然后把内核空间的数据Copy到用户空间,给应用程序使用。
- 写操作:
- 当应用程序调用Read方法时,通过DMA的方式将数据从磁盘拷贝到内核缓冲区。
- 当由CPU控制时,将内核缓冲区中的数据拷贝到用户缓冲区中,给应用程序使用。
- 当应用程序调用Write方法时,CPU会把用户缓冲区中的数据拷贝到内核缓冲区中的Socket Buffer中。
- 最后通过DMA的方式将内核空间中的Socket Buffer拷贝到Socket协议栈(即网卡设备)中进行 数据传输。
- 网络IO的写操作也有四次缓冲区的Copy,第一次是从磁盘缓冲区到内核缓冲区(由CPU控制),第 二次是从内核缓冲区到用户缓冲区(DMA控制),第三次是从用户缓冲区到内核缓冲区中的Socket Buffer(由CPU控制),第四次是从内核缓冲区中的Socket Buffer到网卡设备(由DMA控制)。四次 缓冲区的Copy工作有两次是由CPU控制,其它的两次是由DMA控制。
- 网络IO的主要延迟是由服务器的响应延迟+带宽限制+网络延迟+跳转路由延迟+本地接收延迟共同决定 的。一般为几十到几千毫秒,受环境的影响较大。所以,一般来说,网络IO的延迟要大于磁盘IO的 延迟。
IO多路复用
什么是IO多路复用
- 多路大部分情况下是指多个TCP连接,也就是多个Socket或者多个Channel。
- 复用是指复用一个或多个线程资源。
- IO多路复用就是说,用一个或者多个线程处理多个TCP连接,尽可能减少系统的开销,无需创建和维 护过多的线程。
IO多路复用的模型
Select
- Select模型的基本原理是采用轮询和遍历的方式。在客户端操作服务器时,会创建三种文件描述符,简 称FD。分别是writefds(写描述符),readfds(读描述符)和except fds(异常描述符)。
- Select模型会阻塞监视这三种文件描述符,等有数据,可读,可写,出异常或超时都会返回结果。
- 返回结果后通过遍历fdset,也就是文件描述符的集合,来找到就绪的FD,然后触发相应的IO操作。
- 由于Select模型是采用轮询的方式进行全盘扫描,因此,随着FD数量增多会导致性能下降。
- 每次调用Select函数,都需要把FD集合从用户态拷贝到内核态,并进行遍历。而操作系统对单个进程 打开的FD数量是有限制的,一般默认是1024个。可以通过操作系统的宏定义FD_SETSIZE修改最大FD 数量限制,但是,在IO吞吐量巨大的情况下,效率提示仍然有限。
Poll
- poll模型的原理与select模型基本一致,也是采用轮询和遍历,唯一的区别就是poll模型采用的 是链表的方式来存储FD。
- 它的优点是没有最大的FD数量限制。
- 它的缺点和Select模型一样,也是采用轮询方式全盘扫描,同样也会随着FD数量增多而导致性能下 降。
Epoll
- 由于Select模型和Poll模型都会因为吞吐量的增加而导致性能下降,因此,才出现了Epoll模型。
- Epoll模型是采用时间通知机制来触发相关的IO操作。它没有FD的个数限制,而且从用户态拷贝到 内核态只需要一次。
- 它主要通过系统底层函数来注册,激活FD,从而触发相关的IO操作,大大提高了性能。
- 主要调用了以下三个系统函数:
- epoll_create函数,在系统启动时,会在Linux内核里面申请一个B+树结构的文件系统,然 后,返回Epoll对象。
- epoll_ctl函数,每新建一个连接的时候,会同步更新Epoll对象中的FD,并且绑定一个callback 回调函数。
- epoll_wait函数,轮询所有的callback集合,并触发对应的IO操作。
- Epoll模型最大的优点是将轮询改成了回调,大大提高了CPU的执行效率,也不会随着FD的数量增加 而导致效率下降。当然,它也没有FD的数量限制,也就是说,它能支持的FD上限是操作系统最大的 文件句柄数。一般而言,1G内存大概支持 10 万个句柄。分布式系统中常用的组件如Redis,Nginx 都是优先采用Epoll模型。
- 缺点是只能在Linux上面工作。