系统性能和TCP/UDP网络优化-学习大杂烩

以下内容,纯属拼凑,有点混乱,参考原文在文章末尾。

基于硬件做优化

如果有条件用专用处理器

如GPU,NPU行。

用好CPU缓存,提高缓存命中率

CPU的缓存:一级缓存约5个时钟周期,二级是约12个,三级是约30个。

一次进入缓存的数据大小,coherency_line_size 通常是64字节。

C++[[likely]] [[unlikely]]。

利用好内存管理

常用的库是TCMalloc,Ptmalloc2。TCMalloc在多线程下小内存具有优势。Ptmalloc2在大内存分配上有优势。

栈上的内存比堆更快。像goroutine,可以不用上锁。

IO优化

零拷贝、直接 IO、异步 IO 等等

降低上下文切换和内存拷贝次数。PageCache,磁盘高速缓存。机械硬盘和SSD的区别。

The Linux kernel supports zero-copy through various system calls, such as

  • sys/socket.h's sendfile, sendfile64

  • splice, tee, vmsplice

  • process_vm_readv, process_vm_writev

  • copy_file_range

  • raw sockets with packet mmap[4] or AF_XDP

锁相关

互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。

自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。

共享锁【shared locks】又称为读锁

排他锁【exclusive locks】又称为写锁

 

时钟中断执行的频率很高:100 次/秒(Linux 设计者将一个时钟滴答(tick)定义为 10ms),时钟中断的主要工作是处理和时间有关的所有信息、决定是否执行调度程序。

TCP与UDP区别总结:

  • TCP面向连接;UDP是无连接的,即发送数据之前不需要建立连接

  • TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付

  • TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的

  • UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低

  • 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

  • TCP首部开销20字节;UDP的首部开销小,只有8个字节6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

UDP广播使用广播地址255.255.255.255,本地广播信息是不会被路由器转发

UDP多播,也称为“组播”,将网络中同一业务类型主机进行了逻辑上的分组,进行数据收发的时候其数据仅仅在同一分组中进行,其他的主机没有加入此分组不能收发对应的数据。

  多播的地址是特定的,D类地址用于多播。D类IP地址就是多播IP地址,即224.0.0.0至239.255.255.255之间的IP地址,并被划分为局部连接多播地址、预留多播地址和管理权限多播地址3类:

  1. 局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包。

  2. 预留多播地址:在224.0.1.0~238.255.255.255之间,可用于全球范围(如Internet)或网络协议。

  3. 管理权限多播地址:在239.0.0.0~239.255.255.255之间,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。

TCP决定重传时间间隔的RTO(retransmission timeout)不可控制,linux内核实现中最低值为200ms.

TCP 半连接队列和全连接队列

在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:

  • 半连接队列,也称 SYN 队列;

  • 全连接队列,也称 accepet 队列;

可以通过ss命令查看全连接队列情况。

在「LISTEN 状态」时,Recv-Q/Send-Q 表示的含义如下:

  • Recv-Q:当前全连接队列的大小,也就是当前已完成三次握手并等待服务端 accept() 的 TCP 连接个数;

  • Send-Q:当前全连接最大队列长度;

在「非 LISTEN 状态」时,Recv-Q/Send-Q 表示的含义如下:

  • Recv-Q:已收到但未被应用进程读取的字节数;

  • Send-Q:已发送但未收到确认的字节数;

HTTP 压测工具wrk。

使用 netstat -s 命令来查看丢掉的 TCP 连接的个数.

全连接队列满时,linux默认丢弃syn中的连接,通过将tcp_abort_on_overflow 设为1,就会在满的时候发送一个reset给client。

TCP 全连接队列足最大值取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn, backlog)。从下面的 Linux 内核代码可以得知:

  • somaxconn 是 Linux 内核的参数,默认值是 128,可以通过 /proc/sys/net/core/somaxconn 来设置其值;

  • backloglisten(int sockfd, int backlog) 函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度;

计算当前 TCP 半连接队列长度:

netstat -natp | grep SYN_RECV | wc -l

实际上对服务端一直发送 TCP SYN 包就是所谓的 SYN 洪泛、SYN 攻击、DDos 攻击。

使用 hping3 工具模拟 SYN 攻击。

有三个条件因队列长度的关系而被丢弃的:

  1. 如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;

  2. 若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃;

  3. 如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列长度小于 (max_syn_backlog >> 2),则会丢弃;

