Linux下Http高并发参数优化之TCP/IP基础

 2017-06-06 22:19:32     TCP/IP  Socket  Linux  Http   947


导读: 最近在做 Nginx 压力测试时,需要对 Linux 系统参数进行调整,网上很多参数设置,都是互相 Copy,没有详细说明。我也只好照着 Copy 调试了一边,莫名其妙的就好使了。应了最近学到的一句话「My Code Works I Don't Know Why」。既然能好用,那就先用着了吧。这两天正好有时间做总结,Google 各种疑惑,就对其中的一些知识点进行了梳理和扫盲。

起因


虽然经常说到TCP/IP协议,但是真正直接用它们的机会没有。现在很多框架、语言,都对这些做了封装,便于使用,于是乎,就忽略了它们。

在对 Linux 调优时,涉及一些 TCP/IP 协议相关的内容,都忘记了。看来,丢掉的东西,迟早是要还的。于是,又重新开始学习 TCP/IP。

TCP/IP


网络通信模型

我们都知道网络通信模型有七层组成。第一层是物理层,也就是最底层的,第七层是应用层,也就是我们平时用到的软件或开发的服务。HTTP 协议就是建立在 TCP/IP 协议基础之上的。

模型图如下。

七层协议

上面的七层模型可以抽象的简化为四层。

  • 网络接口层:这个没少好说的(其实就是不懂),就是驱动硬件工作,使数据通过硬件进行发送、传输、接收。

  • 网络互连层:解决在一个单一网络上传输数据包,以及将数据从源网络传输到目的网络。(具体怎么工作的,太复杂,我也没弄懂)

  • 传输层:解决诸如端到端可靠性,或保证数据的有序性等问题。(TCP是有序的,UDP是无序的)

  • 应用层:该层就是我们经常要Coding的服务,是直接面对用户的服务。

模型图如下。

四层协议

TCP/IP通信过程

创建通路: 在进行传输之前,Client 端与 Server 端会有三次握手的通信,以建立连接。

数据传输: TCP协议使用序号,对收到的TCP报文段进行排序以及检测重复的数据;使用校验和来检测报文段的错误;使用确认和计时器来检测和纠正丢包或延时。

终结通路: 连接终止使用了四路握手过程,在这个过程中每个终端的连接都能独立地被终止。

三次握手流程图。
三次握手

整体详细流程图如下。

tpc/ip流程图

注意:
seq: 包的序号,用来解决网络包乱序的问题
ack: 确认收到,用来解决不丢包的问题
Window又叫Advertised-Window: 也就是著名的滑动窗口(Sliding Window),用于解决流控的
TCP Flag: 包的类型,主要是用于操控TCP的状态机的

这里断开连接的过程中,可能会导致出现大量的 'TIME_WAIT',具体原因可以参考理解TIME_WAIT

数据包结构

IP协议负责是根据源主机和目的主机的地址传送数据。为此目的,IP定义了寻址方法和数据报的封装结构。它不保证数据能准确的传输。数据包在到达的时候可能已经损坏,顺序错乱(与其它一起传送的报文相比),产生冗余包,或者全部丢失。如果应用需要保证可靠性,一般需要采取其他的方法,例如利用IP的上层协议TCP协议控制。

TCP协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。

数据包结构如下。

数据包结构

数据传输

TCP协议为了保证数据传输过程的可靠性和有序性,使用序号,对收到的TCP报文段进行排序以及检测重复的数据;使用校验和来检测报文段的错误;使用确认和计时器来检测和纠正丢包或延时。

发送方发送序号和1460字节数据的TCP报文段给接收方,当数据包都是相连的,接收方并不一定每次请求都回复,发送方会一直发送,当接收方回复的序号与发送方不一致时(例如发送方发到序号5,接收方返回2),说明有报文丢失了,需要发送方重新发送 序号+1 的报文。直到接收方所有报文都接收。

数据传输

协议规定好了,数据传输有保障了,传输层的 "协议 + 端口" 可以唯一标识主机中的应用程序(进程)。利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。那么,怎么让它们工作呢?,这时,Socket 就出现了。

Socket

Socket 是对 TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。从设计模式的角度看来,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

Socket 还可以认为是一种网络间不同计算机上的进程通信的一种方法,利用三元组(ip地址,协议,端口)就可以唯一标识网络中的进程,网络中的进程通信可以利用这个标志与其它进程进行交互。

Socket

服务端Socket先绑定ip,再监控指定的网络端口,就可以提供服务了。客户端只需要知道服务的IP和端口,就可以建立连接和通信。

看看 Socket 的工作流程图。

Socket流程图

其实浏览器作为客户端,也是通过 Socket 实现的。

Socket 起源于 Unix ,Unix/Linux 基本哲学之一就是 "一切皆文件",都可以用 "打开(open) –> 读写(write/read) –> 关闭(close)" 模式来进行操作。因此 Socket 也被处理为一种特殊的文件。

这里说的 Socket 抽象层与 Linux 的 Socket 并不是同一个事物。Socket 抽象层是面向应用层的Socket编程。Linux 的 Socket 是指Socket句柄(也叫描述符)。

从Socket 的工作流程图可以看出,TCP服务端绑定IP,监听端口,就可以与客户端建立连接和数据传输。一个客户端与服务端建立连接没什么问题,如果是多个客户端同时与服务端建立连接和通信(并发),单一的Socket进程,单一的端口,怎么做到并发呢?这时候就用到了Socket句柄了。


参考: