diff --git a/notes/pics/tcp-sticky.png b/notes/pics/tcp-sticky.png new file mode 100644 index 000000000..1584d5b12 Binary files /dev/null and b/notes/pics/tcp-sticky.png differ diff --git "a/notes/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234 - \344\274\240\350\276\223\345\261\202.md" "b/notes/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234 - \344\274\240\350\276\223\345\261\202.md" index 21305f181..ad3441878 100644 --- "a/notes/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234 - \344\274\240\350\276\223\345\261\202.md" +++ "b/notes/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234 - \344\274\240\350\276\223\345\261\202.md" @@ -12,6 +12,7 @@ * [TCP 拥塞控制](#tcp-拥塞控制) * [1. 慢开始与拥塞避免](#1-慢开始与拥塞避免) * [2. 快重传与快恢复](#2-快重传与快恢复) + * [TCP 粘包与拆包](#tcp-粘包与拆包) @@ -67,7 +68,7 @@ 第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。 -客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。 +客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。有了第三次握手,客户端收到服务器对滞留请求的确认时,发现确认号不是自己期望的,就回复 RST,服务器收到后放弃这个连接,不会多打开一个连接。 ## TCP 的四次挥手 @@ -97,6 +98,22 @@ - 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。 +2MSL 正好覆盖一个来回:A 的确认最多在网络中存活 1 MSL,B 超时重传的 FIN 最多再存活 1 MSL。Linux 中 TIME_WAIT 固定为 60 秒(TCP_TIMEWAIT_LEN)。 + +**大量 TIME_WAIT 与 CLOSE_WAIT** + +TIME_WAIT 出现在主动关闭的一方,使用短连接的机器会积累大量 TIME_WAIT,例如每次请求都新建连接去访问下游服务。每个 TIME_WAIT 连接占用一个本地端口 60 秒,Linux 默认的本地端口范围是 32768~60999,共 28232 个,连接同一个目标地址和端口时,每秒新建超过约 470 个连接就会耗尽端口。 + +解决方案: + +- 使用长连接或连接池,例如 HTTP 的 keep-alive、数据库连接池; +- 在发起连接的一方开启 net.ipv4.tcp_tw_reuse,允许新连接复用处于 TIME_WAIT 的端口,它依靠 TCP 时间戳选项识别旧连接的报文; +- 扩大本地端口范围 net.ipv4.ip_local_port_range。 + +另一个参数 tcp_tw_recycle 在 NAT 环境下会丢弃正常的连接,Linux 4.12 已将其移除。 + +CLOSE_WAIT 出现在被动关闭的一方,表示对方已经关闭,本方的应用还没有调用 close()。连接大量停在 CLOSE_WAIT 通常是程序的问题,例如异常分支没有关闭连接、从连接池借出的连接没有归还,需要排查代码,保证每个连接最终都会被关闭。 + ## TCP 可靠传输 TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。 @@ -115,7 +132,7 @@ RTTs = (1 - a) × RTTs + a × RTT RTO = RTTs + 4 × RTTd ``` -其中 RTTd 为偏差的加权平均值。 +其中 RTTd 为偏差的加权平均值。RFC 6298 建议 a 取 1/8,计算 RTTd 时的权重取 1/4,并要求 RTO 不小于 1 秒;Linux 的下限为 200 ms。 ## TCP 滑动窗口 @@ -171,3 +188,52 @@ TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、 慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。