网络I/O原理、I/O模型及Linux监控命令

计算机I/O体系结构

I/O是计算机的输入输出,通俗一点讲是计算机数据的流动,包括CPU、内存、磁盘、网络、外设的数据流程,是针对不同主体而言的数据的输入和输出。

为了确保计算机正常工作,让数据能够在连接到计算机的CPU、内存和I/O设备之间流动,计算机提供了数据通路,这些数据通路统称为总线(BUS),为什么叫BUS呢?就像每个“乘客”都可以通过BUS到达他想去的目的地。计算机的“乘客”就是各种I/O设备,如鼠标、键盘、显示器、磁盘、网络等。

I/O设备通常包括两部分:设备控制器和设备本身,设备控制器是插在电路板上的一块芯片或一组芯片,每个I/O设备都有特定的设备控制器。大部分情形下,对这些设备的控制是非常复杂的,它的功能包括接收CPU发来的命令,并负责翻译成设备理解的电信号,以控制设备进行工作;为了匹配CPU和I/O设备之间的速度差异,控制器都会内置存储芯片,也就是缓冲区,负责缓冲设备与CPU之间传输的数据;另外,我们常说的驱动程序也是设备控制器的一部分,驱动程序实际上是内核例程(注:例程是某个系统对外提供的功能接口或服务的集合)的集合,是I/O设备响应设备控制器的编程接口,这些接口是一组规范的VFS函数集(open、read、lseek、ioctl等),而函数的实现有设备驱动程序全权负责。I/O设备与CPU之间的数据交换是通过总线,通过以上这种形式,使CPU从繁杂的设备控制事务中解脱出来。

为什么说I/O是计算机最复杂的模块呢?其实,计算机内核分为多个子系统,包括通信、I/O、进程管理、内存等,I/O体系结构不仅体现在协调CPU、进程、内存、I/O设备之间的数据传输,还包括操作系统对各个I/O动作的优化、调度,这些数据的通信过程是计算机性能关注的重点。

磁盘I/O与网络I/O

磁盘控制器是典型的设备控制器,与计算机总线相连,主要负责把数据写入磁盘和从磁盘读出数据,CPU通过总线将数据传送给磁盘控制器,再由磁盘进行处理,从而产生磁盘I/O。

网络适配器,即网卡,是计算机之间通过网络传送数据的控制器,位于OSI模型的物理层和数据链路层,简单来说,网卡是将计算机的数据封装为帧,并通过网线(对无线网络来说就是电磁波)将数据发送到网络上去;还负责接收网络上其它设备传过来的帧,并将帧重新组合成数据,发送到所在的电脑中;网卡还提供缓冲队列,负责缓冲网卡接收和发送的数据。磁盘等其他硬件设备主要是一台计算机内部的通信,而网络的数据通信,是在客户端和服务端之间进行的,具体来说就是在网络协议支持下,一个网络主机的进程通过网络与网络中其他主机的进程进行数据传输的过程,这一数据的传输过程就是网络I/O。

上一篇我们已经分析了磁盘I/O和操作系统对磁盘I/O的优化方法,从时间消耗上看,CPU和内存的I/O消耗非常少,大部分I/O时间耗费在磁盘I/O和网络I/O上,这也是大部分应用系统的瓶颈点。磁盘I/O主要的延时是由旋转延时 + 寻道延时(2~3ms) + 数据传输延时决定;而网络IO主要延时由: 服务器响应延时 + 带宽限制 + 网络延时 + 跳转路由延时 + 本地接收延时决定。可以看出,网络I/O比磁盘I/O更加复杂,受实时环境影响最大。

Socket

在操作系统中,所有的I/O设备(磁盘、外设、网络等)都被模型化为文件,所有的输入和输出动作都被当成相应的文件的读和写来执行,这些文件通过操作系统的VFS机制(虚拟文件系统),以文件系统形式挂载在Linux内核中,对外提供一致的文件操作接口,由VFS根据不同的文件类型,执行不同的操作。如操作系统的Ext3、Ext4、NTFS、FAT等文件系统,进程的所有文件操作都是通过VFS来适配不同的文件系统,完成实际的文件操作。

在网络通信中,为了适配各种网络协议的复杂性,而使操作系统能够统一操作网络中的数据,在网络与进程间增加了一个抽象层,即套接字(socket)。客户端和服务器通过使用套接字接口建立连接,连接以文件描述符形式提供给进程,套接字接口提供了打开和关闭套接字描述符的函数,客户端和服务器通过读写这些描述符来实现彼此间的通信。所以,socket是一种特殊的文件。

