当前位置:网站首页>系统性能和TCP/UDP网络优化-学习大杂烩
系统性能和TCP/UDP网络优化-学习大杂烩
2022-08-02 14:12:00 【FatherOfCodingMan】
以下内容,纯属拼凑,有点混乱,参考原文在文章末尾。
基于硬件做优化
如果有条件用专用处理器
如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
锁相关
互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。
自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
共享锁【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类:
局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包。
预留多播地址:在224.0.1.0~238.255.255.255之间,可用于全球范围(如Internet)或网络协议。
管理权限多播地址:在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
来设置其值;backlog
是listen(int sockfd, int backlog)
函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度;
计算当前 TCP 半连接队列长度:
netstat -natp | grep SYN_RECV | wc -l
实际上对服务端一直发送 TCP SYN 包就是所谓的 SYN 洪泛、SYN 攻击、DDos 攻击。
使用 hping3
工具模拟 SYN 攻击。
有三个条件因队列长度的关系而被丢弃的:
如果半连接队列满了,并且没有开启 tcp_syncookies,则会丢弃;
若全连接队列满了,且没有重传 SYN+ACK 包的连接请求多于 1 个,则会丢弃;
如果没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列长度小于 (max_syn_backlog >> 2),则会丢弃;
操作系统下tcp相关参数
ls -l /proc/sys/net/ipv4/tcp*
TCP三次握手的性能提升
调整SYN报文重传次数tcp_syn_retries
调整SYN半连接队列长度
调整SYN+ACK报文重传次数tcp_synack_retries
调整accept队列长度
绕过三次握手
TCP四次握手的性能提升
调整FIN报文重传次数
调整FIN_WAIT2状态的时间
调整孤儿连接的上限个数
调整time_wait状态的上限个数
复用time_wait状态的连接
TCP数据传输的性能提升
扩大窗口大小
调整发送缓冲区范围
调整接收缓冲区范围
接收缓冲区动态调节
调整内存范围
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这几个参数都不懂》
边栏推荐
- The SSE instructions into ARM NEON
- Open the door of electricity "Circuit" (1): voltage, current, reference direction
- MATLAB绘图函数fplot详解
- STM32LL库——USART中断接收不定长信息
- Manifest merger failed : Attribute [email protected] value=
- Mysql之MVCC
- 质数相关问题-小记
- Unity插件-FairyGUI
- Redis常见面试题
- Yolov5 official code reading - prior to transmission
猜你喜欢
Detailed introduction to the hierarchical method of binary tree creation
MATLAB制作简易小动画入门详解
剑指offer:合并两个排序的链表
[STM32 Learning 1] Basic knowledge and concepts are clear
mysql的索引结构为什么选用B+树?
MATLAB图形加标注的基本方法入门简介
Unity-Post Processing
Mysql之MVCC
cmake configure libtorch error Failed to compute shorthash for libnvrtc.so
golang之GMP调度模型
随机推荐
Network Security Packet Capture
戴森球计划这个游戏牛逼
LeetCode 2344. 使数组可以被整除的最少删除次数 最大公约数
队列与栈
Summarize computer network super comprehensive test questions
Codeforces Round #624 (Div. 3)
Redis的线程模型
质数相关问题-小记
Unity-Post Processing
Open the door of electricity "Circuit" (1): voltage, current, reference direction
mysql学习总结 & 索引
深入理解Golang之Map
二叉树的遍历:递归法/ 迭代法/ 统一迭代法(强QAQ)
第三十章:普通树的存储和遍历
二叉排序树与 set、map
unity Domain Reload & scene Reload 静态变量重置
Mysql lock
[STM32 Learning 1] Basic knowledge and concepts are clear
The SSE instructions into ARM NEON
利用plot_surface命令绘制复杂曲面入门详解