公开学习文档

公开学习文档


笔记

<h2>总结</h2> <ol> <li> <p>对于收包而言,抓包的位置很靠前,在具体走协议栈之前(先遍历 ptype_all,再遍历 ptype_base,而 IP 协议是注册在 ptype_base 中),所以抓包的信息是很原始的。</p> </li> <li> <p>如果全连接队列满了,在客户端回复 ACK 后,服务端则会丢弃 ACK,因此表现为:服务端不断重传 SYN+ACK,而客户端,则不断重传 ACK。</p> </li> <li> <p>端口不足如何确认? 用 strace 查看系统调用的时间,如果 connect 占用时间非常长,那很可能是端口不够用。</p> </li> <li> <p>查看全连接队列长度? <code>ss -nlt</code> 观察 Send-Q 来确认。溢出次数统计:<code>netstat -s| grep overflowed</code></p> </li> <li> <p>半连接队列无法直接查看,需要手动计算。另外,通过 <code>netstat -s | grep SYNs</code> 查看是不准确的,因为全连接队列满了,也会直接这个计数。</p> </li> <li> <p>对于 LISTEN 端,新请求的 sk 是在第 3 次握手的时候创建的</p> </li> <li> <p>查看 ehash 槽数量:<code>dmesg | grep &amp;quot;TCP established hash table entries&amp;quot;</code></p> </li> <li> <p>本机通信时,使用网口 IP 和使用 127.0.0.1 通信是一样的,并且也是交付到 lo 口</p> </li> <li>100W 个空连接,大概需要内存 4G 左右。因为 1 个是 3.3KB 左右,直接乘以 100W = 3.3G</li> </ol> <h2>高并发</h2> <p>基础: 1、如果请求频繁,考虑使用长连接 2、考虑限制 TIME_WAIT 数量:tcp_max_tw_buckets // 听说未释放的时候,如果连接的是不同的服务端,也能直接复用?</p> <p>服务端: 1、修改文件句柄限制:系统级,用户级。100W,则设置 110W。建议:</p> <pre><code class="language-sh"># /ec/sysctl.conf fs.file-max=1100000 # 系统级 fs.nr_open=110000 # 进程级 # /etc/security/limits.conf soft nofile 1000000 hard nofile 1000000</code></pre> <p>2、修改队列长度:如 somaxconn,backlog=1024 3、建议开启 tcp_syncookies,保证不会因为半连接队列满而丢包 4、减少握手重试次数:tcp_syn_retries</p> <p>客户端: 1、修改文件句柄限制 2、修改可用端口范围:10000 - 60000,或 5000 - 65000 3、端口还是不够用,则考虑端口回收:</p> <pre><code class="language-sh">net.ipv4.tcp_timestamps = 1 # 设置之前,要保证开启这个? net.ipv4.tcp_tw_reuse = 1 net.ipv4.tw_recycle = 1</code></pre> <h2>网络性能优化</h2> <p>1、ring buffer 调整 2、开启多队列 - 建议 3、网卡硬中断合并 4、软中断 budget 调整:net.core.netdev_budget。腾讯虚拟机上是 300 5、LRO/GRO:ethtool -l eth0 TSO/GSO 6、发送文件用 mmap 和 sendfile 7、多队列网卡 XPS 调优 8、本机网络 IO 优化:使用 eBPF 的 sockmap 和 sk redirect 可以绕过 TCP/IP 协议栈 9、kernel-bypass:DPDK 10、客户端慎用 bind ?据说绑定一个端口,这个端口就不能复用了?答:非也,随机分配时,只检查 establish 冲突,不检查是否被绑定</p> <h2>半/全连接队列</h2> <pre><code class="language-sh"># 查看 listen 状态异常统计 netstat -s | grep -i listen # 说明: LINUX_MIB_LISTENDROPS # 不一定,涉及 LISTEN 那一部分(接收 SYN 包 和 ACK 包时)所有的失败都会记录在这里 LINUX_MIB_LISTENOVERFLOWS # 意义明确:全连接队列满导致的异常。这个计数增加,则上面的计数一定会同步增加 ############################# # 查看当前半连接队列长度: 无 # 查看是否有半连接队列溢出: netstat -s | grep SYNs # 注意:此计数包含了涉及 LISTEN 那一部分(接收 SYN 包 和 ACK 包时)所有的失败 # 增加半连接队列长度,参考: min(backlog, somaxconn, tcp_max_syn_backlog) + 1 并向上取整为 2^n,但限制最小为 16 ############################# # 查看当前全连接队列长度: ss -lnt # 结果中的 Send-Q 字段 # 查看是否有全连接队列溢出: netstat -s | grep overflow # 意义明确:全连接队列满导致的异常。这个计数增加,则上面的计数一定会同步增加 # 增加全连接队列长度,参考: min(backlog, somaxconn) ############################# # 相关设置项 cat /proc/sys/net/core/somaxconn cat /proc/sys/net/ipv4/tcp_max_syn_backlog echo '20000 61000' &amp;gt; /proc/sys/net/ipv4/ip_local_port_range </code></pre> <p>另外,ss 结果的字段意义不同:</p> <pre><code class="language-c">// file: net/ipv4/tcp_diag.c static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, void *_info) { struct tcp_info *info = _info; if (inet_sk_state_load(sk) == TCP_LISTEN) { r-&amp;gt;idiag_rqueue = sk-&amp;gt;sk_ack_backlog; // 当前全连接队列大小 r-&amp;gt;idiag_wqueue = sk-&amp;gt;sk_max_ack_backlog; // 全连接队列最大长度 } else if (sk-&amp;gt;sk_type == SOCK_STREAM) { const struct tcp_sock *tp = tcp_sk(sk); r-&amp;gt;idiag_rqueue = max_t(int, READ_ONCE(tp-&amp;gt;rcv_nxt) - READ_ONCE(tp-&amp;gt;copied_seq), 0); // 已收到但未被应用层读取的字节数 r-&amp;gt;idiag_wqueue = READ_ONCE(tp-&amp;gt;write_seq) - tp-&amp;gt;snd_una; // 已发送但未收到确认的字节数 } if (info) tcp_get_info(sk, info); }</code></pre> <p>LISTEN 状态:</p> <p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=04856d1f6bf8420f8969f63e81a927fa&amp;amp;file=file.png" alt="" /></p> <p>非 LISTEN 状态:</p> <p><img src="https://www.showdoc.com.cn/server/api/attachment/visitFile?sign=a10429c229040a4af51b524d3ee725f8&amp;amp;file=file.png" alt="" /></p> <p>&gt; 参考文档:<a href="https://ivanzz1001.github.io/records/post/tcpip/2018/04/24/tcpip_timewait">https://ivanzz1001.github.io/records/post/tcpip/2018/04/24/tcpip_timewait</a></p> <h2>一些信息</h2> <pre><code class="language-sh">cat /proc/net/snmp # 统计网络信息 netstat -s cat /proc/net/dev cat /proc/net/netstat</code></pre>

页面列表

ITEM_HTML