Linux提供了少量基于Unix I/O模型的系统级函数,有打开、关闭、读和写文件,提取文件的元数据。RIO函数是一种更加健壮、高效的I/O,可以完成更多场景的I/O操作。标准I/O函数是基于Unix I/O实现的,并提供了一组强大的高级I/O例程。大部分应用标准I/O更适合,不过对于网络应用来说,RIO和Unix I/O更适用一些。

I/O模型

I/O操作的过程可以大概总结如下:

输入:

  1. 进程向内核发起一个系统调用(read、readv、recv、recvfrom、recvmsg);
  2. 内核收到系统调用,通知I/O设备读取数据;
  3. 设备将数据载入内核缓冲区;
  4. 内核缓冲区接到数据后,复制到用户进程的缓冲区;
  5. 进程缓冲区得到数据,通知内核;
  6. 内核将控制权交给应用进程,进程继续下一步操作;

输出:

  1. 进程向内核发起一个系统调用(write、writev、send、sendto、sendmsg);
  2. 内核收到系统调用,内核将数据从应用进程的缓冲区到内核缓冲区(或设备缓冲区,如Socket缓冲区);
  3. 内核将控制权交给应用进程,由设备执行下一步操作(如磁盘将数据写到磁盘;网卡将数据通过网络发出);

操作系统对于这些I/O操作有几种特定的处理方式,也就是I/O模型,包括阻塞式I/O、非阻塞式I/O、I/O复用、信号驱动式I/O、异步I/O。

阻塞式I/O:

当进程发起一个系统调用时,到返回处理数据结果过程中,进程阻塞于这个系统调用的函数,如:调用系统的接收函数(recvfrom),从设备准备数据到系统缓冲区,到数据从内核拷贝到进程用户空间过程,进程都处于阻塞状态。

非阻塞式I/O:

非阻塞I/O与阻塞I/O不同的是,进程不会在内核准备数据过程中阻塞,而是如果内核没有准备好数据时,直接返回EWOULDBLOCK错误,然后进程一直轮询访问内核,直到内核准备好数据。

I/O复用:

I/O复用提供一种机制,可以通过新的系统调用,实现进程一次多个I/O操作,并通过监听每一个I/O操作的数据准备情况,如果某个I/O的数据准备完成,则内核会通知进程,可以进行某一个的I/O操作。操作系统提供的这种I/O复用的调用函数有select、poll、epoll。

I/O复用阻塞于select调用,等待数据报套接字变成可读,当select返回套接字可读这一条件时,我们再调用recvfrom函数,将数据从内核复制到进程缓冲区。

信号驱动式I/O:

当应用进程发起系统调用时,内核可以通过发送SIGIO信号通知进程,这一期间进程没有被阻塞,然后再有进程发起正式的函数调用,进程等待数据从内核复制到进程缓冲区,完成后进程继续进行下一步。

异步I/O:

相对于同步I/O,异步I/O在进程发出异步请求之后,无论内核是否准备好数据,系统调用都会直接返回给用户进程,内核准备好数据之后,向进程复制数据,然后发送通知给进程,由进程继续操作,整个过程都是非阻塞的。

同步和异步是内核函数的支持方式;阻塞和非阻塞主要看函数是否直接返回,直接返回进程不会阻塞,即非阻塞;不直接返回说明进程在等待数据准备,即阻塞。

Linux监控命令

ethtool用于查询和配置网卡参数的命令。

ifconfig是类UNIX系统的系统管理工具,用于诊断和配置网络接口。

前几行主要显示网卡信息,包括IP、物理地址(MAC)、广播地址、掩码等后面是网卡的数据包发送和接收情况:RX表示接收数据包的情况;TX表示发送数据包的情况;RX errors: 表示总的收包的错误数量,这包括 too-long-frames 错误,Ring Buffer 溢出错误,crc 校验错误,帧同步错误,fifo overruns 以及 missed pkg 等等RX dropped: 表示数据包已经进入了 Ring Buffer,但是由于内存不够等系统原因,导致在拷贝到内存的过程中被丢弃RX overruns: 表示了 fifo 的 overruns,这是由于 Ring Buffer(aka Driver Queue) 传输的 IO 大于 kernel 能够处理的 IO 导致的,而 Ring Buffer 则是指在发起 IRQ 请求之前的那块 buffer

netstat命令是一个监控TCP/IP网络的非常有用的工具,它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息。