操作系统下tcp相关参数

ls -l /proc/sys/net/ipv4/tcp*

TCP三次握手的性能提升

  1. 调整SYN报文重传次数tcp_syn_retries

  2. 调整SYN半连接队列长度

  3. 调整SYN+ACK报文重传次数tcp_synack_retries

  4. 调整accept队列长度

  5. 绕过三次握手

TCP四次握手的性能提升

  1. 调整FIN报文重传次数

  2. 调整FIN_WAIT2状态的时间

  3. 调整孤儿连接的上限个数

  4. 调整time_wait状态的上限个数

  5. 复用time_wait状态的连接

TCP数据传输的性能提升

  1. 扩大窗口大小

  2. 调整发送缓冲区范围

  3. 调整接收缓冲区范围

  4. 接收缓冲区动态调节

  5. 调整内存范围

client发ack报文,tcp_syn_retries默认是6,超时重传1+2+4+8+16+32+64=127秒失败后才终止。可以修改重传次数。

tcp_synack_retries.

如果 SYN 半连接队列已满,只能丢弃连接吗?并不是这样,开启 syncookies 功能就可以在不使用 SYN 队列的情况下成功建立连接。

要想增大半连接队列,不能只单纯增大 tcp_max_syn_backlog 的值,还需一同增大 somaxconn 和 backlog,也就是增大 accept 队列。

tcp_synack_retries

tcp_abort_on_overflow 共有两个值分别是 0 和 1,其分别表示:

  • 0 :如果 accept 队列满了,那么 server 扔掉 client 发过来的 ack ;

  • 1 :如果 accept 队列满了,server 发送一个 RST 包给 client,表示废掉这个握手过程和这个连接;

tcp_abort_on_overflow 设为 0 可以提高连接建立的成功率,只有你非常肯定 accept 队列会长期溢出时,才能设置为 1 以尽快通知客户端。

在 Linux 3.7 内核版本之后,提供了 TCP Fast Open 功能,这个功能可以减少 TCP 连接建立的时延。它把通讯分为两个阶段,第一阶段为首次建立连接,这时走正常的三次握手,但在客户端的 SYN 报文会明确地告诉服务器它想使用 TFO 功能,这样服务器会把客户端 IP 地址用只有自己知道的密钥加密(比如 AES 加密算法),作为 Cookie 携带在返回的 SYN+ACK 报文中,客户端收到后会将 Cookie 缓存在本地。之后,如果客户端再次向服务器建立连接,就可以在第一个 SYN 报文中携带请求数据,同时还要附带缓存的 Cookie。很显然,这种通讯方式下不能再采用经典的“先 connect 再 write 请求”这种编程方法,而要改用 sendto 或者 sendmsg 函数才能实现。

 

四次挥手,每个方向都需要一个 FIN 和一个 ACK。

close 和 shutdown 函数都可以关闭连接。close 函数会让连接变为孤儿连接,shutdown 函数则允许在半关闭的连接上长时间传输数据。Linux 为四次挥手提供了很多控制参数,有些参数的名称与含义并不相符。例如 tcp_orphan_retries 参数中有 orphan 孤儿,却同时对非孤儿连接也生效。tcp_orphan_retries 对所有 FIN_WAIT1 状态下的连接都有效,默认值是 0,特指 8 次。

主动关闭连接的,才有 TIME_WAIT 状态。

如果遇到恶意攻击,FIN 报文根本无法发送出去,这由 TCP 两个特性导致的:

  • 首先,TCP 必须保证报文是有序发送的,FIN 报文也不例外,当发送缓冲区还有数据没有发送时,FIN 报文也不能提前发送。

  • 其次,TCP 有流量控制功能,当接收方接收窗口为 0 时,发送方就不能再发送数据。所以,当攻击者下载大文件时,就可以通过接收窗口设为 0 ,这就会使得 FIN 报文都无法发送出去,那么连接会一直处于 FIN_WAIT1 状态。

tcp_max_orphans 定义了孤儿连接的最大数量。如果孤儿连接数量大于它,新增的孤儿连接将不再走四次挥手,而是直接发送 RST 复位报文强制关闭。

tcp_fin_timeout 它的默认值是 60 秒。这意味着对于孤儿连接,如果 60 秒后还没有收到 FIN 报文,连接就会直接关闭。FIN_WAIT2 状态默认保留 60 秒的原理是一样的,因为这两个状态都需要保持 2MSL 时长。MSL 全称是 Maximum Segment Lifetime,它定义了一个报文在网络中的最长生存时间。

 

