Resolva a fragmentação da rede com MTU
Este tutorial fornece uma solução alternativa para ajudar os administradores de rede a resolver problemas de MTU sem precisar de uma atualização de pilha para mover MTUs para frente e para trás.
Durante a implementação de cargas de trabalho OpenStack, um problema comum é a fragmentação em toda a rede, causando problemas imprevistos de desempenho. A fragmentação normalmente é difícil de resolver porque as redes podem se tornar complexas, de modo que o caminho dos pacotes pode ser difícil de rastrear ou prever.
O OpenStack inicia a configuração da placa de interface de rede (NIC) durante a configuração inicial do cluster ou quando novos nós são adicionados. A configuração da Unidade de Transferência de Mensagens (MTU) também é gerada nesta fase. Não é recomendado alterar a configuração após a implantação do cluster. Normalmente, o integrador de sistemas espera que o caminho ponta a ponta esteja configurado corretamente antes de implantar e configurar a rede para a pilha, para evitar alterações constantes de MTU apenas para teste.
As redes de nêutrons são criadas após a implantação do OSP. Isso permite que os administradores criem redes de 1.500 MTU para as instâncias. No entanto, o próprio nó de computação ainda está configurado para a MTU, portanto, a fragmentação ainda poderá ocorrer. Em cargas de trabalho de telecomunicações, por exemplo, o valor de MTU mais comum para todas as instâncias é 9.000, portanto, é fácil causar fragmentação inadvertidamente após a criação de redes e instâncias.
Molduras gigantes
Aqui está um exemplo de instância (implantada no OSP 16.1.5) configurada com jumbo frames (8996), mas você pode ver que o caminho da rede também não possui jumbo frames configurados. Isso causa fragmentação porque os pacotes do sistema usam 8996 como 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
Isso mostra 100% de perda de pacotes quando nenhuma fragmentação é permitida. A saída identifica efetivamente o problema e revela um problema com o MTU no caminho da rede. Se você permitir a fragmentação, poderá ver que há um ping bem-sucedido.
$ 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
Depois de confirmar o problema, talvez seja necessário esperar até que a equipe de rede resolva o problema. Enquanto isso, a fragmentação existe e afeta o seu sistema. Você não deve atualizar a pilha para verificar se o problema foi corrigido, portanto, neste artigo, compartilho uma maneira segura de diminuir o MTU de ponta a ponta dentro do nó de computação.
Ajustando o MTU
Etapa 1: Identifique o hipervisor em que sua instância está sendo executada
Primeiro, você deve obter informações sobre sua instância. Faça isso no Overcloud usando o comando 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": ""
}
Etapa 2: Conecte-se ao hipervisor e despeje o XML da instância
Em seguida, você precisa de um dump do XML (usando o comando virsh dumpxml
) que define sua instância. Para que você possa filtrá-lo na próxima etapa, redirecione a saída para um arquivo:
[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>
Etapa 3: examine a saída XML
Depois de obter a saída XML, use seu pager ou editor de texto favorito para obter as informações da interface de rede da instância.
<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>
A partir desta saída, filtre a ponte de origem (no nó de cálculo) e o dispositivo de destino (a interface física no nó de cálculo).
Essa saída pode mudar dependendo do tipo de firewall que você está usando ou se você estiver usando grupos de segurança onde o fluxo é um pouco diferente, mas todas as interfaces de host são exibidas e as próximas etapas se aplicam a todas elas.
Etapa 4: observe o dispositivo de destino
Neste caso, tap123
no nó de computação é o dispositivo de destino, então examine-o com o comando 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)
[...]
Você pode ver que o MTU é 8.996, conforme esperado. Você também pode encontrar o endereço MAC (fe:16:3e:f7:15:db), para que você possa opcionalmente confirmar a porta usando os comandos de porta do OpenStack.
Você também pode verificar se esta interface está na ponte br-int:
Bridge br-int
[...]
Port tap123
tag: 1
Interface tap123
Isso também é esperado porque permite o tráfego Sul e Norte para esta instância usando a rede externa.
Etapa 5: alterar o MTU
Aplique uma alteração comum de MTU no host especificamente para sua interface de destino (tap123
neste exemplo).
[compute2]$ sudo ifconfig tap123 mtu 1500
[compute2]$ ip addr show tap123 | grep mtu
tap123: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
Etapa 6: Repita
Agora repita o procedimento dentro da instância para mover o mtu de 8996 para 1500. Isso cobre a parte do hipervisor, pois o neutron ainda está configurado com jumbo frames.
[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
Validação
Agora o caminho dentro da rede local tem um MTU de 1500. Se você tentar enviar um pacote maior que esse, um erro deverá ser exibido:
[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
Este ping adiciona 28 bytes ao cabeçalho, tentando enviar uma carga útil de 1.500 bytes + 28 bytes. O sistema não pode enviá-lo porque excede o MTU. Depois de diminuir a carga útil para 1472, você poderá enviar o ping com êxito em um único quadro.
[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
É assim que se resolvem os problemas de fragmentação quando a plataforma envia pacotes de 9.000 bytes para a rede, mas a fragmentação ainda ocorre em alguns componentes da rede. Agora você resolveu problemas de retransmissão, perda de pacotes, jitter, latência e outros problemas relacionados.
Quando a equipe de rede resolver os problemas de rede, você poderá reverter os comandos MTU para o valor anterior. É assim que você corrige problemas de rede sem precisar reimplantar a pilha.
Simulação ponta a ponta
Veja como simular o problema em um cenário ponta a ponta para ver como funciona. Em vez de executar ping no gateway, você pode executar ping em uma segunda instância. Você deve observar como uma incompatibilidade de MTU causa problemas, especificamente quando um aplicativo está marcando pacotes como Não-Fragmento.
Suponha que seus servidores tenham as seguintes especificações:
Servidor 1:
- Nome do host: servidor1
- IP: 10.169.252.186/24
- MTU: 1500
Servidor 2:
- Nome do host: servidor2
- IP: 10.169.252.184/24
- MTU: 8996
Conecte-se ao servidor1 e execute ping para o servidor2:
[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
Conecte-se ao server1 e execute ping para o server2 sem fragmentação com um MTU de 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
O MTU do servidor1 é 1500, e o servidor2 tem um tamanho de MTU maior que isso, portanto, um aplicativo em execução no servidor1 envia pacotes para server2 não tem problemas de fragmentação. O que acontece se o aplicativo server2 também estiver definido como Not-Fragment, mas usar um MTU de 9000?
[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
Ocorre fragmentação e os pacotes enviados foram perdidos.
Para corrigir isso, repita a correção do MTU para que ambos os servidores tenham o mesmo MTU. Como teste, reverta 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
[...]
Agora repita o ping de carga útil de 9.000 bytes sem fragmentação permitida:
[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
Solução de problemas de MTU
Esta é uma solução fácil para ajudar os administradores de rede a resolver problemas de MTU sem precisar de uma atualização de pilha para mover MTUs para frente e para trás. Todas essas configurações de MTU também são temporárias. Uma instância ou reinicialização do sistema faz com que todas as interfaces sejam revertidas ao valor original (e configurado).
Também leva apenas alguns minutos para ser executado, então espero que você ache isso útil.