AWS Site-to-Site VPN przepustowość poniżej 1 Gbps: MSS clamping i fragmentacja IPsec
Naprawa degradacji przepustowości AWS Site-to-Site VPN spowodowanej fragmentacją MTU na tunelach IPsec łączących się z GCP Cloud VPN.
Objawy
Testy iperf3 pokazują przepustowość znacznie poniżej nominalnej wartości 1.25 Gbps:
iperf3 -c 10.128.0.2 -t 30 -P 1
[ 5] 0.00-30.00 sec 1.42 GBytes 407 Mbits/sec sender
[ 5] 0.00-30.00 sec 1.40 GBytes 401 Mbits/sec receiver
Transfery dużych plików (SCP, rsync) zacinają się okresowo lub kończą znacznie wolniej niż oczekiwano. Retransmisje TCP gwałtownie rosną podczas transferów masowych:
ss -ti | grep -A 5 "10.128.0.2"
cubic wscale:7,7 rto:204 rtt:25.3/2.1 ato:40 mss:1360 pmtu:1500
retrans:0/847 rcv_space:65536
Wysoka liczba retransmisji (847 w tym przykładzie) potwierdza odrzucanie pakietów związane z fragmentacją.
Małe pakiety działają idealnie - sesje SSH są responsywne, wywołania API zwracają szybko, DNS rozwiązuje bez opóźnień. Tylko masowe transfery danych cierpią.
Metryki CloudWatch VPN potwierdzają, że tunel jest aktywny, ale transfer danych jest nieoptymalny:
aws cloudwatch get-metric-statistics \
--namespace "AWS/VPN" \
--metric-name TunnelDataOut \
--dimensions Name=VpnId,Value=vpn-0abc123def456 \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 300 \
--statistics Sum
Przyczyna
Degradacja przepustowości na tunelach IPsec wynika z rozmiaru pakietów i fragmentacji:
-
Za wysoki Path MTU - narzut IPsec powoduje fragmentację. Standardowy MTU Ethernet to 1500 bajtów. Enkapsulacja IPsec dodaje 50-73 bajty narzutu (nagłówek ESP, IV, padding, tag uwierzytelniający). Gdy instancje wysyłają pakiety o rozmiarze 1500 bajtów, gateway VPN musi je fragmentować, aby zmieścić je w tunelu. Fragmentacja na endpoincie tunelu jest kosztowna obliczeniowo i zmniejsza efektywną przepustowość o połowę, ponieważ każdy oryginalny pakiet staje się dwoma.
-
Brak konfiguracji MSS clamping na gateway VPN. Bez MSS clamping endpointy TCP negocjują maksymalny rozmiar segmentu na podstawie lokalnego MTU interfejsu (1460 bajtów dla MTU 1500). Wysyłają segmenty zbyt duże dla tunelu, powodując fragmentację na gateway VPN zamiast mniejszych segmentów od źródła.
-
Ustawiony bit DF (Don’t Fragment) powodujący ciche odrzucanie. Wiele aplikacji ustawia bit DF na pakietach. Gdy te pakiety są zbyt duże dla tunelu i fragmentacja nie jest dozwolona, są po cichu odrzucane. Host wysyłający dowiaduje się o tym dopiero gdy komunikaty ICMP “Fragmentation Needed” dotrą z powrotem - co może być blokowane przez zapory sieciowe.
-
Wyłączone TCP window scaling. Bez window scaling TCP nie jest w stanie dorównać iloczynowi przepustowości i opóźnienia tunelu. Nawet przy poprawnych ustawieniach MTU przepustowość pozostaje niska, ponieważ nadawca pauzuje czekając na potwierdzenia ACK.
-
Ograniczenie pojedynczego przepływu. AWS VPN używa ECMP per-flow między ścieżkami tunelu. Pojedynczy strumień TCP jest przypięty do jednego tunelu i nie może przekroczyć około 1.25 Gbps. Jeśli testujesz jednym strumieniem iperf3 i oczekujesz więcej - to jest maksimum.
Rozwiązanie
Krok 1: Ustawienie MTU instancji na 1400
Na instancjach EC2, które komunikują się przez VPN, zmniejsz MTU interfejsu, aby uwzględnić narzut IPsec:
# On Amazon Linux / RHEL
sudo ip link set dev eth0 mtu 1400
# Make persistent via netplan (Ubuntu)
sudo tee /etc/netplan/99-mtu.yaml <<EOF
network:
version: 2
ethernets:
eth0:
mtu: 1400
EOF
sudo netplan apply
Na instancjach GCP:
# GCP VPC MTU is set at the network level
gcloud compute networks update my-vpc --mtu 1400
Uwaga: Zmiana MTU VPC w GCP wymaga zatrzymania i ponownego uruchomienia instancji w tej sieci.
Alternatywnie, ustaw MTU per-instancja na GCP:
sudo ip link set dev ens4 mtu 1400
Krok 2: Konfiguracja MSS clamping
MSS clamping mówi TCP, aby używał mniejszego rozmiaru segmentu bez zmiany MTU interfejsu. Jest to preferowane podejście, ponieważ wpływa tylko na ruch TCP przechodzący przez tunel.
Na AWS VPN, MSS clamping konfiguruje się w opcjach tunelu:
aws ec2 modify-vpn-tunnel-options \
--vpn-connection-id vpn-0abc123def456 \
--vpn-tunnel-outside-ip-address 203.0.113.1 \
--tunnel-options "TunnelInsideIpVersion=ipv4"
AWS Site-to-Site VPN automatycznie stosuje MSS clamping do 1379 bajtów. Weryfikacja:
aws ec2 describe-vpn-connections \
--vpn-connection-ids vpn-0abc123def456 \
--query 'VpnConnections[0].Options.TunnelOptions[0]' \
--output json | grep -i mss
Na instancjach Linux możesz dodać MSS clamping oparty na iptables jako dodatkowe zabezpieczenie:
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --set-mss 1360
# Make persistent
sudo iptables-save | sudo tee /etc/iptables/rules.v4
Na GCP Cloud Router MSS clamping nie jest bezpośrednio konfigurowalny, ale gateway VPN obsługuje go automatycznie, gdy MTU tunelu jest ustawione poprawnie.
Krok 3: Weryfikacja działania Path MTU Discovery (PMTUD)
Test, czy komunikaty ICMP “Fragmentation Needed” nie są blokowane:
# From EC2 instance, test PMTUD to GCP instance
tracepath -n 10.128.0.2
Oczekiwany wynik pokazujący wykrywanie MTU:
1?: [LOCALHOST] pmtu 1500
1: 10.0.1.1 0.5ms pmtu 1400
2: 169.254.10.1 5.2ms pmtu 1400
3: 10.128.0.2 25.1ms reached
Resume: pmtu 1400 hops 3 back 3
Jeśli PMTUD nie działa (brak redukcji pmtu), sprawdź Security Groups i NACLe:
# Ensure ICMP type 3 (Destination Unreachable) is allowed inbound
aws ec2 describe-security-groups \
--group-ids sg-0abc123 \
--query 'SecurityGroups[0].IpPermissions[?IpProtocol==`icmp`]'
Dodaj ICMP type 3, jeśli brakuje:
aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123 \
--protocol icmp \
--port -1 \
--cidr 10.128.0.0/16
Na GCP upewnij się, że reguły firewalla przepuszczają ICMP:
gcloud compute firewall-rules create allow-icmp-pmtud \
--network my-vpc \
--allow icmp \
--source-ranges 10.0.0.0/8 \
--direction INGRESS
Krok 4: Test z różnymi rozmiarami pakietów
Uruchom iperf3 z jawnym MSS, aby znaleźć optymalny rozmiar segmentu:
# Test with MSS 1360 (accounting for IPsec overhead)
iperf3 -c 10.128.0.2 -t 10 -M 1360
# Compare with default (likely 1460)
iperf3 -c 10.128.0.2 -t 10
# Test UDP to isolate from TCP behavior
iperf3 -c 10.128.0.2 -t 10 -u -b 1G -l 1360
Jeśli MSS 1360 daje znacząco lepszą przepustowość niż domyślna wartość, rozwiązanie jest potwierdzona.
Krok 5: Włączenie TCP window scaling
Sprawdź, czy window scaling jest włączone na instancjach:
sysctl net.ipv4.tcp_window_scaling
Jeśli wyłączone, włącz:
sudo sysctl -w net.ipv4.tcp_window_scaling=1
sudo sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sudo sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"
# Make persistent
echo "net.ipv4.tcp_window_scaling = 1" | sudo tee -a /etc/sysctl.d/99-vpn-tuning.conf
echo "net.ipv4.tcp_rmem = 4096 87380 16777216" | sudo tee -a /etc/sysctl.d/99-vpn-tuning.conf
echo "net.ipv4.tcp_wmem = 4096 65536 16777216" | sudo tee -a /etc/sysctl.d/99-vpn-tuning.conf
sudo sysctl --system
Krok 6: Test przepustowości wielowątkowej
Jeśli przepustowość jednego strumienia wynosi około 1.1-1.25 Gbps (limit per-tunel), użyj równoległych przepływów, aby wysycić wiele tuneli:
# 4 parallel streams
iperf3 -c 10.128.0.2 -t 30 -P 4
Jeśli test wielostrumieniowy pokazuje znaczącą poprawę, wąskim gardłem jest ograniczenie ECMP per-flow, a nie fragmentacja. W tym przypadku upewnij się, że Twój workload naturalnie generuje wiele przepływów TCP (co ma miejsce w większości aplikacji produkcyjnych).
Krok 7: Monitoring retransmisji TCP po naprawie
# Watch retransmits in real-time
watch -n 1 'ss -ti dst 10.128.0.0/16 | grep retrans'
Liczby retransmisji powinny pozostać na zero lub bliskie zera podczas masowych transferów.
Walidacja
Przeprowadź kompleksowy test przepustowości po zastosowaniu poprawek:
iperf3 -c 10.128.0.2 -t 60 -P 1 --json | jq '.end.sum_sent.bits_per_second / 1000000'
Oczekiwany wynik: ponad 1100 Mbps dla jednego strumienia.
Weryfikacja, że fragmentacja nie występuje:
# Check for fragmentation on the instance
cat /proc/net/snmp | grep -A 1 "Ip:"
Sprawdź wartości FragCreates i FragFails - nie powinny rosnąć podczas transferów.
Test z rzeczywistym obciążeniem:
# Large file transfer
time scp -o "Compression=no" /tmp/testfile-1G user@10.128.0.2:/tmp/
# Expected: ~8-9 seconds for 1 GB at 1 Gbps+
Uruchom tracepath, aby potwierdzić działanie PMTUD:
tracepath -n 10.128.0.2
Wynik powinien pokazywać pmtu 1400 (lub skonfigurowaną wartość) bez znaczników asymm lub !H.
Sprawdzenie, że retransmisje TCP są znikome podczas długotrwałego transferu:
# Start a transfer in background
iperf3 -c 10.128.0.2 -t 60 &
# Monitor retransmits
ss -ti dst 10.128.0.2 | grep retrans
Oczekiwany wynik: retrans:0/0 lub bardzo niskie jednocyfrowe wartości.
Potrzebujesz pomocy z łącznością multi-cloud?
Umów darmową 30-minutową rozmowę. Zdiagnozujemy problem z połączeniem i zarekomendujemy właściwe rozwiązanie.