《Linux高性能服务器编程》读书笔记
# 《Linux高性能服务器编程》读书笔记
# 目录
本书分三篇:
- 第一篇,1-4章,介绍TCP/IP中重要的网络协议
- 第二篇,5-15章,剖析服务器编程的各个主要方面
- 5-7章 Linux API
- 8章 高性能服务器的一般框架(IO单元,逻辑单元,存储单元)
- 9-12章 剖析IO单元(IO事件,信号,定时,Libevent)
- 13-15章 多线程,多进程编程,进程池,线程池
- 第三篇,16-17章,探讨如何从系统的角度优化和检测服务器性能
第一章 TCP/IP协议族
第二章 IP协议详解
第三章 TCP协议详解
第四章 TCP/IP通信案例:访问Internet上的Web服务器
第五章 Linux网络编程基础API
第六章 高级IO函数
第七章 Linux服务器程序规范
第八章 高性能服务器程序框架
第九章 IO复用
第十章 信号
第十一章 定时器
第十二章 高性能IO框架库Libevent
第十三章 多进程编程
第十四章 多线程编程
第十五章 进程池和线程池
第十六章 服务器调制,调试和测试
第十七章 系统监测工具
接下来分章节简要记录主要内容,留作个人回顾的“高速缓存”。
后面的章节下的子标题不以书中为依据,而是加入了个人的理解。
# 第一章 TCP/IP协议族
# 1.1 协议族
首先是一张主要的图:
- 数据链路层:主要是ARP和RARP协议
- 网络层是IP协议,另外还要直到ICMP协议也是网络层的重要协议,它的一个重要应用就是ping
- 传输层:自然是TCP和UDP
- 应用层:首先是DNS非常重要,其次就是telnet,ssh等,还要知道OSPF协议用于动态路由更新
# 1.2 封装与分用
封装指的就是数据发送到物理网络之前,从协议栈自顶向下传递的过程中,不同的协议加入头部信息的过程。
具体来说:数据 -> TCP报文段、UDP数据报 -> IP数据报 -> 以太网帧
分用则恰好是封装的反过程,这时帧到达主机后,被不同的协议依次处理,最终把对应的数据交到目标应用程序。
# 1.3 数据链路层的ARP协议
ARP协议实际上可以把任意网络层地址转换为物理地址,但是更多的是使用它从IP地址到以太网地址的过程。
它的工作原理很简单,就是将一个包含目标机器IP地址的信息广播给局域网内所有的机器,满足要求的则会返回,不满足要求的就无视该信息。如果一个局域网中没有这个地址,那么就会把该网络中的路由器解析为硬件地址,然后把数据报传给它,此时对于请求设备已经结束了ARP和传输两个过程。剩下的全部交给路由器,由它递归地执行ARP和传输的操作。
# 1.4 应用层的DNS协议
DNS协议是根据网络域名得到对应目标主机的IP地址。
具体过程:
查hosts。如果没有,进进入下一条。
查本地DNS缓存。如果没有,进进入下一条。
查本地DNS服务器(也叫首选DNS服务器)。如果没有,进进入下一条。
若开启转发,则转至上一级DNS服务器,依次循环。若未开启转发,则转至13台根DNS,本地会收到一个负责该顶级域名的服务器ip,进而由上到下查询。
最终本地DNS服务器返回查询结果给客户机。
# 1.5 Socket在网络结构中的角色
首先Socket是一套API,并不是某个协议。它可以让应用程序能访问内核中的协议实现。如图所示,它存在于应用层和以下各层之间:
它有两个功能:
- 将数据从应用缓冲区复制到内核中的TCP或UDP缓冲区,进而发送。以及其反过程,用于读取接收到的数据。
- 修改内核中各层协议的头部信息或数据结构,精细控制通信行为。
# 第二章 IP协议
第一章中提到了网络层重要的两个协议,一个是IP,还有一个ICMP。
在这里单独拿一章来讲IP协议可见其重要性。
IP协议的特点是:无状态(同样无连接的还有HTTP协议),无连接,不可靠(UDP也是无连接且不可靠的)
# 2.1 IPv4头部结构
这部分没什么好说的,就是IPv4的头部数据。需要注意的是:
- 其长度也是20+40,原因是4bit的头部长度只能表示最大到15,而单位是4字节,也就是15个4字节 = 60字节。
- IP数据报的最大长度是65535(16位)。
- 其中的TTL是生存时间(8位),实际上它是一个计数器,减到0则丢弃数据报。
# 2.2 IP分片是什么
MTU:最大传输单元。
当IP数据报的长度超过帧的MTU时,就会被分片传输。
分片的位置可能是发送端,也可能是中专路由器上,也可能在中间多次被分片,只有在最终的目标机器上才会被重新组装。
被分片后,每个片都有自己的IP数据数据报头部,且有相同的标示值和不同的便宜。
# 2.3 IP 路由与转发(数据报如何找到目的机器)
路由的过程:
- 查找路由表中有没有和目标主机IP相同的主机,即目标主机。
- 查找有没有和目标主机IP具有相同网络ID(网关地址)的IP地址,有则转发。
- 选择默认路由,即网关。
# 2.4 IPv6的特点
- 有128位的IP,v4中只有32位。这意味着每粒沙子都有自己的IP。
- IPv6地址有16进制的:分割表示(4个16进制 * 8),如果遇到连续的0则省略对应段。但是省略只能有一个连续段。
# 第三章 TCP协议
TCP的三个特点:面向连接,字节流,可靠传输
TCP可靠的点包括:
- 确认和超时重传机制
- 流量控制
- 拥塞控制
- 数据校验
# 3.1 TCP的头部结构
我觉得这个还是挺好记的。
其中:
- 头部长度还是4位,这意味着20+40的头部长度。
- 6个标志位,其中有5个比较常见,包括ACK,PSH,RST,SYN,FIN。另一个不常见的是URG,它是表示右下角的紧急指针是否生效。这是TCP发送紧急数据的方法。
- 16位窗口大小,这是流量控制的首段,单位是字节。
- 校验和是TCP执行CRC的部分,是TCP可靠传输的重要保证之一。
# 3.2 连接与断连
三次握手与四次挥手,这里没什么好说的,直接上图。
上下分别是三次握手和四次挥手的部分。
# 3.3 TCP超时重传
首先要注意,有两种超时情况,第一种是建立连接前的超时,我们称之为”连接超时“。另一种就是建立连接后的超时,常称之为”超时重传“。
# 连接超时
此时客户端与服务器还没有建立连接。
这里的机制和超时重传类似,但是我们还是要区分这两种情况。
# 超时重传
这里书上说得不明确,借用其他地方 (opens new window)的总结
超时重传:发送端发送报文后若长时间未收到确认的报文则需要重发该报文。可能有以下几种情况:
- 发送的数据没能到达接收端,所以对方没有响应。
- 接收端接收到数据,但是ACK报文在返回过程中丢失。
- 接收端拒绝或丢弃数据。
RTO:从上一次发送数据,因为长期没有收到ACK响应,到下一次重发之间的时间。就是重传间隔。
- 通常每次重传RTO是前一次重传间隔的两倍,计量单位通常是RTT。例:1RTT,2RTT,4RTT,8RTT......
- 重传次数到达上限之后停止重传。
- 到达上限有两种。在5次内是由TCP控制。第5次重传后,如果还是失败,底层的IP和ARP开始接管,最多15次。
RTT:数据从发送到接收到对方响应之间的时间间隔,即数据报在网络中一个往返用时。大小不稳定。
实际上,RTT的计算也比较复杂,但是这样大概理解是可以的。
# 3.4 TCP拥塞控制
包括慢开始,拥塞避免,快重传,快恢复。
这里是TCP比较重要的一部分内容。
首先必须明确:拥塞控制的最终控制变量是发送窗口swnd(send window),单位是字节数。
而接收方可以通过rwnd(receive window)来控制swnd。但是这样仅仅是流量控制的内容,想要更细粒度的控制流量,即达到拥塞控制的目的,加入了cwnd(congestion window)。最终的swnd为
$$swnd = min(cwnd, swnd)$$
如下图:
下面就分别介绍不同部分的内容。
# 慢开始
慢开始的慢,指的是不要一下子把一个连接的swnd弄成rwnd,而是慢慢的增大。
这里涉及一个SMSS(sender maximum segment size)。指的是发送者最大段大小,单位是字节数。
具体来说,cwnd先控制为SMSS的2-4倍。然后每次收到一个确认,就进行$cwnd+=(N, SMSS)$。N是此次确认中包含之前未被确认的字节数。
这样cwnd会以一个接近指数的方式增长起来(虽然每次增长的差不多,但是由于swnd的增加,增长的频度会增加)。
此时再定义一个变量叫ssthresh(slow start threshold size),即慢启动门限。等到cwnd超过该值,则进入拥塞避免状态。
# 拥塞避免
拥塞避免的目的是减缓cwnd的增长速度。
具体策略:每收到一个确认,cwnd += SMSS*SMSS/cwnd。
这样会保证每个RTT增长1个SMSS,即进入加性增长阶段。
这时都没法发生拥塞,如果发生拥塞了,就会有两种解决路线,路线的选择在于发生了什么样的拥塞
拥塞发生的判断标准为:
- 传输超时(即没有按时收到ACK)— 继续使用慢启动和拥塞避免
- 收到重复的ACK(3个) — 使用快重传和快恢复
如果是传输超时,那就直接进行两步:
- 慢开始门限设置成拥塞时发送窗口的一半(ssthresh减少)
- cwnd = 1,重新进入慢开始。
如果是收到了连续的ACK,就进入下面的快重传与快恢复。
# 快重传与快恢复
简而言之,收到3个重复ACK,则
- 直接重传丢失的报文段
- ssthresh减半
- cwnd = ssthresh,并进入拥塞避免算法
# 第四章 TCP/IP通信案例
本章内容偏实践,没有认真读,但是要分清一下几个概念还是很重要的。
另外本章更注重的是应用层的内容。
# 4.1 什么是HTTP代理服务器
- 正向代理:客户端自己设置的代理服务器地址,客户的每次请求都会发送到正向代理服务器。
- 反向代理:设置在服务器端,作用是接收客户端的请求,并转发给内部网络服务器,并从内部服务上得到结果发送给客户端。
- 透明代理:设置在网关上,任意一方都要经过。
# 4.2 如何访问DNS服务器
# 4.2 HTTP通信的主要内容
# 第五章 Linux网络编程api
# 第六章 高级io函数
# 第七章 Linux服务器程序规范
# 第八章 高性能服务器框架
# 第九章 IO复用
# 第十章 信号
# 第十一章 定时器
# 第十二章 高性能IO框架库 libevent
google chromium用的库