在实施OpenStack工作负载的过程中,一个常见的问题是整个网络的碎片化,造成不可预见的性能问题。分片通常很难解决,因为网络会变得很复杂,所以数据包的路径很难追踪或预测。
OpenStack在集群的初始设置中或添加新节点时启动网络接口卡(NIC)的配置。消息传输单元(MTU)配置也是在这个阶段生成的。不建议在集群部署后改变配置。通常情况下,系统集成商希望在部署和配置堆栈的网络之前,端到端的路径已经正确配置,以避免仅仅为了测试而不断改变MTU。
Neutron网络是在OSP部署后创建的。这允许管理员为实例创建1500MTU的网络。然而,计算节点本身仍然被设置为MTU,所以碎片仍然可能发生。例如,在电信工作负载中,所有实例最常见的MTU值是9000,所以很容易在网络和实例创建后无意中造成碎片。
巨型帧
下面是一个实例的例子(部署在OSP 16.1.5中),配置了巨型帧(8996),但是你可以看到网络路径没有同时配置巨型帧。这导致了碎片化,因为系统数据包使用8996作为MTU。
$ ping 10.169.252.1 -M do -s 8968
PING 10.169.252.1 (10.169.252.1) 8968(8996) bytes of data.
--- 10.169.252.1 ping statistics ---
7 packets transmitted, 0 received, 100% packet loss, time 5999ms
这表明在不允许碎片化的情况下,100%的数据包丢失。该输出有效地识别了问题,揭示了网络路径中MTU的问题。如果你允许分片,你可以看到有一个成功的Ping。
$ ping 10.169.252.1 -M dont -s 8968
PING 10.169.252.1 (10.169.252.1) 8968(8996) bytes of data.
8976 bytes from 10.169.252.1: icmp_seq=1 ttl=255 time=3.66 ms
8976 bytes from 10.169.252.1: icmp_seq=2 ttl=255 time=2.94 ms
8976 bytes from 10.169.252.1: icmp_seq=3 ttl=255 time=2.88 ms
8976 bytes from 10.169.252.1: icmp_seq=4 ttl=255 time=2.56 ms
8976 bytes from 10.169.252.1: icmp_seq=5 ttl=255 time=2.91 ms
--- 10.169.252.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 2.561/2.992/3.663/0.368 m
在确认了这个问题后,你可能需要等待,直到网络团队解决了这个问题。在此期间,碎片化存在并影响你的系统。你不应该更新堆栈来检查问题是否已经解决,所以在这篇文章中,我分享一个安全的方法来降低计算节点内部的端到端MTU。
调整MTU
第1步:确定你的实例运行在哪个管理程序上
首先,你必须获得有关你的实例的信息。从Overcloud使用openstack
命令来做这件事。
(overcloud)[director]$ openstack server \
show 2795221e-f0f7-4518-a5c5-85977357eeec \
-f json
{
"OS-DCF:diskConfig": "MANUAL",
"OS-EXT-AZ:availability_zone": "srvrhpb510-compute-2",
"OS-EXT-SRV-ATTR:host": "srvrhpb510-compute-2.localdomain",
"OS-EXT-SRV-ATTR:hostname": "server-2",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "srvrhpb510-compute-2.localdomain",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000248",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "r-ms2ep00g",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/vda",
"OS-EXT-SRV-ATTR:user_data": null,
"OS-EXT-STS:power_state": "Running",
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"OS-SRV-USG:launched_at": "2021-12-16T18:57:24.000000",
<...>
"volumes_attached": ""
}
第2步:连接到管理程序并转储实例的XML
接下来,你需要转储定义你的实例的XML(使用virsh dumpxml
命令)。这样你就可以在下一步过滤它,把输出重定向到一个文件中。
[compute2]$ sudo podman \
exec -it nova_libvirt bash
(pod)[compute2]# virsh \
list --all
Id Name State
-----------------------------------
6 instance-00000245 running
7 instance-00000248 running
(pod)[compute2]# virsh dumpxml instance-00000245 | tee inst245.xml
instance-00000245
1718c7d4-520a-4366-973d-d421555295b0
server-1
2021-12-16 18:57:03
[...]
第3步:检查XML的输出
有了 XML 输出之后,用你最喜欢的 pager 或文本编辑器来获取实例的网络接口信息。
<interface type='bridge'>
<mac address='fa:16:3e:f7:15:db'/>
<source bridge='br-int'/>
<virtualport type='openvswitch'>
<parameters interfaceid='da128923-84c7-435e-9ec1-5a000ecdc163'/>
</virtualport>
<target dev='tap123'/>
<model type='virtio'/>
<driver name='vhost' rx_queue_size='1024'/>
<mtu size='8996'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
从这个输出中,过滤源桥(在计算节点上)和目标设备(计算节点中的物理接口)。
这个输出可能会发生变化,这取决于你使用的防火墙类型,或者如果你使用的是安全组,其中的流程有点不同,但所有的主机接口都会显示出来,接下来的步骤适用于所有的接口。
第4步:查看目标设备
在这种情况下,计算节点上的tap123
是目标设备,所以用ip命令检查它。
[compute2]$ ip addr show tap123
tap123: flags=4163 mtu 8996
inet6 fe80::fc16:3eff:fef7:15db prefixlen 64 scopeid 0x20
ether fe:16:3e:f7:15:db txqueuelen 10000 (Ethernet)
[...]
你可以看到MTU是8996,正如预期的那样。你还可以找到MAC地址(fe:16:3e:f7:15:db),所以你可以选择使用OpenStack端口命令确认端口。
你还可以检查这个接口是否在br-int桥中。
Bridge br-int
[...]
Port tap123
tag: 1
Interface tap123
这也符合预期,因为这允许这个实例使用外部网络的南方和北方流量。
第5步:改变MTU
在主机上专门为你的目标接口(本例中为tap123
)应用一个普通的MTU改变。
[compute2]$ sudo ifconfig tap123 mtu 1500
[compute2]$ ip addr show tap123 | grep mtu
tap123: flags=4163 mtu 1500
第6步:重复
现在在实例内部重复这个过程,把MTU从8996移到1500。这包括管理程序的部分,因为neutron仍然被配置为巨量帧。
[localhost]$ sudo ip link set dev eth0 mtu 1500
[localhost]$ ip addr show eth0
eth0: flags=4163 mtu 1500
inet 10.169.252.186 netmask 255.255.255.255 broadcast 0.0.0.0
inet6 fe80::f816:3eff:fef7:15db prefixlen 64 scopeid 0x20
ether fa:16:3e:f7:15:db txqueuelen 1000 (Ethernet)
RX packets 1226 bytes 242462 (236.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 401 bytes 292332 (285.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
验证
现在本地网络内的路径的MTU是1500。如果你试图发送一个比这个大的数据包,应该会显示一个错误。
[localhost]$ ping 10.169.252.1 -M do -s 1500
PING 10.169.252.1 (10.169.252.1) 1500(1528) bytes of data.
ping: local error: Message too long, mtu=1500
ping: local error: Message too long, mtu=1500
ping: local error: Message too long, mtu=1500
ping: local error: Message too long, mtu=1500
--- 10.169.252.1 ping statistics ---
4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3000ms
这个ping将28字节添加到头,试图发送1500字节+28字节的有效载荷。系统无法发送,因为它超过了MTU。一旦你把有效载荷减少到1472,你就可以在一个帧中成功发送ping。
[localhost]$ ping 10.169.252.1 -M do -s 1472
PING 10.169.252.1 (10.169.252.1) 1472(1500) bytes of data.
1480 bytes from 10.169.252.1: icmp_seq=1 ttl=255 time=1.37 ms
1480 bytes from 10.169.252.1: icmp_seq=2 ttl=255 time=1.11 ms
1480 bytes from 10.169.252.1: icmp_seq=3 ttl=255 time=1.02 ms
1480 bytes from 10.169.252.1: icmp_seq=4 ttl=255 time=1.12 ms
--- 10.169.252.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 1.024/1.160/1.378/0.131 ms
这就是当平台向网络发送9000字节的数据包时,如何结束碎片问题,但在一些网络组件中仍然发生碎片。现在你已经解决了重传问题、丢包问题、抖动问题、延迟问题和其他相关问题。
当网络团队解决了网络问题后,你可以将MTU命令恢复到以前的值。这就是你修复网络问题的方法,而不需要重新部署堆栈。
端对端模拟
下面是如何在端到端方案中模拟这个问题,看看它是如何工作的。你可以不ping网关,而ping第二个实例。你应该观察MTU不匹配是如何导致问题的,特别是当一个应用程序将数据包标记为非碎片时。
假设你的服务器有以下规格。
服务器 1:
主机名: server1
IP: 10.169.252.186/24
MTU: 1500
服务器2:
主机名:server2
IP:10.169.252.184/24
MTU:8996
连接到server1并ping到server2。
[server1]$ ping 10.169.252.184
PING 10.169.252.184 (10.169.252.184) 56(84) bytes of data.
64 bytes from 10.169.252.184: icmp_seq=1 ttl=64 time=0.503 ms
64 bytes from 10.169.252.184: icmp_seq=2 ttl=64 time=0.193 ms
64 bytes from 10.169.252.184: icmp_seq=3 ttl=64 time=0.213 ms
--- 10.169.252.184 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.193/0.303/0.503/0.141 ms
连接到server1并ping到server2,不分片,MTU为1500。
[server1]$ ping 10.169.252.184 -M do -s 1472
PING 10.169.252.184 (10.169.252.184) 1472(1500) bytes of data.
1480 bytes from 10.169.252.184: icmp_seq=1 ttl=64 time=0.512 ms
1480 bytes from 10.169.252.184: icmp_seq=2 ttl=64 time=0.293 ms
1480 bytes from 10.169.252.184: icmp_seq=3 ttl=64 time=0.230 ms
1480 bytes from 10.169.252.184: icmp_seq=4 ttl=64 time=0.268 ms
1480 bytes from 10.169.252.184: icmp_seq=5 ttl=64 time=0.230 ms
1480 bytes from 10.169.252.184: icmp_seq=6 ttl=64 time=0.208 ms
1480 bytes from 10.169.252.184: icmp_seq=7 ttl=64 time=0.219 ms
1480 bytes from 10.169.252.184: icmp_seq=8 ttl=64 time=0.229 ms
1480 bytes from 10.169.252.184: icmp_seq=9 ttl=64 time=0.228 ms
--- 10.169.252.184 ping statistics ---
9 packets transmitted, 9 received, 0% packet loss, time 8010ms
rtt min/avg/max/mdev = 0.208/0.268/0.512/0.091 ms
server1的MTU是1500,而server2的MTU大小比这个大,所以运行在server1上的应用程序向server2发送数据包时没有碎片问题。如果服务器2的应用程序也被设置为非碎片,但使用9000的MTU,会发生什么?
[localhost]$ ping 10.169.252.186 -M do -s 8968
PING 10.169.252.186 (10.169.252.186) 8968(8996) bytes of data.
--- 10.169.252.186 ping statistics ---
10 packets transmitted, 0 received, 100% packet loss, time 8999ms
发生了分片,发送的数据包被丢失。
要纠正这个问题,请重复MTU的修复,使两个服务器的MTU相同。作为一个测试,恢复服务器1。
[compute2]$ sudo ip link set dev tap123 mtu 8996
[compute2]$ ip addr show tap123 | grep mtu
tap123: flags=4163 mtu 8996
[server1]$ sudo ip link set dev eth0 mtu 8996
[server1]$ ip addr show eth0 | grep mtu
eth0: flags=4163 mtu 8996
[...]
现在重复9000字节有效载荷的ping,不允许有分片。
[server2]$ ping 10.169.252.186 -M do -s 8968
PING 10.169.252.186 (10.169.252.186) 8968(8996) bytes of data.
8976 bytes from 10.169.252.186: icmp_seq=1 ttl=64 time=1.60 ms
8976 bytes from 10.169.252.186: icmp_seq=2 ttl=64 time=0.260 ms
8976 bytes from 10.169.252.186: icmp_seq=3 ttl=64 time=0.257 ms
8976 bytes from 10.169.252.186: icmp_seq=4 ttl=64 time=0.210 ms
8976 bytes from 10.169.252.186: icmp_seq=5 ttl=64 time=0.249 ms
8976 bytes from 10.169.252.186: icmp_seq=6 ttl=64 time=0.250 ms
--- 10.169.252.186 ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5001ms
rtt min/avg/max/mdev = 0.210/0.472/1.607/0.507 ms
排除MTU的故障
这是一个简单的解决方法,帮助网络管理员解决MTU问题,而不需要通过堆栈更新来来回移动MTU。所有这些MTU配置也是暂时的。一个实例或系统重启会使所有接口恢复到原来的(和配置的值)。
这也只需要几分钟的时间,所以我希望你能发现这一点。