docs: 汇编研究

This commit is contained in:
LiuBinPeng
2022-06-23 14:59:47 +08:00
parent 55d66cc4c5
commit f0e20eaf2e
30 changed files with 1042 additions and 347 deletions

View File

@@ -2,6 +2,147 @@
## TCP/UDP
TCP 传输的核心公式:速度 = 窗口大小/往返时间,这个公式对于理解传输本质和排查传输问题具有很强的知道意义。
TCP 里面有三种窗口发送窗口、接收窗口、拥塞窗口。如果没有特别说明TCP Window 指的是接收窗口。
TCP Window Full指的是在途数据的大小等于接收窗口大小时窗口会“满”
Wireshark 分析得到的信息都会用方括号包起来TCP 报文本身的信息,没有方括号。
### TCP 如何探测到拥塞
TCP 传输的起始阶段,速度都是从低到高升上来的,很少一上来就以最终速度运行的情况。
这个机制其实就是 TCP 的拥塞控制。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCPWindowDiff.png)
### TCP 拥塞控制
TCP 使用拥塞机制来确保传输速度和稳定性。拥塞机制是通信双方自己要实现的功能,在途中的网络设备(交换机、路由器)转发,不关心拥塞机制。
拥塞机制包括:慢启动、拥塞避免、快速重传、快速回复。
#### 慢启动
Slow start即 TCP 传输的开始阶段是从一个相对低的速度开始的。之后拥塞窗口会翻倍方式增长。每次 TCP 收到一个确认了数据的 ACK拥塞窗口就增加1个 MSS
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-SlowStart.png)
当收到重复的 ACK 报文即确认号一样比如收到2个 ACK但他们的确认号一样那么第二个 ACK 就不算是“确认数据的 ACK”拥塞窗口就不会增加2个 MSS只会增加1个 MSS。
会持续增长吗?当然不是,有终止条件:
- 遇到了拥塞
- 拥塞窗口增长到慢启动阈值
注意慢启动阶段并不是“每过1RTT 就翻倍”也可能会比翻倍少一些。什么意思呢慢启动阶段TCP 每收到一个 ACK拥塞窗口就增加1MSS。假设初始拥塞窗口大小为2MSS发送2个数据报之后
- 收到1个ACK间隔确认那么在1RTT内拥塞窗口从2变为3没有翻倍
- 收到2个ACK那么在1RTT内拥塞窗口从2变为4翻倍了
#### 慢启动阈值
**慢启动阈值** ssthresh过了这个阈值拥塞窗口的增长速度就立刻变慢了变为每过一个 RTT拥塞窗口就增加一个 MSS之前是没收到一个确认数据的 ACK 就增加1个 MSS
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-SlowStartChart.png)
上图所示,假设 ICW 是4个 MSSssthresh 是32个 MSS慢启动阶段经过1个 RTT 后CW 扩大为8MSS、16MSS、32MSS。等到了阈值之后TCP就进入拥塞避免阶段了。每过一个 RTT拥塞窗口只增加1MSS曲线就变为较为斜率较低的直线了。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-CongestionAvoidance.png)
QA如果拥塞窗口大小正好等于慢启动阈值那么发送方这时候是需要采用拥塞避免过程线性增长还是继续选择慢启动过程指数增长[RFC5681](https://datatracker.ietf.org/doc/html/rfc5681) 规定是说两者都可以。
#### 间隔确认
很多 TCP 的实现中,如果收到连续多个报文,确认报文是间隔一个进行回复的。
比如发送方发送1、2接收方收到1、2此时针对2进行确认。发送方发送3、4接收方针对4进行确认。这样的机制下会使得拥塞窗口的增长速度比每次 ACK 更低一些(更稳)
#### 拥塞窗口
Congestion Window拥塞窗口简写 CW。拥塞窗口是针对每个连接进行维护的比如某个主机有3个 TCP 连接在传输数据那么这3个连接就各自维护自己的拥塞窗口。
**初始化拥塞窗口**Initial Congestion Window简写为 ICWIW
在 Linux 内核3.0以前ICW 的比较小在2到4个MSS2010年谷歌提出为了充分利用现代互联网的传输能力Linux 应该把 ICW 从24个MSS提升到10MSS。这也被应用到 Linux 内核3.0及其以后的版本中规定了 `TCP_INIT_CWND` 为10.
```c
#define TCP_INIT_CWND 10
```
这个值在慢启动阶段影响了传输速度慢启动阶段每经过1个RTT拥塞窗口就翻倍所以不同的 ICW 就会造成不同的传输速度。
| ICW | 1RTT后 | 2RTT后 | 3RTT后 |
| --- | ----- | ----- | ----- |
| 2 | 4 | 8 | 16 |
| 10 | 20 | 40 | 80 |
#### 拥塞避免
TCP 野蛮生长后当达到慢启动阈值之后会进入拥塞避免阶段。这个阶段的特点是“和性增长乘性降低”Addictive increase/multiplicative decreaseAIMD解释下就是拥塞避免阶段每个RTT时间拥塞窗口只增长1MSS这个阶段的拥塞窗口增长是线性的斜率比较低的直线当探测到拥塞时拥塞窗口就要往下降下降是直接减半的叫做乘性降低。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-CongestionAvoidanceProgress.png)
#### 窗口和 MSS 的关系
窗口一般比MSS大MSS 是有确定上限的一般为1460当然实际情况下值可能更低。
窗口一般是n个MSS。
#### 快速重传
TCP 每发送一个报文,就会启动一个超时计时器,若在限定时间内没有收到这个报文的确认,则发送方认为这个报文在网络上丢了,需要发送方重传这个报文,这个机制叫做“超时重传”。
TCP 最小超时重传时间为200ms在这个机制下虽然解决了丢包问题但带来一个新的问题某个包都已经丢失了还需要等待200ms或者更长时间那体验不就更糟糕了吗
TCP 会利用另一种机制来解决超时重传带来的时间等待问题就是快速重传机制一旦发送方收到3次重复确认确认 ACK 报文中有确认号加上第一次确认就一共4次就不用等待超时计时器了直接重传这个报文。
注意:快速重传看的是数据,超时重传看的是时间。
#### 快速恢复
快速恢复是 TCP Reno 算法引入的一个阶段,是和“快速重传”搭配工作的。跟之前的“慢启动-拥塞避免-慢启动-拥塞避免”不同的是,当遇到拥塞点之后,通过快速重传,就不再进入慢启动了,而是从这个减半的拥塞窗口开始,保持跟拥塞避免一样的线性增长,直到遇到下一个拥塞点。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-QuickRecover.png)
注意:“快速恢复”有几个小细节
- 快速恢复一定是和快速重传搭配使用的。那有何表现或者为什么这么设计如果在快速重传的场景下也就是收到连续3次重复确认 ACK 报文那么这个特征可以理解为“网络虽然有点问题但是能收到3次重复 ACK 报文网络也没那么糟糕”所以如果走传统的拥塞避免直接从0开始就很慢也很浪费效率但如果按照拥塞避免直接减半之后再走慢启动也很浪费网络所以当遇到一个拥塞点之后减半就按照拥塞避免线性增长
总结:慢启动不只是在 TCP 连接启动的阶段才发生传输的过程中遇到网络较差也会发生多次慢启动。一旦拥塞避免阶段探测到了拥塞TCP 还是会回到慢启动过程,只不过这个慢启动阈值跟之前的不同,如果有多次拥塞,会重复这个过程直到传输结束。
### 总结
- 慢启动:每收到一个 ACK拥塞窗口CW增加一个 MSS
- 拥塞避免:策略是“和性增长乘性降低”,每一个 RTTCW 增加一个 MSS
- 快速重传:接收到 3 次或者以上的重复确认后,直接重传这个丢失的报文
- 快速恢复:结合快速重传,在遇到拥塞点后,跳过慢启动阶段,进入线性增长
拥塞窗口CW和接收窗口RW是如何决定了传输速度上限的简单来说
- 当 RW > CW 时,速度由 CW 决定
- 当 RW < CW 时,速度由 RW 决定
## HTTP 缓存控制
缓存Cache是计算机领域里的一个重要概念是优化系统性能的利器。
@@ -455,9 +596,6 @@ TLS 是建立在 TCP 的上层协议,因此要先按照 TCP 的规则来,也
注意这里不是 TCP Fast OpenTFO 是用来加速连续 TCP 连接的数据交互 TCP 拓展协议。原理如下TCP 三次握手的过程中,当用户首次访问 Server 时,发送 SYN 包Server 根据用户 IP 生成 Cookie已加密并与 SYN-ACK 一同发回 Client当 Client 随后重连时在SYN 包携带 TCP Cookie如果 Server 校验合法,则在用户回复 ACK 前就可以直接发送数据;否则按照正常三次握手进行。
第三步:服务器会把证书也发送给客户端(Server Certificate),见下图第一个大红框中的内容。
同时服务器选择了 ECDHE 算法所以在发送了服务器证书后马上发送“Server Key Exchange”消息。里面是椭圆曲线的公钥(Server Params),用来实现密钥的交换算法,再加上自己的私钥签名认证(用私钥对椭圆曲线的 public key 做了签名认证生成了 Signature)