高性能IO底层原理
IO读写的基础原理
? 用户程序进行IO的读写,依赖于底层的IO读写。都会用到read&write两大系统调用,不通操作系统中,IO读写系统调用的名称可能不完全相同,功能基本一致。在用户程序中,无论是Socket的IO还是文件IO操作都属于上层应用开发。
? read系统调用:并不是直接从物理设备把数据读取到内存中,是把数据从内核缓冲区复制到进程缓冲区
? write系统调用:也不是直接把数据写入到物理设备,是把数据从进程缓冲区复制到内核缓冲区
即上层应用无论是调用操作系统的read还是调用操作系统的write,都会涉及到缓冲区。 上层应用的IO操作,实际上不是物理设备级别的读写,而是缓存的复制。 read&write两大系统调用,都不负责数据在内核缓冲区和磁盘之间的交换。底层的读写交换是由操作系统内核来完成的。
内核缓冲区与进程缓冲区
? 缓冲区的目的是为了减少频繁与设备之间的物理交换。设备的直接读写,涉及操作系统的中断。 当发生系统中断时,需要保存之前的进程数据和状态等信息,而结束中断之后,还需要恢复之前的进程数据和状态等信息。为了减少这种底层系统的时间损耗,性能损耗,就出行了内存缓冲区。
? 有了内存缓冲区后,上层应用使用read系统调用时,仅仅是把数据从内核缓冲区复制到上层应用的缓冲区(进程缓冲区);上层应用使用write系统调用时,只需要把数据从进程缓冲区复制到内核缓冲区。底层操作会对内核缓冲区进行监控,等待缓冲区达到一定数量时,再进行IO设备的中断处理,集中执行物理设备的实际IO操作,这种机制提示了系统的性能。以至于什么时候中断(读中断,写中断),由操作系统的内核决定,用户程序不需要关心。
? 从数量上来说,Linux系统中,操作系统内核只有一个内核缓冲区。 每个用户程序(进程),有自己的缓冲区,叫做进程缓冲区。 所以用户程序的IO读写程序,在大多数情况下,没有进行实际的IO操作,而是在进程缓冲区和内核缓冲区直接之间进行的数据交换。
典型的系统调用流程
? 图示 系统调用read&write流程
? 例如read系统调用的输入流程
-
等待数据就绪 -
从内核向进程复制数据。 如果read是一个socket。那么具体流程为:
? 从客户端和服务器端的角度来理解,即一次socket的请求和响应如下
- 客户端请求: linux通过网卡读取到客户端的请求数据,将数据读取到内核缓冲区
- 服务器端获取请求数据:通过read系统调用,从linux内核缓冲区读取数据,再送入Java进程缓冲区
- 服务器端业务处理:Java进程在自己的用户空间处理客户端的请求
- 服务器端返回数据:Java进程处理完成,构建好响应数据。通过write系统调用。将这些数据从用户缓存区写入内核缓冲区
- 发送至客户端:linux内核通过网络IO,将内核缓冲区中的数据写入网卡,网卡通过底层的通信协议,会将数据发送给目标客户端。
|