上一篇《第4章-4 linux 磁盘IO》,接着了解linux网络管理
通过以下几方面来配置和优化网络:
1. TCP/IP 模型(了解)
2. TCP/IP 的三次握手建立连接和四次挥手结束连接
3. Socket Buffer
4. 多网卡绑定(了解)
5. 网络检测和故障排除
TCP/IP 模型
OSI与 TCP/IP协议之相关性
TCP/IP 的三次握手建立连接和四次挥手结束连接
三次握手建立连接:
1) 第一次握手:建立连接时,客户端 A 发送 SYN 包(SYN=j)到服务器 B,并进入 SYN_SEND 状态,等待服务器 B 确认。
2) 第二次握手:服务器 B 收到 SYN 包,必须发送一个 ACK 包,来确认客户 A 的 SYN
(ACK=j+1),同时自己也发送一个 SYN 包(SYN=k),即 SYN+ACK 包,此时服务器 B
进入 SYN_RECV 状态。
3) 第三次握手:客户端 A 收到服务器 B 的 SYN+ACK 包,向服务器 B 发送确认包 ACK
(ACK=k+1),此包发送完毕,客户端 A 和服务器 B 进入 ESTABLISHED 状态,完成三次握手(注意,主动打开方的最后一个 ACK 包中可能会携带了它要发送给服务端的数据)。
总结:三次握手,其实就是主动打开方,发送 SYN,表示要建立连接,然后被动打开方对此进行确认,然后主动方收到确认之后,对确认进行确认;
四次挥手断开连接:
由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭,TCP 的双方都要向对方发送一次 FIN 包,并且要对方对此进行确认。根据两次 FIN 包的发送和确认可以将四次挥手分为两个阶段:
第一阶段:主要是主动闭方发送 FIN,被动方对它进行确认;
1) 第一次挥手:主动关闭方,客户端发送完数据之后,向服务器发送一个 FIN(M)数据包,进入FIN_WAIT1 状态;被动关闭方服务器收到 FIN(M)后,进入 CLOSE_WAIT 状态;
2) 第二次挥手:服务端发送 FIN(M)的确认包 ACK(M+1),关闭服务器读通道,进入 LAST_ACK 状态;客户端收到 ACK(M+1)后,关闭客户端写通道,进入 FIN_WATI2 状态;此时客户端仍能通过读通道读取服务器的数据,服务器仍能通过写通道写数据。
第二阶段:主要是被动关闭方发送 FIN,主动方对它进行确认;
1) 第三次挥手:服务器发送完数据,向客户机发送一个 FIN(N)数据包,状态没有变还是 LAST_ACK;客户端收到 FIN(N)后,进入 TIME_WAIT 状态
2) 第四次挥手:客户端返回对 FIN(N)的确认段 ACK(N+1),关闭客户机读通道(还是 TIME_WAIT 状态);服务器收到 ACK(N+1)后,关闭服务器写通道,进入 CLOSED 状态 。
总结:四次挥手,其本质就是:主动关闭方数据发送完成之后 发送 FIN,表示我方数据发
送完,要断开连接,被动方对此进行确认;然后被动关闭方在数据发送完成之后 发送 FIN,
表示我方数据发送完成,要断开连接,主动方对此进行确认;
CLOSE_WAIT 状态的原因和处理方法
由 TCP 四次挥手断开连接的过程,可以知道 CLOSE_WAIT 是主动关闭方发送 FIN 之后,被动方收到 FIN 就进入了 CLOSE_WAIT 状态,此时如果被动方没有调用 close() 函数来关闭 TCP 连接,那么被动方服务器就会一直处于 CLOSE_WAIT 状态(等待调用 close 函数的状态);所以 CLOSE_WAIT 状态的原因主要有两点:
1) 代码中没有写关闭连接的代码,也就是程序有 bug;
2) 该连接的业务代码处理时间太长,代码还在处理,对方已经发起断开连接请求; 也就是客户端因为某种原因提前向服务端发出了 FIN 信号,导致服务端被动关闭,若服务端不主动关闭 socket发 FIN 给 Client,此时服务端 Socket 会处于 CLOSE_WAIT 状态(而不是 LAST_ACK 状态)。
由于某种原因导致的 CLOSE_WAIT 会维持至少 2 个小时的时间(系统默认超时时间的是 7200 秒,也就是 2 小时)。如果服务端程序因某个原因导致系统造成过多 CLOSE_WAIT,
那么通常是等不到释放那一刻系统就已崩掉了。要解决 CLOSE_WAIT 过多导致的问题,有
两种方法:
1) 找到程序的 bug,进行修正;
2) 修改 TCP/IP 的 keepalive 的相关参数来缩短 CLOSE_WAIT 状态维持的时间
TCP 连接的保持(keepalive)相关参数:
1) /proc/sys/net/ipv4/tcp_keepalive_time 对应内核参数 net.ipv4.tcp_keepalive_time
含义:如果在该参数指定的秒数内,TCP 连接一直处于空闲,则内核开始向客户端发起对它的探测,看他是否还存活;
2) /proc/sys/net/ipv4/tcp_keepalive_intvl 对应内核参数 net.ipv4.tcp_keepalive_intvl
含义:以该参数指定的秒数为时间间隔,向客户端发起对它的探测;
3) /proc/sys/net/ipv4/tcp_keepalive_probes 对应内核参数 net.ipv4.tcp_keepalive_probes
含义:内核发起对客户端探测的次数,如果都没有得到响应,那么就断定客户端不可达
或者已关闭,内核就关闭该 TCP 连接,释放相关资源
结 论 : CLOSE_WAIT 状 态 维 持 的 秒 数 = tcp_keepalive_time + tcp_keepalive_intvl * tcp_keepalive_probes 。 所 以 适 当 的 降 低 tcp_keepalive_time , tcp_keepalive_intvl ,tcp_keepalive_probes 三个值就可以减少 CLOSE_WAIT:
临时修改方法:
sysctl -w net.ipv4.tcp_keepalive_time=600 sysctl -w net.ipv4.tcp_keepalive_probes=3 sysctl -w net.ipv4.tcp_keepalive_intvl=5 sysctl -p
修改会暂时生效,重新启动服务器后,会还原成默认值。修改之后,进行观察一段时间,如果 CLOSE_WAIT 减少,那么就可以进行
永久性修改:
在文件 /etc/sysctl.conf 中的添加或者修改成下面的内容:
net.ipv4.tcp_keepalive_time = 1800 net.ipv4.tcp_keepalive_probes = 3 net.ipv4.tcp_keepalive_intvl = 15
这里的数值比上面的要大,因为上面的测试数据有点激进。当然数据该大之后效果不好,还是可以使用上面激进的数据。
修改之后执行:
sysctl -p
TIME_WAIT 状态的原因和处理方法:
TIME_WAIT 发生在 TCP 四次挥手的第二阶段:被动关闭方发送 FIN(N),主动方收到该
FIN(N),就进入 TIME_WAIT 状态,然后发送 ACK(N+1)。进入 TIME_WAIT 之后,主动关闭方会等待 2MSL( Maximum Segment Lifetime 报文最大存活时间 )的时间,才释放自己占有的端口等资源。这是因为,如果最后的 ACK(N+1)没有被被动方收到的话,被动方会重新发生一个 FIN(N2),那么主动方再次发送一个确认 ACK(N2+1),所以这样一来就要用使主动关闭方在
TIME_WAIT 状态等待 2MSL 的时长。如果你的 TIME_WAIT 状态的 TCP 过多,占用了过多端口等资源,那么可以通过修改 TCP 内核参数进行调优:
TCP 连接的 TIME_WATI 相关参数:
1) /proc/sys/net/ipv4/tcp_tw_reuse 对应的内核参数:net.ipv4.tcp_tw_reuse
含义: 是否能够重新启用处于 TIME_WAIT 状态的 TCP 连接用于新的连接;启用该参数
的同时,必须同时启用下面的快速回收 recycle 参数
2) /proc/sys/net/ipv4/tcp_tw_recycle 对应的内核参数:net.ipv4.tcp_tw_recycle
含义:设置是否对 TIME_WAIT 状态的 TCP 进行快速回收;
3) /proc/sys/net/ipv4/tcp_fin_timeout 对应的内核参数:net.ipv4.tcp_fin_timeout
含义:主动关闭方 TCP 保持在 FIN_WAIT_2 状态的时间。对方可能会一直不结束连接或
不可预料的进程死亡。默认值为 60 秒。
修改方法和 keepalive 的相关参数一样:
sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.tcp_tw_recycle=1 sysctl -w net.ipv4.tcp_fin_timeout=30 sysctl -p
永久修改方法,也是修改 /etc/sydctl.conf:
net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_tw_recycle=1 net.ipv4.tcp_fin_timeout=30
sysctl -p 是修改生效。
Socket Buffer
发送方发送数据,接收方接受数据,双方必须存在一个保存数据的 buffer,称为 Socket
Buffer,TCP/IP 的实现都是放在 kernel 中的,所以 Socket Buffer 也是在 kernel 中的。Socket Buffer 的大小配置对网络的性能有很大的影响,相关参数如下:
1) /proc/sys/net/ipv4/tcp_mem: 这是一个系统全局参数,表示所有 TCP 的 buffer 配置。有三个值,单位为内存页(通常为 4K),第一个值表示 buffer 的下限,第二个值表示内存压力模式开启,即超过该值,开启内存压力模式;第三个值内存使用的上限,超过时,可能会丢弃报文。
2) /proc/sys/net/ipv4/tcp_rmem: r 表示 receive,也有三个值,第一个值为 TCP 接收 buffer 的最少字节数;第二个是默认值(该值会被 rmem_default 覆盖);第三个值 TCP 接收 buffer 的最大字节数(该值会被 rmem_max 覆盖);
3) /proc/sys/net/ipv4/tcp_wmem: w 表示 write,也就是 send。也有三个值,第一个值为 TCP 发送buffer 的最少字节数;第二个是默认值(该值会被 wmem_default 覆盖);第三个值 TCP 发送 buffer的最大字节数(该值会被 wmem_max 覆盖);
4) /proc/sys/net/core/wmem_default: TCP 数据发送窗口默认字节数;
5) /proc/sys/net/core/wmem_max: TCP 数据发送窗口最大字节数;
6) /proc/sys/net/core/rmem_default: TCP 数据接收窗口默认字节数;
7) /proc/sys/net/core/rmem_max: TCP 数据接收窗口最大字节数;
调高网络缓存
/proc/sys/net/ipv4/tcp_mem TCP 全局缓存,单位为内存页(4k); 对应的内核参数:net.ipv4.tcp_mem ,可以在 /etc/sysctl.conf 中进行修改; /proc/sys/net/ipv4/tcp_rmem 接收 buffer,单位为字节 对应的内核参数:net.ipv4.tcp_rmem, 可以在 /etc/sysctl.conf 中进行修改; /proc/sys/net/ipv4/tcp_wmem 接收 buffer,单位为字节 对应的内核参数:net.ipv4.tcp_wmem, 可以在 /etc/sysctl.conf 中进行修改; /proc/sys/net/core/rmem_default 接收 buffer 默认大小,单位字节 对应内核参数:net.core.rmem_default, 可以在 /etc/sysctl.conf 中进行修改; /proc/sys/net/core/rmem_max 接收 buffer 最大大小,单位字节 对应内核参数:net.core.rmem_max, 可以在 /etc/sysctl.conf 中进行修改; /proc/sys/net/core/wmem_default 发送 buffer 默认大小,单位字节 对应内核参数:net.core.rmem_default, 可以在 /etc/sysctl.conf 中进行修改; /proc/sys/net/core/wmem_max 发送 buffer 最大大小,单位字节 对应内核参数:net.core.rmem_max, 可以在 /etc/sysctl.conf 中进行修改; 注意:修改 /etc/sysctl.conf 之后,必须执行 sysctl -p 命令才能生效。
多网卡绑定(了解)
Linux 内核支持将多个物理网卡绑定成一个逻辑网络,通过 bond 技术让多块网卡看起来是一个单独的以太网接口设备并具有相同的 ip 地址,从而进行网卡的负载均衡和网卡容错。
网络检测和故障排除
1. 延时检测、端口及防火墙的状态检测
ping 、telnet、systemctl status firewalld(centos 7.0)
2. 使用 netstat 命令查看活动的网络连接
根据协议 tcp -t, udp -u 进行显示:
netstat -ntap , netstat -nuap
-n 表示 numeric 用数字显示 ip 和 端口,而不是文字;
-t 表示 tcp 连接
-u 表示 udp 连接
-a 选项表示所有状态的 TCP 连接
-p 表示程序名称;
字段含义:
recv-Q 接收队列(receive queue)。表示收到的数据已经在本地接收缓冲,但是还有多少没有被用户进程取走。
send-Q 发送队列(send queue)。发送了数据,但是没有收到对方的 Ack 的, 还保留本地缓冲区。
注意:这两个值通常应该为 0,如果不为 0 可能是有问题的。packets 在两个队列里都不应该有堆积状态。可接受短暂的非 0 情况。
查看 TCP 连接处于各种状态的连接数量:
[root@db1 ~]# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' ESTABLISHED 4
3. 使用 sar 命令查看网络流量及负载
sar -n DEV 1 5 : 查看所有网卡每秒收包,发包数量,每秒接收多少 KB,发送多少 KB:
字段含义:
rxpck/s txpck/s rxkB/s txkB/s 每秒收包,每秒发包,每秒接收 KB 数量,每秒发送 KB 数量;
sar -n EDEV 1 5:查看网络错误,网络超负载,网络故障
字段含义:
rxerr/s:Total number of bad packets received per second. 每秒接收的损坏的包
txerr/s:Total number of errors that happened per second while transmitting packets. 每秒发送的损坏的包
coll/s: Number of collisions that happened per second while transmitting packets. 每秒发送的网络冲突包数
rxdrop/s: Number of received packets dropped per second because of a lack of space in linux buffers. 每秒丢弃的接收包
txdrop/s: Number of transmitted packets dropped per second because of a lack of space in linux buffers. 每秒发送的被丢弃的包
txcarr/s: Number of carrier-errors that happened per second while transmitting packets. carrier-errors 每秒载波错误数
rxfram/s: Number of frame alignment errors that happened per second on received packets.每秒接收数据包的帧对齐错误数
rxfifo/s:Number of FIFO overrun errors that happened per second on received packets. 接收 fifo 队列发生过载错误次数(每秒)
txfifo/s:Number of FIFO overrun errors that happened per second on transmitted packets. 发送方的 fifo 队列发生过载错误次数(每秒)
1) 如果 coll/s 网络冲突持续存在,那么可能网络设备存在问题或者存在瓶颈,或者配置错误;
2) 发生了 FIFO 队列 overrun,表示 SOCKET BUFFER 太小;
3) 持续的数据包损坏,frame 损坏,可能预示着网络设备出现部分故障,或者配置错误;
4. 使用 ifconfig 命令查看网络活动
[root@localhost ~]# ifconfig eth0
// UP:表示“接口已启用”。
// BROADCAST :表示“主机支持广播”。
// RUNNING:表示“接口在工作中”。
// MULTICAST:表示“主机支持多播”。
// MTU:1500(最大传输单元):1500 字节
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
// inet :网卡的 IP 地址。
// netmask :网络掩码。
// broadcast :广播地址。
inet 192.168.1.135 netmask 255.255.255.0 broadcast 192.168.1.255
// 网卡的 IPv6 地址
inet6 fe80::2aa:bbff:fecc:ddee prefixlen 64 scopeid 0x20<link>
// 连接类型:Ethernet (以太网) HWaddr (硬件 mac 地址)
// txqueuelen (网卡设置的传送队列长度)
ether 00:aa:bb:cc:dd:ee txqueuelen 1000 (Ethernet)
// RX packets 接收时,正确的数据包数。
// RX bytes 接收的数据量。
// RX errors 接收时,产生错误的数据包数。
// RX dropped 接收时,丢弃的数据包数。
// RX overruns 接收时,由于速度过快而丢失的数据包数。
// RX frame 接收时,发生 frame 错误而丢失的数据包数。
RX packets 2825 bytes 218511 (213.3 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
// TX packets 发送时,正确的数据包数。
// TX bytes 发送的数据量。
// TX errors 发送时,产生错误的数据包数。
// TX dropped 发送时,丢弃的数据包数。
// TX overruns 发送时,由于速度过快而丢失的数据包数。
// TX carrier 发送时,发生 carrier 错误而丢失的数据包数。
// collisions 冲突信息包的数目。
TX packets 1077 bytes 145236 (141.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
上一篇《第4章-4 linux 磁盘IO》
下一篇《》