在实施 OpenStack 工作负载期间,一个常见问题是整个网络中的分片,这会导致无法预见的性能问题。分片通常难以解决,因为网络可能会变得复杂,因此数据包的路径可能难以追踪或预测。
OpenStack 在集群的初始设置期间或添加新节点时启动网络接口卡 (NIC) 配置。消息传输单元 (MTU) 配置也在此阶段生成。不建议在集群部署后更改配置。通常,系统集成商期望在部署和配置堆栈网络之前,端到端路径已正确配置,以避免仅为了测试而不断更改 MTU。
Neutron 网络在 OSP 部署后创建。这允许管理员为实例创建 1500 MTU 的网络。但是,计算节点本身仍设置为 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
<domain type='kvm' id='6'>
<name>instance-00000245</name>
<uuid>1718c7d4-520a-4366-973d-d421555295b0</uuid>
<metadata>
<nova:instance xmlns:nova="http://openstack.org/xmlns/libvirt/nova/1.0">
<nova:package version="20.4.1-1.20201114041747.el8ost"/>
<nova:name>server-1</nova:name>
<nova:creationTime>2021-12-16 18:57:03</nova:creationTime>
[...]
</domain>
步骤 3:检查 XML 输出
在您获得 XML 输出后,使用您最喜欢的分页器或文本编辑器来获取实例的网络接口信息。
<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<UP,BROADCAST,RUNNING,MULTICAST> mtu 8996
inet6 fe80::fc16:3eff:fef7:15db prefixlen 64 scopeid 0x20<link>
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<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
步骤 6:重复
现在在实例内部重复此过程,将 mtu 从 8996 移动到 1500。这涵盖了虚拟机管理程序部分,因为 neutron 仍然配置为巨型帧。
[localhost]$ sudo ip link set dev eth0 mtu 1500
[localhost]$ ip addr show eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> 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<link>
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 不匹配如何导致问题,特别是当应用程序将数据包标记为 Not-Fragment 时。
假设您的服务器具有以下规格
服务器 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 发送数据包时没有分片问题。如果 server2 的应用程序也设置为 Not-Fragment,但使用 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。作为测试,恢复 server1
[compute2]$ sudo ip link set dev tap123 mtu 8996
[compute2]$ ip addr show tap123 | grep mtu
tap123: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 8996
[server1]$ sudo ip link set dev eth0 mtu 8996
[server1]$ ip addr show eth0 | grep mtu
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> 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 配置也是临时的。实例或系统重启会导致所有接口恢复为原始值(和配置值)。
它也只需几分钟即可完成,所以我希望您觉得这很有用。
评论已关闭。