滑动窗口

滑动窗口大小,是发送接收缓冲区大小,需要消耗内存。因为tcp报文发送出去后,在确认前还不删除,所以占用内存。

让「发送方」根据「接收方」的实际接收能力控制发送的数据量。

接收缓冲区的大小也叫接收窗口,是个根据缓冲区剩余多少来变化的。

TCP 的传输速度,受制于发送窗口与接收窗口,以及网络设备传输能力。

带宽时延积,它决定网络中飞行报文的大小。 好比一根水管中传输的水量。发送缓冲区不能超过带宽时延积。

通过 tcp_wmem 配置Linux 的缓冲区动态调节功能。

  • 如果发送缓冲区「超过」带宽时延积,超出的部分就没办法有效的网络传输,同时导致网络过载,容易丢包;

  • 如果发送缓冲区「小于」带宽时延积,就不能很好的发挥出网络的传输效率。

策略参数
扩大窗口大小tcp_window_scaling
调整发送缓冲区范围tcp_wmem
调整接收缓冲区范围tcp_rmem
打开接收缓冲区动态调节tcp_moderate_rcvbuf
调整内存范围tcp_mem

默认的滑动窗口最大只能到 65KB,要想提升发送速度必须提升滑动窗口的上限,在 Linux 下是通过设置 tcp_window_scaling 为 1 做到的。(这个正常开启吧)

需要注意的是,tcp_wmem 和 tcp_rmem 的单位是字节,而 tcp_mem 的单位是页面大小。而且,千万不要在 socket 上直接设置 SO_SNDBUF 或者 SO_RCVBUF,这样会关闭缓冲区的动态调整功能。更多内容看陶辉大佬11讲的内容。

TCP的四种拥塞控制算法 1.慢开始。窗口大小由小变大,指数增长。 2.拥塞控制。当拥塞窗口达到拥塞阈值(ssthresh)时,拥塞窗口从指数增长变为线性增长。 3.快重传。通过重传3次丢失包号前一个确认来通知重传。 4.快恢复。当收到三次重复 ACK 时,进入快速恢复阶段,此时拥塞阈值降为之前的一半,然后进入线性增长阶段。

应用层用心跳包也有点用,应对死掉的连接或者攻击。

心跳包小于MTU(1500个字节)时,UDP 协议通常是更好的选择。

SO_SNDBUF

问题:

udp如何有效加密?

udp如何验证用户,每个数据包都需要附带登陆凭证?

网络优化

在合适的情况下利用好UDP广播和组播。

可以考虑在分布服务的时候也用广播或组播,自动发现其它服务。

A类地址:0+7 bit网络ID+24bit主机ID

B类地址:10+12bit网络ID+16bit主机ID

C类地址:110+21bit网络ID+8bit主机ID

D类地址:1110+多播地址

E类地址:1111+预留实验地址

主机 ID 不会出现全 0 和全 1 这两种情况,主机 ID 的比特位全部设为 1 后就是广播地址。192.168.0.101 是 C 类地址,把主机 ID 从 101 改为 255 后,就可以用 192.168.0.255 发送广播了。

子网掩码。

广播报文的丢弃在传输层中,系统查看目标端口是否有进程在监听。

组播除了能够更精准的管理组播范围,还能够跨越多个网络工作。

C10K是指服务器同时处理 1 万个 TCP 连接,C10M是1 千万个 TCP 连接。

多路复用能够将多个低速信道整合到一个高速信道进行传输,从而有效地利用了高速信道。多路复用根据使用的技术可以分为时分复用(TDM)、频分复用(FDM)、空分复用(SDM)和码分复用(CDM)。IO多路复用:复用的是线程。

systemtap是内核开发者必须要掌握的一个工具.获取正在运行的 Linux 系统的信息.动态地监控和跟踪运行中的Linux内核.

TCP性能测试工具:TPCDive

 

 

引用与参考:

极客时间,陶辉的《系统性能调优必知必会》

小林coding《面试官:换人!他连TCP这几个参数都不懂》

https://mp.weixin.qq.com/s/2qN0ulyBtO2I67NB_RnJbg

小林coding的其它文章

拥塞控制

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FatherOfCodingMan

如果觉得有用的话,可以赏点饭钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值