前几节,咱们一块儿学习了文件系统和磁盘 I/O 的工做原理,以及相应的性能分析和优化方法。接下来,咱们将进入下一个重要模块—— Linux 的网络子系统。缓存
因为网络处理的流程最复杂,跟咱们前面讲到的进程调度、中断处理、内存管理以及 I/O等都密不可分,因此,我把网络模块做为最后一个资源模块来说解。bash
同 CPU、内存以及 I/O 同样,网络也是 Linux 系统最核心的功能。网络是一种把不一样计算机或网络设备链接到一块儿的技术,它本质上是一种进程间通讯方式,特别是跨系统的进程
间通讯,必需要经过网络才能进行。随着高并发、分布式、云计算、微服务等技术的普及,网络的性能也变得愈来愈重要。服务器
那么:网络
一、Linux 网络又是怎么工做的呢?数据结构
二、又有哪些指标衡量网络的性能呢?并发
接下来的两篇文章,我将带你一块儿学习 Linux 网络的工做原理和性能指标。负载均衡
说到网络,我想你确定常常提起七层负载均衡、四层负载均衡,或者三层设备、二层设备等等。那么,这里说的二层、三层、四层、七层又都是什么意思呢?框架
实际上,这些层都来自国际标准化组织制定的开放式系统互联通讯参考模型(OpenSystem Interconnection Reference Model),简称为 OSI 网络模型。分布式
为了解决网络互联中异构设备的兼容性问题,并解耦复杂的网络包处理流程,OSI 模型把网络互联的框架分为应用层、表示层、会话层、传输层、网络层、数据链路层以及物理层
等七层,每一个层负责不一样的功能。其中,微服务
应用层,负责为应用程序提供统一的接口。
表示层,负责把数据转换成兼容接收系统的格式。
会话层,负责维护计算机之间的通讯链接。
传输层,负责为数据加上传输表头,造成数据包。
网络层,负责数据的路由和转发。
数据链路层,负责 MAC 寻址、错误侦测和改错。
可是 OSI 模型仍是太复杂了,也没能提供一个可实现的方法。因此,在 Linux 中,咱们实际上使用的是另外一个更实用的四层模型,即 TCP/IP 网络模型。
TCP/IP 模型,把网络互联的框架分为应用层、传输层、网络层、网络接口层等四层,其中,
物理层,负责在物理网络中传输数据帧。
应用层,负责向用户提供一组应用程序,好比 HTTP、FTP、DNS 等。
传输层,负责端到端的通讯,好比 TCP、UDP 等。
网络层,负责网络包的封装、寻址和路由,好比 IP、ICMP 等。
网络接口层,负责网络包在物理网络中的传输,好比 MAC 寻址、错误侦测以及经过网卡传输网络帧等。
为了帮你更形象理解 TCP/IP 与 OSI 模型的关系,我画了一张图,以下所示:
固然了,虽然说 Linux 实际按照 TCP/IP 模型,实现了网络协议栈,但在平时的学习交流中,咱们习惯上仍是用 OSI 七层模型来描述。好比,说到七层和四层负载均衡,对应的分
别是 OSI 模型中的应用层和传输层(而它们对应到 TCP/IP 模型中,其实是四层和三层)。
TCP/IP 模型包括了大量的网络协议,这些协议的原理,也是咱们每一个人必须掌握的核心基础知识。若是你不太熟练,推荐你去学《TCP/IP 详解》的卷一和卷二,或者学习极客时间
出品的《 趣谈网络协议》专栏。
有了 TCP/IP 模型后,在进行网络传输时,数据包就会按照协议栈,对上一层发来的数据进行逐层处理;而后封装上该层的协议头,再发送给下一层。
固然,网络包在每一层的处理逻辑,都取决于各层采用的网络协议。好比在应用层,一个提供 REST API 的应用,可使用 HTTP 协议,把它须要传输的 JSON 数据封装到 HTTP
协议中,而后向下传递给 TCP 层。
而封装作的事情就很简单了,只是在原来的负载先后,增长固定格式的元数据,原始的负载数据并不会被修改。
好比,以经过 TCP 协议通讯的网络包为例,经过下面这张图,咱们能够看到,应用程序数据在每一个层的封装格式
其中:
传输层在应用程序数据前面增长了 TCP 头; 网络层在 TCP 数据包前增长了 IP 头; 而网络接口层,又在 IP 数据包先后分别增长了帧头和帧尾。
这些新增的头部和尾部,都按照特定的协议格式填充,想了解具体格式,你能够查看协议的文档。 好比,你能够查看这里,了解 TCP 头的格
这些新增的头部和尾部,增长了网络包的大小,但咱们都知道,物理链路中并不能传输任意大小的数据包。网络接口配置的最大传输单元(MTU),就规定了最大的 IP 包大小。
在咱们最经常使用的以太网中,MTU 默认值是 1500(这也是 Linux 的默认值)。
一旦网络包超过 MTU 的大小,就会在网络层分片,以保证分片后的 IP 包不大于 MTU值。显然,MTU 越大,须要的分包也就越少,天然,网络吞吐能力就越好。
理解了 TCP/IP 网络模型和网络包的封装原理后,你很容易能想到,Linux 内核中的网络栈,其实也相似于 TCP/IP 的四层结构。以下图所示,就是 Linux 通用 IP 网络栈的示意
图:
(图片参考《性能之巅》图 10.7 通用 IP 网络栈绘制)
咱们从上到下来看这个网络栈,你能够发现,
一、最上层的应用程序,须要经过系统调用,来跟套接字接口进行交互;套接字的下面,就是咱们前面提到的传输层、网络层和网络接口层;
二、最底层,则是网卡驱动程序以及物理网卡设备。
一、网卡是发送和接收网络包的基本设备。
二、在系统启动过程当中,网卡经过内核中的网卡驱动程序注册到系统中。
三、而在网络收发过程当中,内核经过中断跟网卡进行交互。
再结合前面提到的 Linux 网络栈,能够看出,网络包的处理很是复杂。因此,网卡硬中断只处理最核心的网卡数据读取或发送,而协议栈中的大部分逻辑,都会放到软中断中处理。
了解了 Linux 网络栈后,咱们再来看看, Linux 究竟是怎么收发网络包的。
注意,如下内容都以物理网卡为例。事实上,Linux 还支持众多的虚拟网络
设备,而它们的网络收发流程会有一些差异。
咱们先来看网络包的接收流程。
一、当一个网络帧到达网卡后,网卡会经过 DMA 方式,把这个网络包放到收包队列中;而后经过硬中断,告诉中断处理程序已经收到了网络包。
二、接着,网卡中断处理程序会为网络帧分配内核数据结构(sk_buff),并将其拷贝到sk_buff 缓冲区中;而后再经过软中断,通知内核收到了新的网络帧。
三、接下来,内核协议栈从缓冲区中取出网络帧,并经过网络协议栈,从下到上逐层处理这个网络帧。好比,
一、在链路层检查报文的合法性,找出上层协议的类型(好比 IPv4 仍是 IPv6),再去掉帧头、帧尾,而后交给网络层。
二、网络层取出 IP 头,判断网络包下一步的走向,好比是交给上层处理仍是转发。当网络层确认这个包是要发送到本机后,就会取出上层协议的类型(好比 TCP 仍是 UDP),去
掉 IP 头,再交给传输层处理。
三、传输层取出 TCP 头或者 UDP 头后,根据 < 源 IP、源端口、目的 IP、目的端口 > 四元组做为标识,找出对应的 Socket,并把数据拷贝到 Socket 的接收缓存中。
四、最后,应用程序就可使用 Socket 接口,读取到新接收到的数据了。为了更清晰表示这个流程,我画了一张图,这张图的左半部分表示接收流程,而图中的粉色箭头则表示网络包的处理路径。
了解网络包的接收流程后,就很容易理解网络包的发送流程。网络包的发送流程就是上图的右半部分,很容易发现,网络包的发送方向,正好跟接收方向相反。
一、首先,应用程序调用 Socket API(好比 sendmsg)发送网络包。
因为这是一个系统调用,因此会陷入到内核态的套接字层中。套接字层会把数据包放到Socket 发送缓冲区中。
二、接下来,网络协议栈从 Socket 发送缓冲区中,
一、取出数据包;再按照 TCP/IP 栈,从上到下逐层处理。
二、好比,传输层和网络层,分别为其增长 TCP 头和 IP 头,执行路由查找确认下一跳的 IP,并按照 MTU 大小进行分片。
三、分片后的网络包,再送到网络接口层,进行物理地址寻址,以找到下一跳的 MAC 地址。而后添加帧头和帧尾,放到发包队列中。
这一切完成后,会有软中断通知驱动程序:发包队列中有新的网络帧须要发送
三、最后,驱动程序经过 DMA ,从发包队列中读出网络帧,并经过物理网卡把它发送出去。
在今天的文章中,我带你一块儿梳理了 Linux 网络的工做原理。
多台服务器经过网卡、交换机、路由器等网络设备链接到一块儿,构成了相互链接的网络。因为网络设备的异构性和网络协议的复杂性,国际标准化组织定义了一个七层的 OSI 网络
模型,可是这个模型过于复杂,实际工做中的事实标准,是更为实用的 TCP/IP 模型。
TCP/IP 模型,把网络互联的框架,分为应用层、传输层、网络层、网络接口层等四层,这也是 Linux 网络栈最核心的构成部分。
一、应用程序经过套接字接口发送数据包,先要在网络协议栈中从上到下进行逐层处理,最终再送到网卡发送出去。
二、而接收时,一样先通过网络栈从下到上的逐层处理,最终才会送到应用程序。
了解了 Linux 网络的基本原理和收发流程后,你确定火烧眉毛想知道,如何去观察网络的性能状况。那么,具体来讲,哪些指标能够衡量 Linux 的网络性能呢?别急,我将在下一节中为你详细讲解。