从整体上看,netstat的输出结果可以分为两个部分:一个是Active Internet connections,称为有源TCP连接,其中"Recv-Q"和"Send-Q"指的是接收队列和发送队列。这些数字一般都应该是0。如果不是则表示软件包正在队列中堆积。这种情况只能在非常少的情况见到;另一个是Active UNIX domain sockets,称为有源Unix域套接口(和网络套接字一样,但是只能用于本机通信,性能可以提高一倍)。Proto显示连接使用的协议;RefCnt表示连接到本套接口上的进程号;Types显示套接口的类型;State显示套接口当前的状态;Path表示连接到套接口的其它进程使用的路径名
-a或--all:显示所有连线中的Socket;  -A<网络类型>或--<网络类型>:列出该网络类型连线中的相关地址;  -c或--continuous:持续列出网络状态;  -C或--cache:显示路由器配置的快取信息;  -e或--extend:显示网络其他相关信息;  -F或--fib:显示FIB;  -g或--groups:显示多重广播功能群组组员名单;  -h或--help:在线帮助; -i或--interfaces:显示网络界面信息表单;  -l或--listening:显示监控中的服务器的Socket;  -M或--masquerade:显示伪装的网络连线;  -n或--numeric:直接使用ip地址,而不通过域名服务器;  -N或--netlink或--symbolic:显示网络硬件外围设备的符号连接名称;  -o或--timers:显示计时器;  -p或--programs:显示正在使用Socket的程序识别码和程序名称;  -r或--route:显示Routing Table;  -s或--statistice:显示网络工作信息统计表;  -t或--tcp:显示TCP传输协议的连线状况;  -u或--udp:显示UDP传输协议的连线状况;  -v或--verbose:显示指令执行过程;  -V或--version:显示版本信息;  -w或--raw:显示RAW传输协议的连线状况;  -x或--unix:此参数的效果和指定"-A unix"参数相同;  --ip或--inet:此参数的效果和指定"-A inet"参数相同。

如:netstat -anop | grep 关键字(进程、端口),查看某个进程或者端口占用情况

tcpdump抓取网络数据包(强大的命令)

dstat命令,综合了 vmstat, iostat, ifstat, netstat 等多个信息

-c:显示CPU系统占用,用户占用,空闲,等待,中断,软件中断等信息。-C:当有多个CPU时候,此参数可按需分别显示cpu状态,例:-C 0,1 是显示cpu0和cpu1的信息。-d:显示磁盘读写数据大小。-D hda,total:include hda and total。-n:显示网络状态。-N eth1,total:有多块网卡时,指定要显示的网卡。-l:显示系统负载情况。-m:显示内存使用情况。-g:显示页面使用情况。-p:显示进程状态。-s:显示交换分区使用情况。-S:类似D/N。-r:I/O请求情况。-y:系统状态。--ipc:显示ipc消息队列,信号等信息。--socket:用来显示tcp udp端口状态。-a:此为默认选项,等同于-cdngy。-v:等同于 -pmgdsc -D total。--output 文件:此选项也比较有用,可以把状态信息以csv的格式重定向到指定的文件中,以便日后查看。例:dstat --output /root/dstat.csv & 此时让程序默默的在后台运行并把结果输出到/root/dstat.csv文件中。

其他监控工具

iptraf——实时网络状况监测

tcptrace——数据包分析工具

ping——发送一个回送信号请求给网络主机

netperf——网络带宽工具

其他关键概念

  1. VFS—虚拟文件系统:不同文件系统和用户进程之间的一个抽象层
  2. 缓冲区
    1. 内核缓冲区
    2. 用户进程缓冲区
    3. 设备缓冲区(硬件缓冲区)
  3. 系统优化—Zero Copy
  4. AIO
  5. 最大传输单元(Maximum Transmission Unit,MTU)

  1. 《深入理解计算机系统》
  2. 《UNIX网络编程:套接字联网API》
  3. https://www.cnblogs.com/huxiao-tee/p/4657851.html
  4. https://www.cnblogs.com/sunsky303/p/8962628.html
  5. https://www.jianshu.com/p/fa7bdc4f3de7
  6. https://ylgrgyq.github.io/2017/07/23/linux-receive-packet-1/
  7. http://www.pulpcode.cn/2017/02/01/user-buffer-and-kernel-buffer/
  8. https://www.ibm.com/developerworks/cn/linux/l-linux-kernel/Linux
  9. https://www.ibm.com/developerworks/cn/linux/l-async/index.html
  10. https://www.sunzhongwei.com/read-the-card-from-the-ifconfig-traffic
  11. https://www.cnblogs.com/ggjucheng/archive/2012/01/14/2322659.html
  12. https://blog.51cto.com/linuxzj/1587241

原文发布于微信公众号 - BanzClub(banz-club)

原文发表时间:2019-05-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券