注:计算机网络是一个很大的学科,不是三言两语、一篇文章就能说清楚的,这里只是简单普及一下基础知识,以及运维常用的工具和排查手段。
一 知识图谱
二 网络层次划分
计算机的网络结构分为3种,OSI 七层模型、TCP/IP 四层模型 和 五层模型,OSI 七层模型是理论上的一个通信模型,在实际应用上常用的是 TCP/IP 模型 。在 TCP/IP 模型中,在操作系统层面所有进程、应用所实际的都是 应用层 的协议,如 SMTP, HTTP 等,然后再通过 底层 进行建立通讯。
如果是 agent -> server
的数据交互为例:
- Agent 作为应用程序,会产生数据 data,当数据需要发送到先经过传输层的封装,把对应的端口信息封装到数据包中。
- 然后传输层的数据包再经过网络层的封装,把 IP 地址信息封装到数据包中。
- 最后链路层会再把自己的物理地址进行封装到数据包中,形成一个完整的数据报文,包含Mac地址,IP地址信息,端口信息等 (完整的数据报文如下)。
- 这段报文后续会被网络设备进行路由和转发,到对应的 server,然后经过层层的解包,最后把 data 数据交给 server 应用程序进行后续的处理。
三 带宽和传输速率
正常来说,一个报文的大小一般是 1448 字节 Byte 1,(也叫大B,1Byte = 8 bit比特)。而每秒能传输的 字节数,即是我们常说的带宽,常用的单位有 Mb/s 2 和 MB/s。所以在进行沟通网络带宽时,我们需要注意与除了与客户沟通带宽的大小之后,还有确认单位,如:”客户如果说能提供的带宽是 100 兆”,我们需要再问一句:“是大B还是小b。”3 以此来确认对应的单位,同时,运营商方面的叫法,也是以 Mb/s 为单位,如 100兆带宽 ,或者是 100 Mbps ,都是表示 XX 兆比特每秒,需要 100Mb/s = (100/8) MB/s = 12.5 MB/s
注:
- 这里与 MTU (最大传输单元,Maximum Transmission Unit) 相关,一般是 1500。MTU 是链路层对网络层的限制,如果超过这个限制,会在网络层进行数据包的分片,不利于传输。
- Mb/s 也有使用 Mbps 进行表示。
- 大B 表示 Bytes/s, 小b 表示 bits/s
3.1 如何测试?
在 Linux 系统中,我们通常会使用 iperf3 工具进行测试两端之间的带宽。
# 工具安装
yum -y install iperf3
iperf3 是 C/S 架构,需要在接收方听一个端口,并且由发起方发起请求,因此源和目标都要安装该工具。
# 在接收方:
iperf3 -s -p 3000
# -s 表示是 server 端
# -p 表示要侦听的端口
# 返回:
# -----------------------------------------------------------
# Server listening on 3000
# -----------------------------------------------------------
# 在发起方:
iperf3 -c 10.10.0.10 -p 3000
测试完成后,在发起方会看到如下的返回:
上面的返回结论是: 共传输了 3.98 GB 的数据,发送方带宽是 3.42 Gbits/s,接收方带宽是 3.42 Gbits/s。换算成传输速率就是:(3.42*1024/8) MB/s
,约为 400 MB/s。
四 常见网络协议
- 从 二 网络层次划分 中可以看到,我们常说的 “SSH 协议、HTTP 协议、SMTP 协议” 等,都是应用层所定义的协议,不同的服务之间使用不同的协议进行建立会话。
- 而我们在开放端口时常说的 TCP,UDP 协议,实际是指的是传输层的通讯协议,常见的是这两个协议,上层的协议一般会封装成 TCP 或 UDP 再往下进行通讯。
- 第三个常说的 IPv4、IPv6,实际上是指网络层的 IP (Internet Protocol) 协议,v4 版本和 v6 版本。
所以我们常说的开放网络策略,一般都需要提供对应的 IP 地址和端口,实际上就是对双方的 传输层、网络层 进行建立通讯。如:
源 | 方向 | 目标 | 端口 | 协议 |
---|---|---|---|---|
10.10.0.10 | –> | 20.10.10.10 | 3306 | TCP |
要特别注意的是,默认情况下,我们所说的 开放端口,开放防火墙策略 等,一般都是指 准入策略,而不是准入准出。如上面的策略,并没有写
10.10.0.10 <-- 20.10.10.10
的返回策略,一般情况下在建立会话时,发起方会根据操作系统内核所分配的一个随机端口,与目标进行建立起会话,随机端口的范围众多,一般不会有要求开放对应的端口,而更应该关注的是目标端口。
五 会话连接
当客户端与服务端要建立起 TCP 连接时,一般需要经过二次握手。而如果需要正常断开会话,需要四次挥手。以下以 gse 为例:
5.1 三次握手
- 正常情况下,gse_server 服务端的进程会正常侦听一个 (或多个) 端口,这时如果使用
netstat
命令,可以看到该端口处于 LISTEN 状态。 - 当 gse_agent 需要发起与 gse_agent 的连接时,会发送一个 SYN 信号,然后 agent 服务器上会看到 SYN-SEND 的状态。一般情况下是看不到的,因为这会在瞬间完成。只有在 gse_server 端没有开通防火墙的情况下,才会看到该状态。
- 当 gse_server 收到来自 agent 的 SYN 请求后,会回复一个 SYN+ACK 的应答,并且网络状态会改成 SYN-RECV。
- gse_agent 收到 SYN+ACK 信号后,立即回复 ACK 的应答到 gse_server。当 gse_server 收到应答后,即建立起连接,
netstat
状态为 ESTABLISHED。
六 网络连通性测试
当我们充分了解上述所涉及到的知识后,便可以进一步来理解如何去测试两个服务之间的网络连通性。从下往上:
- 在链路层:两个服务器之间需要有物理设备的支撑,如网线、光纤、Wifi、交换机路由器等等,以及服务器的网卡设置有特定的,唯一的物理地址,即 Mac 地址。一般情况下企业内部都会有这些设备。如果两个服务 (或服务器) 之间无法找到任何一个物理设备可以建立连接的,这种情况称为 物理隔离
- 在网络层:两个服务 (或服务器) 之间需要有用于通信的地址信息,如 IP 地址,并且两者之间功能进行通讯。我们可以使用
ping
工具来测试网络层是否能通信。
ping 10.10.0.10
注:ping 所使用的协议是网络层的 ICMP 协议,ping 不通也并不能代表传输层也不通,但 ping 一般情况下企业内部都会开放。
- 在传输层:两个服务 (或服务器) 之间需要有可以用于通讯用的端口,以及端口能连通。我们可以使用 telnet 工具进行测试传输层的连通性。
telnet 10.10.0.10 48668
# 返回:
# Trying 10.10.0.10...
# Connected to 10.10.0.10.
# Escape character is '^]'.
# Connection closed by foreign host.
注:telnet 只能用于测试有状态的 TCP 连接,无状态的 UDP 连接不能使用 telnet 进行测试,可以使用 nc 命令:
nc -vuz 10.10.0.10 60020 # 返回: # Ncat: Version 7.50 ( https://nmap.org/ncat ) # Ncat: Connected to 10.11.25.11:60020. # Ncat: UDP packet sent successfully # Ncat: 1 bytes sent, 0 bytes received in 2.01 seconds.
但是由于 UDP 的无状态,上述的测试可能也不一定准确,有条件的话可以使用 nc 先在接收方进行侦听一个 UDP 端口,然后在发起方再用 nc 命令发起一个 UDP 连接:
# 接收方: nc -ulp 9090 # 侦听 UDP 9090 端口 # 发起方: echo "hello" |nc -vu 10.10.0.10 9090 # 成功后在接收方应该能看到 hello 信息的返回 # 即表示 UDP 是通的。
- 最后还有一种情况,就是发起方的系统的随机端口已经用完,导致没有更多的随机端口用于发起新的连接。这种一般比较特殊,默认情况下 Linux 的随机端口是
32768-60999
,Windows 的随机端口范围是49152-65535
。
# Linux 查看随机端口
sysctl net.ipv4.ip_local_port_range
# Windows 查看随机端口
netsh int ipv4 show dynamicport tcp
七 网络性能问题
网络的性能问题主要看三个指标:传输速率,响应延迟,丢包率。
7.1 ping
对于响应延迟和丢包率来说,最简单的工具就是 ping
工具:
ping 10.10.0.10 -c 10
# 返回:
# PING 10.10.0.10 (10.10.0.10) 56(84) bytes of data.
# 64 bytes from 10.10.0.10: icmp_seq=1 ttl=60 time=4.04 ms
# 64 bytes from 10.10.0.10: icmp_seq=2 ttl=60 time=4.32 ms
# 64 bytes from 10.10.0.10: icmp_seq=3 ttl=60 time=4.38 ms
# 64 bytes from 10.10.0.10: icmp_seq=4 ttl=60 time=4.68 ms
# 64 bytes from 10.10.0.10: icmp_seq=5 ttl=60 time=4.02 ms
# 64 bytes from 10.10.0.10: icmp_seq=6 ttl=60 time=4.15 ms
# 64 bytes from 10.10.0.10: icmp_seq=7 ttl=60 time=4.36 ms
# 64 bytes from 10.10.0.10: icmp_seq=8 ttl=60 time=4.42 ms
# 64 bytes from 10.10.0.10: icmp_seq=9 ttl=60 time=4.10 ms
# 64 bytes from 10.10.0.10: icmp_seq=10 ttl=60 time=3.76 ms
#
# --- 10.10.0.10 ping statistics ---
# 10 packets transmitted, 10 received, 0% packet loss, time 9012ms
# rtt min/avg/max/mdev = 3.764/4.228/4.686/0.248 ms
从上述的返回中,可以得到的结果有:
- 丢包率是 0% :
10 packets transmitted, 10 received, 0% packet loss, time 9012ms
- RTT 响应时间平均是 4.228ms:
rtt min/avg/max/mdev = 3.764/4.228/4.686/0.248 ms
要注意的主要是 RTT 响应时间,虽然单位是 ms, 但是如果在测试过程中有出现 30ms 或者 300ms 之类的,与个位数的响应时间相比,这些的延迟是相当于慢了 十倍、百倍,如果这种情况出现的频率很高,需要检查两者之间的网络是否有很大的波动。
# 64 bytes from 10.10.0.10: icmp_seq=1 ttl=60 time=4.04 ms
# 64 bytes from 10.10.0.10: icmp_seq=2 ttl=60 time=4.32 ms
# 64 bytes from 10.10.0.10: icmp_seq=3 ttl=60 time=4.38 ms
# 64 bytes from 10.10.0.10: icmp_seq=4 ttl=60 time=4.68 ms
# 64 bytes from 10.10.0.10: icmp_seq=5 ttl=60 time=34.02 ms
# 64 bytes from 10.10.0.10: icmp_seq=6 ttl=60 time=4.15 ms
# 64 bytes from 10.10.0.10: icmp_seq=7 ttl=60 time=4.36 ms
# 64 bytes from 10.10.0.10: icmp_seq=8 ttl=60 time=203.42 ms
# 64 bytes from 10.10.0.10: icmp_seq=9 ttl=60 time=4.10 ms
# 64 bytes from 10.10.0.10: icmp_seq=10 ttl=60 time=3.76 ms
7.2 mtr
mtr 是一个可以结合 ping, nslookup, tracert 来进行判断网络的工具,可以同是进行收集测试连接状态,可用性等。
# 直接使用 mtr 进行测试到 gse 的网络
mtr 10.10.0.10 -r -c 10
# -r 表示返回报告
# -c 10 表示测试的次数
# 返回:
# HOST: server1 Loss% Snt Last Avg Best Wrst StDev
# 1.|-- server1 0.0% 10 2004. 1723. 203.4 2005. 620.5
mtr 报告的每列的意思:
- 第一列:
HOST
,显示IP地址或者主机名。- 第二列:
Loss%
,这个结点的丢包率。- 第三列:
Snt
,发送包的数量。- 第四列:
Last
,最近一次的延时,单位是毫秒ms。- 第五列:
Avg
,平均延时,单位是毫秒ms。- 第六列:
Best
,最低延时,单位是毫秒ms。- 第七列:
Wrst
,最高延时,单位是毫秒ms。- 第八列:
StDev
,标准差。报告一般看三个:
Loss%
、延时 和 标准差:
- Loss 表示当前主机到 gse 服务器的丢包率是多少,正常来说不应该有出现丢包。
- 延时一般会关注平均延时是多少,1-30ms 是极快,31-50ms 是良好, 50-100ms 是普通,>100m 是差
- 标准差是反馈网络的稳定性,数值越大,网络的稳定性越差
7.3 netstat
netstat 主要是查看主机的连接状态,以及网络收发队列是否有问题。
常用的命令有:
# 统计网络状态
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
注:
- CLOSED:无连接是活动的或正在进行
- LISTEN:服务器在等待进入呼叫
- SYN_RECV:一个连接请求已经到达,等待确认
- SYN_SENT:应用已经开始,打开一个连接
- ESTABLISHED:正常数据传输状态
- FIN_WAIT1:应用说它已经完成
- FIN_WAIT2:另一边已同意释放
- ITMED_WAIT:等待所有分组死掉
- CLOSING:两边同时尝试关闭
- TIME_WAIT:另一边已初始化一个释放
- LAST_ACK:等待所有分组死掉
# 检查 TCP 收发队列
netstat -nap |grep -w ESTABLISHED |grep -v 'tcp 0 0'
# 返回的第二列是 Recv-Q 接收队列,第三列是 Send-Q 发送队列
正常情况下这两个队列都应该是动态清零,如果存在大量的数值,就有可能是网络质量存在问题,或者是对应的应用无法快速进行处理请求。
八 抓包分析
常用的抓包工具有: Linux 的 tcpdump
, Windows 的 Wireshark
。
# 一般常用的抓包命令如下
# 抓取 tcp 48668 和 58625 端口的包,含收发动作。
tcpdump \
-i any \
-nn \
-XX \
-vvv \
-s0 \
'(tcp port 48668) or (tcp port 58625)' \
-w tcpdump.cap
抓取的包一般会使用 Wireshark 进行分析,这里就不展开进行分析,有需要的可以参阅:
- 《Wireshark网络分析就这么简单-林沛满》
- 《Wireshark网络分析的艺术-林沛满》