AWS 기술 블로그

AWS에서의 MTU, MSS 이해

들어가며

레거시 이더넷 네트워크는 IEEE 802.3 표준에 따라 1500바이트의 MTU(Maximum Transmission Unit)를 기본값으로 사용합니다. 반면 AWS 클라우드 인프라는 9001바이트 점보 프레임(Jumbo Frames)을 지원함으로써 프레임 오버헤드 비율을 최소화하고 네트워크 처리량(throughput)을 극대화합니다.

하지만 하이브리드 클라우드 환경과 같은 비대칭 MTU 구성에서 MTU와 MSS(Maximum Segment Size) 설정이 적절히 고려되지 않을 경우, 네트워크 연결 중단이나 성능 저하가 발생할 수 있습니다. 또한 대용량 데이터 전송 시 경로 상의 작은 MTU로 인해 패킷 단편화가 발생하면 CPU 오버헤드가 증가하고 전체 네트워크 처리량이 현저히 감소할 수 있습니다. 더불어 블랙홀 라우팅 또는 방화벽 정책으로 PMTUD(Path MTU Discovery) 실패가 발생하면 특정 크기 이상의 패킷이 손실되는 문제가 발생할 수 있습니다.

이 글에서는 엔터프라이즈 네트워크 설계자와 클라우드 아키텍트가 실제 환경에서 마주하는 시나리오를 바탕으로, MTU와 MSS 협상(MSS negotiation) 개념, 네트워크 중간 장치에서 구현되는 MSS 클램핑(MSS clamping) 메커니즘, 그리고 ICMP를 활용한 PMTUD 프로토콜의 작동 원리를 알아보겠습니다.

목차

MTU(Maximum Transmission Unit)와 MSS(Maximum Segment Size)의 개념

그림 1: MTU와 MSS의 경계와 구성 요소

MTU는 OSI 모델 3계층(네트워크 계층)에서 정의되는 IP 패킷의 최대 크기로, 네트워크 인터페이스가 단일 IP 패킷으로 전송할 수 있는 최대 바이트 수를 의미합니다. 이 값은 IP 헤더와 상위 계층 페이로드(TCP/UDP 헤더 + 애플리케이션 데이터)를 포함하지만, Layer 2 이더넷 헤더(14바이트)와 FCS(4바이트)는 포함하지 않습니다. 표준 이더넷 환경에서 MTU는 1500바이트로, 이는 전체 이더넷 프레임 크기 1518바이트에서 Layer 2 오버헤드 18바이트를 제외한 값입니다.

MSS는 OSI 모델 4계층(전송 계층)에서 정의되는 TCP 세그먼트의 최대 데이터 크기로, TCP 헤더를 제외한 순수 애플리케이션 데이터만을 의미합니다. MSS는 TCP 3-way 핸드셰이크 과정에서 양측이 서로 광고한 MSS 값 중 더 작은 값으로 결정되어 해당 TCP 세션에서 사용됩니다.

AWS 클라우드 환경에서의 MSS/MTU 파라미터 검증을 위한 테스트 환경 구성

단일 VPC(Virtual Private Cloud) 환경에 Amazon Linux 2023 AMI 기반의 EC2 인스턴스 두 대를 배포하여 TCP 3-way 핸드셰이크 과정에서 발생하는 MTU/MSS 협상 메커니즘을 분석해보겠습니다.

EC2 인스턴스 간의 네트워크 트래픽 분석을 위해 AWS VPC 트래픽 미러링(VPC Traffic Mirroring) 기능을 활용하여 패킷을 캡처할 예정입니다. VPC 트래픽 미러링은 VXLAN(Virtual Extensible LAN) 프로토콜로 미러링된 패킷을 캡슐화하기 때문에, 분석 시에는 VXLAN 헤더를 고려한 패킷 디코딩 작업이 필요합니다. VPC 트래픽 미러링에 대한 자세한 내용은 다음을 참고하시기 바랍니다.

그림 2: EC2 인스턴스 간 직접 통신을 통한 MTU/MSS 파라미터 검증 아키텍처

먼저 클라이언트와 서버 인스턴스의 네트워크 인터페이스가 모두 9001바이트 MTU로 설정되어 점보 프레임을 지원하는지 확인하겠습니다. 이는 VPC 내 EC2 인스턴스에 기본적으로 할당되는 점보 프레임 MTU 값이며, 인스턴스 유형에 따라 지원되는 최대 MTU 값은 달라질 수 있으므로 주의해야 합니다.

[ec2-user@client ~]$ ifconfig
ens5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 10.200.31.74  netmask 255.255.255.0  broadcast 10.200.31.255

클라이언트 인스턴스의 네트워크 인터페이스 MTU 파라미터 설정 확인

[ec2-user@server ~]$ ifconfig
ens5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
        inet 10.200.61.183  netmask 255.255.255.0  broadcast 10.200.61.255

서버 인스턴스의 네트워크 인터페이스 MTU 파라미터 설정 확인

Amazon EC2 점보 프레임 환경에서의 TCP 연결 수립 및 데이터 전송 과정

클라이언트 인스턴스가 서버 인스턴스의 HTTP 서비스로 TCP 연결을 수립하고 데이터를 전송하는 과정을 살펴보겠습니다. 각 인스턴스에 연결된 ENI(Elastic Network Interface)의 트래픽을 VPC 트래픽 미러링을 통해 개별 미러 타겟으로 전송하고, 이를 tcpdump로 캡처할 것입니다. 이렇게 수집된 패킷 데이터를 통해 TCP 3-way 핸드셰이크 과정에서 교환되는 SYN, SYN-ACK 패킷의 MSS 옵션 값과 실제 데이터 전송 시 페이로드 크기를 정밀하게 분석할 수 있습니다.

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..30000})" http://10.200.61.183/

클라이언트에서 30,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [S], seq 2195535102, win 62727, options [mss 8961,...], length 0
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [S.], seq 3315669066, ack 2195535103, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [P.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [P.], seq 26848:30150, ack 1, win 491, options [...], length 3302: HTTP
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [.], ack 26848, win 380, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [.], ack 30150, win 358, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [P.], seq 1:261, ack 30150, win 442, options [...], length 260: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], ack 261, win 489, options [...], length 0
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [F.], seq 30150, ack 261, win 489, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [F.], seq 261, ack 30151, win 442, options [...], length 0
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], ack 262, win 489, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [S], seq 2195535102, win 62727, options [mss 8961,...], length 0
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [S.], seq 3315669066, ack 2195535103, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [P.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [P.], seq 26848:30150, ack 1, win 491, options [...], length 3302: HTTP
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [.], ack 26848, win 380, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [.], ack 30150, win 358, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [P.], seq 1:261, ack 30150, win 442, options [...], length 260: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], ack 261, win 489, options [...], length 0
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [F.], seq 30150, ack 261, win 489, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.56756: Flags [F.], seq 261, ack 30151, win 442, options [...], length 0
IP 10.200.31.74.56756 > 10.200.61.183.http: Flags [.], ack 262, win 489, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 3: TCP 3-way 핸드셰이크 과정의 MSS 협상과 HTTP POST 데이터 전송 시퀀스 다이어그램

TCP 3-way 핸드셰이크 과정에서 클라이언트와 서버는 SYN 및 SYN-ACK 패킷의 TCP 옵션 필드를 통해 각자 지원 가능한 MSS 값을 광고했습니다. 본 테스트 환경에서는 클라이언트와 서버 모두 점보 프레임 MTU 9001바이트에서 IP 헤더(20바이트)와 TCP 헤더(20바이트)를 제외한 8961바이트(MTU 9001 – IP/TCP 헤더 40바이트)를 MSS 값으로 광고했습니다. 이후 클라이언트는 30,000바이트의 페이로드를 8949바이트(MSS 8961 – TCP 옵션 필드 12바이트) 단위로 분할하여 서버에 전송했습니다.

MTU 비대칭 환경에서의 TCP 연결 수립 및 데이터 전송 과정 분석

이번에는 클라이언트의 MTU를 표준 이더넷 규격인 1500바이트로 하향 조정한 환경을 구성하겠습니다. 이후 5,000바이트 페이로드를 포함한 HTTP POST 요청을 전송하여 MSS 협상 과정과 세그먼트 분할 메커니즘을 검증할 것입니다. 이러한 구성에서 클라이언트는 1460바이트 MSS(MTU 1500 – IP/TCP 헤더 40바이트)를 광고하게 되며, 서버와의 통신 과정에서 이 제한된 MSS 값이 실제로 어떻게 적용되는지 패킷 캡처를 통해 분석하겠습니다.

그림 4: MTU 비대칭 환경에서의 EC2 인스턴스 간 통신 아키텍처

구분 IP 주소 MTU 파라미터 설정
클라이언트 10.200.31.74 1500
서버 10.200.61.183 9001

표 1: 인스턴스 구성 정보

[ec2-user@client ~]$ sudo ip link set dev ens5 mtu 1500

네트워크 인터페이스의 MTU 값 조정 명령어 예(인터페이스명: ens5, MTU: 1500)

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..5000})" http://10.200.61.183/

클라이언트에서 5,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [S], seq 2113476558, win 64240, options [mss 1460,...], length 0
IP 10.200.61.183.http > 10.200.31.74.36170: Flags [S.], seq 1878899386, ack 2113476559, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], ack 1, win 502, options [...], length 0
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], seq 1:1449, ack 1, win 502, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], seq 1449:2897, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], seq 2897:4345, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [P.], seq 4345:5149, ack 1, win 502, options [...], length 804: HTTP
IP 10.200.61.183.http > 10.200.31.74.36170: Flags [.], ack 5149, win 450, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.36170: Flags [P.], seq 1:261, ack 5149, win 450, options [...], length 260: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], ack 261, win 501, options [...], length 0
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [F.], seq 5149, ack 261, win 501, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.36170: Flags [F.], seq 261, ack 5150, win 450, options [...], length 0
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], ack 262, win 501, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [S], seq 2113476558, win 64240, options [mss 1460,...], length 0
IP 10.200.61.183.http > 10.200.31.74.36170: Flags [S.], seq 1878899386, ack 2113476559, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], ack 1, win 502, options [...], length 0
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], seq 1:1449, ack 1, win 502, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], seq 1449:2897, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], seq 2897:4345, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [P.], seq 4345:5149, ack 1, win 502, options [...], length 804: HTTP
IP 10.200.61.183.http > 10.200.31.74.36170: Flags [.], ack 5149, win 450, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.36170: Flags [P.], seq 1:261, ack 5149, win 450, options [...], length 260: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], ack 261, win 501, options [...], length 0
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [F.], seq 5149, ack 261, win 501, options [...], length 0
IP 10.200.61.183.http > 10.200.31.74.36170: Flags [F.], seq 261, ack 5150, win 450, options [...], length 0
IP 10.200.31.74.36170 > 10.200.61.183.http: Flags [.], ack 262, win 501, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 5: MTU 비대칭 환경에서의 MSS 협상 및 세그먼트 분할 시퀀스 다이어그램

TCP 3-way 핸드셰이크 과정에서 클라이언트는 MSS 1460바이트를, 서버는 MSS 8961바이트를 상호 광고합니다. TCP 표준(RFC 793)에 명시된 바와 같이, 실제 통신에는 두 값 중 더 작은 1460바이트가 적용됩니다. 클라이언트는 이 협상된 MSS 값에서 TCP 옵션 필드(타임스탬프 등)로 인한 오버헤드 12바이트를 추가로 고려하여 실제 데이터 세그먼트 크기를 1448바이트로 조정합니다. 결과적으로 5,000바이트 페이로드는 4개의 TCP 세그먼트로 분할되어 전송됩니다.

반대 시나리오, 즉 클라이언트의 MTU가 9001바이트이고 서버의 MTU가 1500바이트인 경우에도 동일한 원리가 적용됩니다. TCP 연결 수립 과정에서 클라이언트와 서버는 자신의 로컬 MTU를 기반으로 MSS 값을 광고합니다. 이에 따라 클라이언트는 점보 프레임 기반의 MSS 8961바이트를, 서버는 표준 이더넷 기반의 MSS 1460바이트를 광고합니다. TCP 프로토콜 명세에 따라 두 값 중 더 작은 1460바이트가 최종 MSS로 선택되어 세그먼트 크기를 결정하게 됩니다. 결과적으로 클라이언트는 자신의 MTU가 더 크더라도 서버가 처리 가능한 크기로 데이터를 분할하여 전송하게 됩니다.

그림 6: MTU 비대칭 환경에서의 MSS 협상 및 TCP 세그먼트 분할 메커니즘

ELB(Elastic Load Balancing) 환경에서의 MSS 클램핑

MSS 클램핑(MSS Clamping)은 라우터, 방화벽, 로드밸런서 등의 네트워크 중간 장치가 TCP SYN 및 SYN-ACK 패킷의 MSS 필드를 실시간으로 검사하고, 해당 장치의 인터페이스 MTU 또는 관리자가 설정한 임계값 보다 큰 MSS 값을 하향 조정하는 기술입니다.

이 기술은 네트워크 경로상의 MTU보다 큰 TCP 세그먼트 전송으로 인한 IP 단편화(Fragmentation)를 사전에 방지합니다. 또한 VPN 터널링과 같이 캡슐화로 인해 MTU가 감소하는 환경에서도 추가 헤더 오버헤드를 고려하여 적절한 세그먼트 크기를 보장함으로써 네트워크 성능 저하와 패킷 손실을 예방합니다.

AWS에서는 Network Load Balancer(NLB), Gateway Load Balancer(GWLB), Transit Gateway와 같은 하이퍼플레인(Hyperplane) 기반 네트워크 서비스들이 MSS 클램핑을 지원합니다.

AWS Network Load Balancer

클라이언트(MSS=8961), 서버(MSS=8961) 환경에서 NLB의 MSS 클램핑 검증

이제 NLB(Network Load Balancer)에 구현된 MSS 클램핑 메커니즘을 패킷 레벨에서 분석하여 검증해보겠습니다.

그림 7: MSS 클램핑 검증을 위한 NLB 기반 EC2 인스턴스 간 TCP 통신 아키텍처

클라이언트에서 NLB를 경유하여 서버의 HTTP 서비스로 연결하고 데이터를 전송했습니다. 이 과정에서 VPC 트래픽 미러링 기능을 활용하여 각 인스턴스의 ENI에서 발생하는 트래픽을 전용 모니터링 인스턴스로 미러링하고, tcpdump를 통해 패킷을 캡처하여 패킷 헤더와 TCP 옵션 필드를 확인했습니다.

구분 IP 주소 MTU 파라미터 설정
클라이언트 10.200.31.74 9001
서버 10.200.61.89 9001

표 2: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..30000})" http://<nlb-dns-name>

클라이언트에서 30,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [S], seq 3607538628, win 62727, options [mss 8961,...], length 0
IP 10.200.31.5.http > 10.200.31.74.37170: Flags [S.], seq 4042676183, ack 3607538629, win 62643, options [mss 8365,...], length 0
IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [.], seq 1:8354, ack 1, win 491, options [...], length 8353: HTTP: POST / HTTP/1.1
IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [.], seq 8354:16707, ack 1, win 491, options [...], length 8353: HTTP
IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [P.], seq 16707:25060, ack 1, win 491, options [...], length 8353: HTTP
IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [P.], seq 25060:30194, ack 1, win 491, options [...], length 5134: HTTP
IP 10.200.31.5.http > 10.200.31.74.37170: Flags [.], ack 25060, win 394, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.37170: Flags [.], ack 30194, win 370, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.37170: Flags [P.], seq 1:254, ack 30194, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [F.], seq 30194, ack 254, win 490, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.37170: Flags [F.], seq 254, ack 30195, win 442, options [...], length 0
IP 10.200.31.74.37170 > 10.200.31.5.http: Flags [.], ack 255, win 490, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [S], seq 3607538628, win 62727, options [mss 8365,...], length 0
IP 10.200.61.89.http > 10.200.31.5.24743: Flags [S.], seq 4042676183, ack 3607538629, win 62643, options [mss 8961,...], length 0
IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [.], seq 1:8354, ack 1, win 491, options [...], length 8353: HTTP: POST / HTTP/1.1
IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [.], seq 8354:16707, ack 1, win 491, options [...], length 8353: HTTP
IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [P.], seq 16707:25060, ack 1, win 491, options [...], length 8353: HTTP
IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [P.], seq 25060:30194, ack 1, win 491, options [...], length 5134: HTTP
IP 10.200.61.89.http > 10.200.31.5.24743: Flags [.], ack 25060, win 394, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.24743: Flags [.], ack 30194, win 370, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.24743: Flags [P.], seq 1:254, ack 30194, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [F.], seq 30194, ack 254, win 490, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.24743: Flags [F.], seq 254, ack 30195, win 442, options [...], length 0
IP 10.200.31.5.24743 > 10.200.61.89.http: Flags [.], ack 255, win 490, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 8: NLB의 MSS 클램핑이 적용된 MSS 협상 및 HTTP POST 데이터 전송 시퀀스 다이어그램

MTU 9001바이트로 설정된 클라이언트는 동일한 MTU 환경의 서버를 대상으로 하는 NLB에 30,000바이트 페이로드를 포함한 HTTP POST 요청을 전송했습니다. TCP 3-way 핸드셰이크 과정에서 클라이언트와 서버는 SYN/SYN-ACK 패킷의 TCP 옵션 필드를 통해 MSS 8961바이트(MTU 9001 – IP/TCP 헤더 40바이트)를 광고했습니다. 그러나 NLB는 MSS 클램핑을 수행하여 양방향으로 전달되는 MSS 값을 8365바이트로 하향 조정했습니다.

이후 데이터 전송 단계에서 클라이언트는 TCP 옵션 헤더 오버헤드 12바이트를 고려하여 페이로드를 8353바이트 단위로 세그먼트화하여 NLB로 전송했으며, NLB 타겟 그룹에 등록된 서버에서도 동일한 크기의 세그먼트로 수신되었습니다.

클라이언트(MSS=1460), 서버(MSS=8961) 환경에서 NLB의 MSS 클램핑 검증

다음으로, 인터넷 환경의 클라이언트가 퍼블릭 서브넷에 배치된 NLB를 통해 프라이빗 서브넷의 서버와 통신하는 시나리오를 시뮬레이션했습니다. 이를 위해 클라이언트의 네트워크 인터페이스 MTU를 표준 이더넷 규격인 1500바이트로 설정하고, MTU 비대칭 환경에서 NLB의 MSS 클램핑 동작 메커니즘과 TCP 세그먼트화 패턴의 변화를 분석해보겠습니다.

구분 IP 주소 MTU 파라미터 설정
클라이언트 10.200.31.74 1500
서버 10.200.61.89 9001

표 3: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..5000})" http://<nlb-dns-name>

클라이언트에서 5,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [S], seq 3100008435, win 64240, options [mss 1460,...], length 0
IP 10.200.31.5.http > 10.200.31.74.37564: Flags [S.], seq 693252362, ack 3100008436, win 62643, options [mss 8365,...], length 0
IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [.], ack 1, win 502, options [...], length 0
IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [.], seq 1:1449, ack 1, win 502, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [.], seq 1449:2897, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [.], seq 2897:4345, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [P.], seq 4345:5193, ack 1, win 502, options [...], length 848: HTTP
IP 10.200.31.5.http > 10.200.31.74.37564: Flags [.], ack 1449, win 479, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.37564: Flags [.], ack 5193, win 450, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.37564: Flags [P.], seq 1:254, ack 5193, win 450, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [.], ack 254, win 501, options [...], length 0
IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [F.], seq 5193, ack 254, win 501, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.37564: Flags [F.], seq 254, ack 5194, win 450, options [...], length 0
IP 10.200.31.74.37564 > 10.200.31.5.http: Flags [.], ack 255, win 501, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [S], seq 3100008435, win 64240, options [mss 1460,...], length 0
IP 10.200.61.89.http > 10.200.31.5.6981: Flags [S.], seq 693252362, ack 3100008436, win 62643, options [mss 8961,...], length 0
IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [.], ack 1, win 502, options [...], length 0
IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [.], seq 1:1449, ack 1, win 502, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [.], seq 1449:2897, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [.], seq 2897:4345, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [P.], seq 4345:5193, ack 1, win 502, options [...], length 848: HTTP
IP 10.200.61.89.http > 10.200.31.5.6981: Flags [.], ack 1449, win 479, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.6981: Flags [.], ack 5193, win 450, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.6981: Flags [P.], seq 1:254, ack 5193, win 450, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [.], ack 254, win 501, options [...], length 0
IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [F.], seq 5193, ack 254, win 501, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.6981: Flags [F.], seq 254, ack 5194, win 450, options [...], length 0
IP 10.200.31.5.6981 > 10.200.61.89.http: Flags [.], ack 255, win 501, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 9: MTU 비대칭 환경에서 NLB의 MSS 클램핑 적용 시 MSS 협상 및 데이터 전송 시퀀스 다이어그램

클라이언트가 1460바이트 MSS를 광고했을 때, NLB는 클라이언트의 SYN 패킷 MSS 값이 자체 클램핑 임계값인 8365바이트보다 작았기 때문에 이 값을 변경하지 않고 그대로 서버에 전송했습니다. 반면 서버의 SYN-ACK 패킷에서 광고된 MSS 8961바이트는 8365바이트로 클램핑하여 클라이언트에 전달했습니다.

결과적으로 클라이언트는 TCP 표준에 따라 자신이 광고한 MSS 값과 NLB로부터 수신한 클램핑된 MSS 값 중 작은 값인 1460바이트를 선택했습니다. 이후 TCP 옵션 헤더 12바이트를 고려한 실제 페이로드를 1448바이트 단위로 세그먼트화하여 HTTP POST 요청을 전송했습니다.

클라이언트(MSS=8961), 서버(MSS=1460) 환경에서 NLB의 MSS 클램핑 검증

이 시나리오에서는 서버 측의 MTU가 전체 경로의 MSS 값을 결정합니다. TCP 연결 수립 과정에서 서버가 광고하는 MSS 값인 1460바이트(MTU 1500 – IP/TCP 헤더 40바이트)가 세션의 최종 MSS로 결정될 것으로 예상할 수 있습니다.

구분 IP 주소 MTU 파라미터 설정
클라이언트 10.200.31.74 9001
서버 10.200.61.89 1500

표 4: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..5000})" http://<nlb-dns-name>

클라이언트에서 5,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [S], seq 3219726282, win 62727, options [mss 8961,...], length 0
IP 10.200.31.5.http > 10.200.31.74.40340: Flags [S.], seq 1371597539, ack 3219726283, win 65160, options [mss 1460,...], length 0
IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [.], seq 1:1449, ack 1, win 491, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [.], seq 1449:2897, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [.], seq 2897:4345, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [P.], seq 4345:5193, ack 1, win 491, options [...], length 848: HTTP
IP 10.200.31.5.http > 10.200.31.74.40340: Flags [.], ack 2897, win 494, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.40340: Flags [.], ack 5193, win 481, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.40340: Flags [P.], seq 1:254, ack 5193, win 501, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [F.], seq 5193, ack 254, win 490, options [...], length 0
IP 10.200.31.5.http > 10.200.31.74.40340: Flags [F.], seq 254, ack 5194, win 501, options [...], length 0
IP 10.200.31.74.40340 > 10.200.31.5.http: Flags [.], ack 255, win 490, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [S], seq 3219726282, win 62727, options [mss 8365,...], length 0
IP 10.200.61.89.http > 10.200.31.5.26663: Flags [S.], seq 1371597539, ack 3219726283, win 65160, options [mss 1460,...], length 0
IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [.], seq 1:1449, ack 1, win 491, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [.], seq 1449:2897, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [.], seq 2897:4345, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [P.], seq 4345:5193, ack 1, win 491, options [...], length 848: HTTP
IP 10.200.61.89.http > 10.200.31.5.26663: Flags [.], ack 2897, win 494, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.26663: Flags [.], ack 5193, win 481, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.26663: Flags [P.], seq 1:254, ack 5193, win 501, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [F.], seq 5193, ack 254, win 490, options [...], length 0
IP 10.200.61.89.http > 10.200.31.5.26663: Flags [F.], seq 254, ack 5194, win 501, options [...], length 0
IP 10.200.31.5.26663 > 10.200.61.89.http: Flags [.], ack 255, win 490, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 10: 역방향 MTU 비대칭 환경에서 NLB의 MSS 클램핑 적용 시 MSS 협상 및 데이터 전송 시퀀스 다이어그램

패킷 캡처 분석 결과, NLB는 클라이언트의 SYN 패킷에서 광고된 MSS 8961바이트를 8365바이트로 클램핑하여 서버에 전달했습니다. 서버는 SYN-ACK 패킷에서 MSS 1460바이트를 광고하여 NLB에 응답했고, NLB는 서버의 SYN-ACK 패킷 MSS 값이 자체 클램핑 임계값인 8365바이트보다 작았기 때문에 이 값을 변경하지 않고 그대로 클라이언트에 전달했습니다.

결과적으로 클라이언트는 자신의 MSS 8961바이트와 서버의 MSS 1460바이트 중 더 작은 값인 1460바이트를 최종 MSS로 선택하고, TCP 옵션 헤더 오버헤드를 고려하여 실제 페이로드를 1448바이트 단위로 세그먼트화하여 HTTP POST 요청을 전송했습니다.

NLB 환경에서의 MSS 클램핑 메커니즘 분석 결과

NLB를 경유하는 클라이언트-서버 간 통신에서는 경로상 최소 MTU가 전체 네트워크 성능을 결정한다는 TCP의 기본 원리를 확인했습니다. NLB는 네트워크 경로의 MTU 제약을 고려하여 TCP 연결 수립 단계에서 MSS를 8365바이트로 클램핑합니다. 또한 클라이언트로부터 전송된 세그먼트화된 페이로드는 시퀀스 번호와 TCP 플래그 정보를 완전히 보존한 채 서버에 투명하게 전달되는 것을 검증할 수 있었습니다.

AWS Application Load Balancer

클라이언트(MSS=8961), 서버(MSS=8961) 환경에서 ALB의 MSS 클램핑 검증

이제 L7(응용 계층)에서 동작하는 ALB가 NLB와 마찬가지로 MSS 클램핑을 지원하는지 패킷 레벨에서 분석하여 검증해보겠습니다. ALB는 L7 프록시로 동작하므로 NLB와 달리 클라이언트-ALB 구간과 ALB-서버 구간에서 각각 독립적인 TCP 연결을 유지합니다. 이러한 특성으로 인해 MSS 클램핑이 발생하지 않을 것으로 예상됩니다.

그림 11: MSS 클램핑 검증을 위한 ALB 기반 EC2 인스턴스 간 TCP 통신 아키텍처

구분 IP 주소 MTU 파라미터 설정
클라이언트 10.200.31.74 9001
서버 10.200.61.51 9001

표 5: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..30000})" http://<alb-dns-name>

클라이언트에서 30,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [S], seq 1284899534, win 62727, options [mss 8961,...], length 0
IP 10.200.31.69.http > 10.200.31.74.54428: Flags [S.], seq 2944742339, ack 1284899535, win 26847, options [mss 8961,...], length 0
IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [P.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.69.http > 10.200.31.74.54428: Flags [.], ack 8950, win 175, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.54428: Flags [.], ack 17899, win 245, options [...], length 0
IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [P.], seq 26848:30197, ack 1, win 491, options [...], length 3349: HTTP
IP 10.200.31.69.http > 10.200.31.74.54428: Flags [.], ack 26848, win 315, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.54428: Flags [.], ack 30197, win 384, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.54428: Flags [P.], seq 1:276, ack 30197, win 384, options [...], length 275: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [.], ack 276, win 489, options [...], length 0
IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [F.], seq 30197, ack 276, win 489, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.54428: Flags [F.], seq 276, ack 30198, win 384, options [...], length 0
IP 10.200.31.74.54428 > 10.200.31.69.http: Flags [.], ack 277, win 489, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [S], seq 1686154361, win 26883, options [mss 8961,...], length 0
IP 10.200.61.51.http > 10.200.31.69.51592: Flags [S.], seq 2866386463, ack 1686154362, win 62643, options [mss 8961,...], length 0
IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [.], ack 1, win 106, options [...], length 0
IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [.], seq 1:8950, ack 1, win 106, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [P.], seq 8950:9354, ack 1, win 106, options [...], length 404: HTTP
IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [.], seq 9354:18303, ack 1, win 106, options [...], length 8949: HTTP
IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [P.], seq 18303:25738, ack 1, win 106, options [...], length 7435: HTTP
IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [P.], seq 25738:30334, ack 1, win 106, options [...], length 4596: HTTP
IP 10.200.61.51.http > 10.200.31.69.51592: Flags [.], ack 9354, win 442, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.51592: Flags [.], ack 25738, win 378, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.51592: Flags [.], ack 30334, win 351, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.51592: Flags [P.], seq 1:252, ack 30334, win 442, options [...], length 251: HTTP: HTTP/1.1 200 OK
IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [.], ack 252, win 110, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.51592: Flags [F.], seq 252, ack 30334, win 442, options [...], length 0
IP 10.200.31.69.51592 > 10.200.61.51.http: Flags [F.], seq 30334, ack 253, win 110, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.51592: Flags [.], ack 30335, win 442, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 12: ALB 환경에서의 MSS 협상 및 HTTP POST 데이터 전송 시퀀스 다이어그램

패킷 캡처 분석 결과, 클라이언트와 서버 간 통신에서 양측 모두 점보 프레임을 지원하는 MSS 8961바이트(MTU 9001 – IP/TCP 헤더 40바이트)를 광고하는 것을 확인했습니다. ALB는 NLB와 달리 L7 프록시 모델로 동작하여 클라이언트-ALB 구간과 ALB-서버 구간에서 완전히 독립적인 TCP 연결을 수립합니다. 이로 인해 두 연결 구간에서 서로 다른 소스/목적지 포트와 시퀀스 번호가 사용되며, 각 연결 구간별로 독립적인 MSS 협상 과정이 이루어집니다.

또한 ALB는 클라이언트로부터 수신한 HTTP 요청을 애플리케이션 계층에서 완전히 파싱하고 재구성한 후 서버로 전송합니다. 이 과정에서 세그먼트 분할 패턴이 변경되며, X-Forwarded-For와 같은 HTTP 헤더를 추가하거나 기존 헤더를 수정하기 때문에 클라이언트가 전송한 원본 데이터 크기(30,196바이트)와 ALB가 서버로 전달하는 데이터 크기(30,333바이트) 간에 차이가 발생할 수 있습니다.

클라이언트(MSS=1460), 서버(MSS=8961) 환경에서 ALB의 MSS 클램핑 검증

다음으로, MTU 비대칭 환경을 시뮬레이션하기 위해 클라이언트의 네트워크 인터페이스 MTU를 표준 이더넷 규격인 1500바이트로 설정했습니다.

구분 IP 주소 MTU 파라미터 설정
클라이언트 10.200.31.74 1500
서버 10.200.61.51 9001

표 6: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..20000})" http://<alb-dns-name>

클라이언트에서 20,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [S], seq 2708825074, win 64240, options [mss 1460,...], length 0
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [S.], seq 2887993719, ack 2708825075, win 26847, options [mss 8961,...], length 0
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], ack 1, win 502, options [...], length 0
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 1:1449, ack 1, win 502, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 1449:2897, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 2897:4345, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 4345:5793, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [P.], seq 5793:7241, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 7241:8689, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 8689:10137, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 10137:11585, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 11585:13033, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [P.], seq 13033:14481, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [.], ack 2897, win 128, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [.], ack 7241, win 198, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [.], ack 10137, win 268, options [...], length 0
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 14481:15929, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 15929:17377, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [.], ack 14481, win 302, options [...], length 0
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], seq 17377:18825, ack 1, win 502, options [...], length 1448: HTTP
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [P.], seq 18825:20197, ack 1, win 502, options [...], length 1372: HTTP
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [.], ack 15929, win 313, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [.], ack 20197, win 383, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [P.], seq 1:276, ack 20197, win 383, options [...], length 275: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], ack 276, win 501, options [...], length 0
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [F.], seq 20197, ack 276, win 501, options [...], length 0
IP 10.200.31.69.http > 10.200.31.74.59972: Flags [F.], seq 276, ack 20198, win 383, options [...], length 0
IP 10.200.31.74.59972 > 10.200.31.69.http: Flags [.], ack 277, win 501, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.69.8938 > 10.200.61.51.http: Flags [S], seq 2399809552, win 26883, options [mss 8961,...], length 0
IP 10.200.61.51.http > 10.200.31.69.8938: Flags [S.], seq 980512255, ack 2399809553, win 62643, options [mss 8961,...], length 0
IP 10.200.31.69.8938 > 10.200.61.51.http: Flags [.], ack 1, win 106, options [...], length 0
IP 10.200.31.69.8938 > 10.200.61.51.http: Flags [.], seq 1:8950, ack 1, win 106, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.69.8938 > 10.200.61.51.http: Flags [P.], seq 8950:9354, ack 1, win 106, options [...], length 404: HTTP
IP 10.200.31.69.8938 > 10.200.61.51.http: Flags [.], seq 9354:18303, ack 1, win 106, options [...], length 8949: HTTP
IP 10.200.31.69.8938 > 10.200.61.51.http: Flags [P.], seq 18303:20334, ack 1, win 106, options [...], length 2031: HTTP
IP 10.200.61.51.http > 10.200.31.69.8938: Flags [.], ack 9354, win 442, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.8938: Flags [.], ack 20334, win 410, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.8938: Flags [P.], seq 1:252, ack 20334, win 442, options [...], length 251: HTTP: HTTP/1.1 200 OK
IP 10.200.31.69.8938 > 10.200.61.51.http: Flags [.], ack 252, win 110, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.8938: Flags [F.], seq 252, ack 20334, win 442, options [...], length 0
IP 10.200.31.69.8938 > 10.200.61.51.http: Flags [F.], seq 20334, ack 253, win 110, options [...], length 0
IP 10.200.61.51.http > 10.200.31.69.8938: Flags [.], ack 20335, win 442, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 13: MTU 비대칭 환경에서 ALB의 독립적 TCP 연결 및 MSS 협상 시퀀스 다이어그램

패킷 캡처 분석 결과, TCP 3-way 핸드셰이크 과정에서 클라이언트는 SYN 패킷의 TCP 옵션 필드를 통해 MSS 1460바이트(MTU 1500 – IP/TCP 헤더 40바이트)를 광고했습니다. 반면 ALB는 서버와의 독립적인 TCP 연결 수립 과정에서 MSS 8961바이트(MTU 9001 – IP/TCP 헤더 40바이트)를 광고했습니다.

클라이언트가 ALB로 20,000바이트 크기의 HTTP POST 요청을 전송할 때, 클라이언트-ALB 구간에서는 협상된 MSS 1460바이트에서 TCP 옵션 헤더 오버헤드 12바이트를 고려한 실제 페이로드 1448바이트 단위로 총 14개의 세그먼트로 분할되었습니다. 반면, ALB-서버 구간에서는 협상된 MSS 8961바이트를 기반으로 최대 8949바이트 페이로드 단위의 총 4개 세그먼트로 재구성되어 전송되었습니다.

NLB와 ALB의 MTU/MSS 처리 방식 비교 분석

NLB와 ALB의 MTU/MSS 처리 방식 차이는 OSI 모델에서의 동작 계층 차이에서 비롯됩니다. L4(전송 계층)에서 동작하는 NLB는 투명한 TCP 프록시로서 단일 TCP 연결의 MSS를 네트워크 경로상 최소값으로 클램핑합니다. 반면, L7(응용 계층)에서 동작하는 ALB는 L7 프록시로서 클라이언트-ALB와 ALB-서버 간 두 개의 독립적인 TCP 연결을 종단간 관리합니다.

결과적으로 클라이언트가 표준 이더넷 MTU 1500바이트 환경에 있더라도, ALB는 MSS 클램핑을 수행하지 않고 타겟 그룹이 위치한 AWS 내부 네트워크에서 점보 프레임(9001바이트)을 활용한 효율적인 데이터 전송이 가능합니다. 이러한 구조를 통해 백엔드 서버와의 통신에서 TCP 세그먼트 수를 줄이고 TCP/IP 프로토콜 오버헤드를 최소화함으로써 전체적인 네트워크 성능을 최적화할 수 있습니다.

AWS Gateway Load Balancer

GWLB의 동작 원리

GWLB는 하이퍼플레인 기반의 분산 아키텍처를 활용하여 다중 AZ(Avaiability Zone)에 배치된 방화벽 어플라이언스를 로드밸런싱함으로써 고가용성을 구현합니다. 또한 트래픽 부하에 따른 탄력적 스케일링을 지원하는 ELB의 한 유형으로 보안 아키텍처 구성 시 널리 활용됩니다.

GWLB는 VPC 엔드포인트 서비스(AWS PrivateLink)와 통합되어 여러 VPC 간 트래픽을 중앙 집중식 보안 VPC로 투명하게 리디렉션합니다. 또한 UDP 6081 포트를 사용하는 GENEVE(Generic Network Virtualization Encapsulation) 프로토콜로 원본 IP 패킷을 캡슐화하여 보존합니다.

이러한 아키텍처를 통해 방화벽 어플라이언스는 소스 IP 보존 및 상태 기반 검사를 수행할 수 있으며, Palo Alto Networks, Fortinet, Check Point 등 주요 NGFW(Next-Generation Firewall) 벤더의 가상 어플라이언스와 원활하게 통합되어 엔터프라이즈급 보안 요구사항을 충족하는 확장성 높은 방화벽 아키텍처를 구현할 수 있습니다.

 

그림 14: Geneve 캡슐화 패킷 구조도

GWLB 서비스를 대상으로 MSS 클램핑 지원 여부 및 동작 메커니즘을 검증하기에 앞서, GWLB의 기본 동작 방식에 대해 간략히 설명하겠습니다.

GWLB를 사용한 아키텍처에서 클라이언트와 서버 간 통신은 “Bump-in-the-wire” 방식으로 이루어집니다. 이는 GWLB 동작 원리를 이해하는 핵심 개념으로, 패킷 플로우는 다음과 같은 단계로 진행됩니다.

그림 15: MSS 클램핑 검증을 위한 GWLB 기반 EC2 인스턴스 간 TCP 통신 아키텍처

  1. 클라이언트의 HTTP POST 요청은 클라이언트 인스턴스가 위치한 서브넷과 연결된 라우트 테이블을 참조하여 GWLB 엔드포인트로 전달됩니다.
  2. GWLB 엔드포인트는 AWS PrivateLink 기반 기술을 통해 원본 패킷을 캡슐화하여 GWLB로 전달합니다.
  3. GWLB는 전달받은 원본 패킷을 GENEVE 프로토콜로 캡슐화하여 방화벽 어플라이언스로 전달합니다.
  4. 방화벽 어플라이언스는 캡슐화된 패킷을 복원하여 보안 검사 및 정책 적용 등의 보안 기능을 수행합니다.
  5. 보안 기능 수행 완료 후, 처리된 원본 패킷은 다시 GENEVE로 캡슐화되어 GWLB로 반환됩니다.
  6. GWLB로 반환된 패킷은 다시 AWS PrivateLink 기반 기술로 캡슐화되어 GWLB 엔드포인트로 전달됩니다.
  7. GWLB 엔드포인트는 패킷을 복원한 후, 해당 엔드포인트가 위치한 서브넷의 라우트 테이블을 참조하여 최종 목적지인 서버로 전달합니다.

GWLB의 MSS 클램핑 메커니즘 검증

구분 VPC CIDR IP 주소 MTU 파라미터 설정
클라이언트 10.200.0.0/16 10.200.31.74 9001
방화벽 10.100.0.0/16 10.100.41.67 9001
서버 10.200.0.0/16 10.200.101.194 9001

표 7: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..30000})" http://10.200.101.194/

클라이언트에서 30,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [S], seq 2568499041, win 62727, options [mss 8961,...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [S.], seq 4023906746, ack 2568499042, win 62643, options [mss 8341,...], length 0
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], seq 1:8330, ack 1, win 491, options [...], length 8329: HTTP: POST / HTTP/1.1
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], seq 8330:16659, ack 1, win 491, options [...], length 8329: HTTP
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [P.], seq 16659:24988, ack 1, win 491, options [...], length 8329: HTTP
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [P.], seq 24988:30151, ack 1, win 491, options [...], length 5163: HTTP
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 8330, win 442, options [...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 24988, win 391, options [...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 30151, win 361, options [...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [P.], seq 1:254, ack 30151, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [F.], seq 30151, ack 254, win 490, options [...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [F.], seq 254, ack 30152, win 442, options [...], length 0
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 255, win 490, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [S], seq 2568499041, win 62727, options [mss 8365,...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [S], seq 2568499041, win 62727, options [mss 8365,...], length 0
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [S.], seq 4023906746, ack 2568499042, win 62643, options [mss 8365,...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [S.], seq 4023906746, ack 2568499042, win 62643, options [mss 8365,...], length 0
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], seq 1:8330, ack 1, win 491, options [...], length 8329: HTTP: POST / HTTP/1.1
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], seq 1:8330, ack 1, win 491, options [...], length 8329: HTTP: POST / HTTP/1.1
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], seq 8330:16659, ack 1, win 491, options [...], length 8329: HTTP
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [P.], seq 16659:24988, ack 1, win 491, options [...], length 8329: HTTP
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [P.], seq 24988:30151, ack 1, win 491, options [...], length 5163: HTTP
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], seq 8330:16659, ack 1, win 491, options [...], length 8329: HTTP
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [P.], seq 16659:24988, ack 1, win 491, options [...], length 8329: HTTP
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [P.], seq 24988:30151, ack 1, win 491, options [...], length 5163: HTTP
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 8330, win 442, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 8330, win 442, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 24988, win 391, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 30151, win 361, options [...], length 0
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 24988, win 391, options [...], length 0
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 30151, win 361, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [P.], seq 1:254, ack 30151, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [P.], seq 1:254, ack 30151, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [F.], seq 30151, ack 254, win 490, options [...], length 0
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [F.], seq 30151, ack 254, win 490, options [...], length 0
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [F.], seq 254, ack 30152, win 442, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.101.194.http > 10.200.31.74.54938: Flags [F.], seq 254, ack 30152, win 442, options [...], length 0
IP 10.100.31.229.62182 > 10.100.41.67.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 255, win 490, options [...], length 0
IP 10.100.41.67.62182 > 10.100.31.229.6081: Geneve, ..., options [32 bytes]: IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 255, win 490, options [...], length 0

방화벽 어플라이언스 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [S], seq 2568499041, win 62727, options [mss 8341,...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [S.], seq 4023906746, ack 2568499042, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], seq 1:8330, ack 1, win 491, options [...], length 8329: HTTP: POST / HTTP/1.1
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], seq 8330:16659, ack 1, win 491, options [...], length 8329: HTTP
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [P.], seq 16659:24988, ack 1, win 491, options [...], length 8329: HTTP
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [P.], seq 24988:30151, ack 1, win 491, options [...], length 5163: HTTP
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 8330, win 442, options [...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 24988, win 391, options [...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [.], ack 30151, win 361, options [...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [P.], seq 1:254, ack 30151, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [F.], seq 30151, ack 254, win 490, options [...], length 0
IP 10.200.101.194.http > 10.200.31.74.54938: Flags [F.], seq 254, ack 30152, win 442, options [...], length 0
IP 10.200.31.74.54938 > 10.200.101.194.http: Flags [.], ack 255, win 490, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 16: GWLB 환경에서의 MSS 협상 및 HTTP POST 데이터 전송 시퀀스 다이어그램

TCP 3-way 핸드셰이크 과정에서 클라이언트와 서버 모두 MSS 8961바이트를 광고했지만, GWLB는 GENEVE 캡슐화 등 오버헤드를 고려하여 8341바이트로 클램핑했습니다. 이는 앞서 테스트한 NLB의 MSS 8365바이트보다 24바이트 더 작게 조정된 결과입니다.

클라이언트가 서버로 전송한 30,000바이트 크기의 HTTP POST 요청은 최종 협상된 MSS 8341바이트에서 TCP 옵션 헤더 오버헤드 12바이트를 고려하여 8329바이트 단위로 세그먼트화되어 전송되었습니다. 모든 패킷은 방화벽 어플라이언스를 경유했으며, NLB와 마찬가지로 TCP 시퀀스 번호와 포트 번호를 완전히 보존하는 것을 확인할 수 있었습니다. 이를 통해 GWLB가 클라이언트-서버 간 통신에 투명하게 삽입되는 “Bump-in-the-wire” 방식으로 동작함을 검증할 수 있었습니다.

GWLB 타겟 그룹에 등록된 방화벽 어플라이언스의 MTU 파라미터 설정 시 고려사항

GWLB와 GENEVE 프로토콜을 통해 통신하는 방화벽 어플라이언스의 MTU 파라미터 설정에 관한 중요한 고려사항이 있습니다.

GWLB는 NLB와 마찬가지로 클라이언트-서버 간 통신 시 최대 8341바이트 세그먼트로 전송될 수 있습니다. 그러나 MSS 클램핑을 지원하지 않는 방화벽 어플라이언스의 경우, 8449바이트 이상의 MTU 설정이 필요합니다. 이는 외부 IP 헤더(20바이트), 외부 UDP 헤더(8바이트), GENEVE 헤더(8바이트), GENEVE 옵션(32바이트), 원본 IP 헤더(20바이트), 원본 TCP 헤더(20바이트), 그리고 데이터 페이로드(MSS 8341바이트)를 모두 포함한 크기입니다.

AWS ELB 서비스의 MSS 클램핑 비교 분석

지금까지 AWS ELB 서비스의 MSS 클램핑 지원 여부와 세그먼트 처리 방식을 분석한 결과를 요약하면 다음과 같습니다. AWS ELB 서비스는 각 로드밸런서의 동작 계층과 아키텍처 특성에 따라 MSS 클램핑을 다르게 구현하고 있습니다. L4 계층에서 동작하는 NLB와 GWLB는 MSS 클램핑을 통해 IP 단편화를 방지하고 네트워크 성능을 최적화합니다. 반면, L7 계층에서 동작하는 ALB는 독립적인 TCP 연결 관리를 통해 각 통신 구간별 최적의 MTU를 활용하는 방식을 채택하고 있습니다. 보안 아키텍처 구성 시 GWLB를 사용할 경우, GENEVE 프로토콜 캡슐화로 인한 추가 오버헤드를 고려한 방화벽 어플라이언스의 MTU 파라미터 설정이 중요합니다.

구분 NLB ALB GWLB
동작 계층 L4(전송 계층) L7(응용 계층) L4(전송 계층)
MSS 클램핑 지원 지원 해당 없음 지원
클램핑 MSS 값 8365바이트 해당 없음 8341바이트
TCP 연결 방식 TCP 프록시 L7 프록시 Bump-in-the-wire

표 8: AWS ELB 서비스의 MSS 클램핑 기능 비교

Transit Gateway와 VPC 피어링 환경에서의 MSS 클램핑

Transit Gateway(TGW)

TGW는 VPC 피어링과 함께 VPC 간 연결을 위해 널리 활용되는 AWS 네트워크 서비스입니다. TGW를 사용하여 두 개의 VPC를 연결한 아키텍처는 다음과 같으며, TGW는 MTU 8500바이트(MSS 8460바이트)를 지원합니다.

그림 17: MSS 클램핑 검증을 위한 TGW 기반 VPC 간 EC2 인스턴스 통신 아키텍처

구분 VPC CIDR IP 주소 MTU 파라미터 설정
클라이언트 10.200.0.0/16 10.200.31.74 9001
서버 10.0.0.0/16 10.0.31.189 9001

표 9: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..30000})" http://10.0.31.189/

클라이언트에서 30,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [S], seq 2779330369, win 62727, options [mss 8460,...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [S.], seq 3406476291, ack 2779330370, win 62643, options [mss 8460,...], length 0
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], seq 1:8449, ack 1, win 491, options [...], length 8448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], seq 8449:16897, ack 1, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [P.], seq 16897:25345, ack 1, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [P.], seq 25345:30148, ack 1, win 491, options [...], length 4803: HTTP
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [.], ack 16897, win 430, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [.], ack 25345, win 388, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [.], ack 30148, win 366, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [P.], seq 1:254, ack 30148, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [F.], seq 30148, ack 254, win 490, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [F.], seq 254, ack 30149, win 442, options [...], length 0
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], ack 255, win 490, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [S], seq 2779330369, win 62727, options [mss 8460,...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [S.], seq 3406476291, ack 2779330370, win 62643, options [mss 8460,...], length 0
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], seq 1:8449, ack 1, win 491, options [...], length 8448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], seq 8449:16897, ack 1, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [P.], seq 16897:25345, ack 1, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [P.], seq 25345:30148, ack 1, win 491, options [...], length 4803: HTTP
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [.], ack 16897, win 430, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [.], ack 25345, win 388, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [.], ack 30148, win 366, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [P.], seq 1:254, ack 30148, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [F.], seq 30148, ack 254, win 490, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.49162: Flags [F.], seq 254, ack 30149, win 442, options [...], length 0
IP 10.200.31.74.49162 > 10.0.31.189.http: Flags [.], ack 255, win 490, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 18: TGW 기반 VPC 간 EC2 인스턴스의 MSS 협상 및 HTTP POST 데이터 전송 시퀀스 다이어그램

클라이언트와 서버의 ENI 트래픽 미러링을 통해 수집한 패킷 캡처 결과를 분석해보면, TCP 3-way 핸드셰이크 과정에서 클라이언트와 서버 모두 MTU가 9001바이트이지만 MSS 8460바이트를 광고한 것을 확인할 수 있습니다. 이는 클라이언트와 서버가 통신 시 TGW를 경유하는 경우, 클라이언트와 서버 인스턴스가 있는 호스트의 하이퍼바이저에서 MSS를 8460바이트로 클램핑하기 때문입니다.

이후 실제 데이터 페이로드는 TCP 옵션 헤더 오버헤드를 고려하여 8448바이트 단위로 세그먼트화되어 전송되었습니다.

VPC 피어링(VPC Peering)

AWS는 2025년 3월, 교차 리전 VPC 피어링(Cross-Region VPC Peering) 연결에서 EC2 인스턴스가 점보 프레임을 지원하도록 기능을 개선했습니다. 이를 통해 기존 1500바이트 MTU 제한에서 최대 8500바이트의 MTU를 지원하게 되었습니다. 이번 업데이트로 교차 리전 VPC 피어링 연결에서도 더 높은 네트워크 처리량과 효율성을 확보할 수 있게 되었습니다.

본 테스트에서는 VPC 피어링 환경에서의 MSS 클램핑 메커니즘을 검증하기 위해, 먼저 리전 내 VPC 피어링(Intra-Region VPC Peering) 환경에서 MSS 클램핑이 어떻게 구현되어 있는지 확인한 후, 교차 리전 VPC 피어링 환경에서의 MSS 클램핑 메커니즘을 분석하겠습니다.

리전 내 VPC 피어링 환경에서의 MSS 클램핑 검증

먼저 리전 내 VPC 피어링 환경에서 클라이언트와 서버 간 MSS 클램핑이 적용되는지 검증하겠습니다.

그림 19: MSS 클램핑 검증을 위한 리전 내 VPC 피어링 기반 EC2 인스턴스 간 TCP 통신 아키텍처

구분 리전 VPC CIDR IP 주소 MTU 파라미터 설정
클라이언트 서울 10.200.0.0/16 10.200.31.74 9001
서버 서울 10.0.0.0/16 10.0.31.189 9001

표 10: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..30000})" http://10.0.31.189/

클라이언트에서 30,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [S], seq 37184247, win 62727, options [mss 8961,...], length 0
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [S.], seq 1445637394, ack 37184248, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [P.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [.], ack 26848, win 389, options [...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [P.], seq 26848:30148, ack 1, win 491, options [...], length 3300: HTTP
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [.], ack 30148, win 373, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [P.], seq 1:254, ack 30148, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [F.], seq 30148, ack 254, win 490, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [F.], seq 254, ack 30149, win 442, options [...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], ack 255, win 490, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [S], seq 37184247, win 62727, options [mss 8961,...], length 0
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [S.], seq 1445637394, ack 37184248, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [P.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [.], ack 26848, win 389, options [...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [P.], seq 26848:30148, ack 1, win 491, options [...], length 3300: HTTP
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [.], ack 30148, win 373, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [P.], seq 1:254, ack 30148, win 442, options [...], length 253: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], ack 254, win 490, options [...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [F.], seq 30148, ack 254, win 490, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.50062: Flags [F.], seq 254, ack 30149, win 442, options [...], length 0
IP 10.200.31.74.50062 > 10.0.31.189.http: Flags [.], ack 255, win 490, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 20: 리전 내 VPC 피어링 환경에서의 EC2 인스턴스 간 MSS 협상 및 HTTP POST 데이터 전송 시퀀스 다이어그램

패킷 캡처 분석 결과, TCP 3-way 핸드셰이크 과정에서 클라이언트와 서버 모두 MSS 8961바이트(MTU 9001 – IP/TCP 헤더 40바이트)를 광고했습니다. 리전 내 TGW 연결과는 달리 VPC 피어링 연결에서는 MSS 클램핑 없이 클라이언트와 서버가 직접 통신하는 환경과 동일한 결과를 보였습니다. 클라이언트는 최종적으로 MSS 8961바이트를 협상했고, TCP 옵션 헤더 12바이트를 고려한 실제 페이로드를 세그먼트당 8949바이트로 서버에 전송했습니다.

교차 리전 VPC 피어링 환경에서의 MSS 클램핑 검증

그림 21: MSS 클램핑 검증을 위한 교차 리전 VPC 피어링 기반 EC2 인스턴스 간 TCP 통신 아키텍처

구분 리전 VPC CIDR IP 주소 MTU 파라미터 설정
클라이언트 서울 10.200.0.0/16 10.200.31.74 9001
서버 버지니아 10.172.0.0/16 10.172.9.227 9001

표 11: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..30000})" http://10.172.9.227/

클라이언트에서 30,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [S], seq 1179110791, win 62727, options [mss 8460,...], length 0
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [S.], seq 1670421842, ack 1179110792, win 62643, options [mss 8460,...], length 0
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], seq 1:8449, ack 1, win 491, options [...], length 8448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [P.], seq 8449:16897, ack 1, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], seq 16897:25345, ack 1, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [P.], seq 25345:30149, ack 1, win 491, options [...], length 4804: HTTP
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [.], ack 16897, win 425, options [...], length 0
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [.], ack 30149, win 353, options [...], length 0
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [P.], seq 1:256, ack 30149, win 442, options [...], length 255: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], ack 256, win 490, options [...], length 0
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [F.], seq 30149, ack 256, win 490, options [...], length 0
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [F.], seq 256, ack 30150, win 442, options [...], length 0
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], ack 257, win 490, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [S], seq 1179110791, win 62727, options [mss 8460,...], length 0
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [S.], seq 1670421842, ack 1179110792, win 62643, options [mss 8460,...], length 0
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], seq 1:8449, ack 1, win 491, options [...], length 8448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [P.], seq 8449:16897, ack 1, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], seq 16897:25345, ack 1, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [P.], seq 25345:30149, ack 1, win 491, options [...], length 4804: HTTP
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [.], ack 16897, win 425, options [...], length 0
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [.], ack 30149, win 353, options [...], length 0
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [P.], seq 1:256, ack 30149, win 442, options [...], length 255: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], ack 256, win 490, options [...], length 0
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [F.], seq 30149, ack 256, win 490, options [...], length 0
IP 10.172.9.227.http > 10.200.31.74.38254: Flags [F.], seq 256, ack 30150, win 442, options [...], length 0
IP 10.200.31.74.38254 > 10.172.9.227.http: Flags [.], ack 257, win 490, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 22: 교차 리전 VPC 피어링 환경에서의 EC2 인스턴스 간 MSS 협상 및 HTTP POST 데이터 전송 시퀀스 다이어그램

VPC 피어링 환경에서 EC2 인스턴스 간 통신에 있어서, 리전 내 VPC 피어링 환경과는 달리 교차 리전 VPC 피어링 환경에서는 TGW와 동일한 방식으로 MSS 클램핑이 작동합니다.

이에 따라 클라이언트의 HTTP POST 요청은 최종 협상된 MSS 8460바이트에서 TCP 옵션 헤더 오버헤드 12바이트를 고려한 실제 데이터 페이로드 8448바이트 단위로 세그먼트화되어 서버로 전송되었습니다.

TGW와 VPC 피어링 환경에서의 MSS 클램핑 비교 분석

TGW와 VPC 피어링에 대한 MSS 클램핑 지원 여부와 세그먼트 처리 방식에 대해 요약하면 다음과 같습니다. TGW는 MSS 클램핑을 지원하지만, VPC 피어링의 경우 교차 리전 피어링 환경 여부에 따라 MSS 클램핑 지원 여부가 결정됩니다.

구분 TGW 리전 내 VPC 피어링 교차 리전 VPC 피어링
MSS 클램핑 지원 지원 해당 없음 지원
클램핑 MSS 값 8460바이트 해당 없음 8460바이트
MTU 지원 8500바이트 9001바이트 8500바이트

표 12: TGW와 VPC 피어링의 MSS 클램핑 비교 분석

데이터 전송 시 MTU 크기를 동적으로 조정하는 PMTUD(Path MTU Discovery) 메커니즘

마지막으로 PMTUD 메커니즘을 검증하겠습니다. PMTUD는 송신자가 목적지까지의 네트워크 경로에서 지원하는 최대 MTU 크기를 동적으로 조정하는 프로토콜입니다.

MSS 클램핑이 TCP 3-way 핸드셰이크 과정에서 MSS 값을 사전에 조정하는 정적인 방식이라면, PMTUD는 실제 데이터 전송 중에 동적으로 MTU를 조정합니다. 송신자는 IP 헤더의 DF(Don’t Fragment) 비트를 설정하여 패킷을 전송하고, 경로상에 더 작은 MTU를 가진 링크가 있을 경우 해당 라우터로부터 ICMP “Fragmentation Needed”(Type 3, Code 4) 메시지를 수신합니다. 이를 통해 IP 단편화로 인한 성능 저하와 패킷 손실을 효과적으로 방지할 수 있습니다.

특성 MSS 클램핑 PMTUD
작동 시점 TCP 3-way 핸드셰이크 중 데이터 전송 중
작동 방식 TCP SYN/SYN-ACK 패킷의 MSS 옵션 필드 값을 조정 송신자가 MTU를 조정하여 요청을 재전송하도록 ICMP 메시지 응답
프로토콜 TCP 프로토콜 TCP/UDP 등 모든 전송 프로토콜
ICMP 의존성 ICMP에 의존하지 않음 ICMP 메시지 차단 시 작동 불가
네트워크 오버헤드 추가 패킷 교환 없이 TCP 핸드셰이크 패킷만 수정 ICMP 메시지 교환 및 패킷 재전송 발생
경로 변경 대응 TCP 연결 수립 이후 변경된 경로에 대한 대응 불가 경로 변경으로 MTU가 작아지는 경우에도 동적으로 대응 가능

표 13: MSS 클램핑과 PMTUD 특성 비교

PMTUD 메커니즘 검증을 위한 테스트 환경 구성

다음은 PMTUD를 검증하기 위한 테스트 아키텍처입니다. 클라이언트와 서버 간 통신 시 모든 트래픽이 네트워크 어플라이언스(방화벽, 라우터 등)를 경유하도록 구성되어 있습니다. 어플라이언스는 투명 프록시로 동작하여 수신한 트래픽을 MSS 클램핑과 같은 별도 처리 없이 그대로 포워딩합니다. 어플라이언스 인스턴스 구성에 대한 내용은 다음을 참고하세요.

그림 23: PMTUD 메커니즘 검증을 위한 네트워크 어플라이언스 경유 EC2 인스턴스 간 TCP 통신 아키텍처

구분 서브넷 CIDR IP 주소 MTU 파라미터 설정
클라이언트 10.200.31.0/24 10.200.31.74 9001
어플라이언스 10.200.41.0/24 10.200.41.218 9001
서버 10.200.51.0/24 10.200.51.63 9001

표 14: 인스턴스 구성 정보


[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..30000})" http://10.200.51.63/

클라이언트에서 30,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [S], seq 3901249824, win 62727, options [mss 8961,...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [S.], seq 2725227140, ack 3901249825, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [P.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [P.], seq 26848:30149, ack 1, win 491, options [...], length 3301: HTTP
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [.], ack 26848, win 388, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [.], ack 30149, win 372, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [P.], seq 1:262, ack 30149, win 442, options [...], length 261: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 262, win 489, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [F.], seq 30149, ack 262, win 489, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [F.], seq 262, ack 30150, win 442, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 263, win 489, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [S], seq 3901249824, win 62727, options [mss 8961,...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [S], seq 3901249824, win 62727, options [mss 8961,...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [S.], seq 2725227140, ack 3901249825, win 62643, options [mss 8961,...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [S.], seq 2725227140, ack 3901249825, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [P.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [P.], seq 26848:30149, ack 1, win 491, options [...], length 3301: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [P.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [P.], seq 26848:30149, ack 1, win 491, options [...], length 3301: HTTP
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [.], ack 26848, win 388, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [.], ack 30149, win 372, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [.], ack 26848, win 388, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [.], ack 30149, win 372, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [P.], seq 1:262, ack 30149, win 442, options [...], length 261: HTTP: HTTP/1.1 200 OK
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [P.], seq 1:262, ack 30149, win 442, options [...], length 261: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 262, win 489, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 262, win 489, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [F.], seq 30149, ack 262, win 489, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [F.], seq 30149, ack 262, win 489, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [F.], seq 262, ack 30150, win 442, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [F.], seq 262, ack 30150, win 442, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 263, win 489, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 263, win 489, options [...], length 0

네트워크 어플라이언스 ENI 트래픽 미러링을 통한 패킷 캡처 결과

IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [S], seq 3901249824, win 62727, options [mss 8961,...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [S.], seq 2725227140, ack 3901249825, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], seq 1:8950, ack 1, win 491, options [...], length 8949: HTTP: POST / HTTP/1.1
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], seq 8950:17899, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [P.], seq 17899:26848, ack 1, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [P.], seq 26848:30149, ack 1, win 491, options [...], length 3301: HTTP
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [.], ack 26848, win 388, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [.], ack 30149, win 372, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [P.], seq 1:262, ack 30149, win 442, options [...], length 261: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 262, win 489, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [F.], seq 30149, ack 262, win 489, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.34668: Flags [F.], seq 262, ack 30150, win 442, options [...], length 0
IP 10.200.31.74.34668 > 10.200.51.63.http: Flags [.], ack 263, win 489, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 24: 네트워크 어플라이언스를 경유하는 EC2 인스턴스 간 TCP 3-way 핸드셰이크 및 HTTP POST 데이터 전송 시퀀스 다이어그램

네트워크 어플라이언스는 라우터 처럼 MSS 클램핑없이 단순히 패킷포워딩을 수행, 클라이언트와 서버 간 통신은 MSS 8961바이트로 이루어집니다. 이후 클라이언트는 패킷을 8949바이트(MTU 9001-40바이트-12바이트) 단위로 분할하여 전송했습니다.

PMTUD 시뮬레이션

이제 네트워크 어플라이언스의 MTU를 1500바이트로 하향 조정하여 데이터 전송 중 발생하는 PMTUD 메커니즘을 확인하겠습니다.

그림 25: PMTUD 메커니즘 검증을 위한 MTU 제약 환경에서의 TCP 통신 아키텍처

구분 서브넷 CIDR IP 주소 MTU 파라미터 설정
클라이언트 10.200.31.0/24 10.200.31.74 9001
어플라이언스 10.200.41.0/24 10.200.41.218 1500
서버 10.200.51.0/24 10.200.51.63 9001

표 15: 인스턴스 구성 정보

[ec2-user@client ~]$ curl -X POST -d "$(printf 'a%.0s' {1..5000})" http://10.200.51.63/

클라이언트에서 5,000바이트 페이로드를 포함한 HTTP POST 요청 전송

IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [S], seq 3394565049, win 62727, options [mss 8961,...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [S.], seq 3948777377, ack 3394565050, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [P.], seq 1:5148, ack 1, win 491, options [...], length 5147: HTTP: POST / HTTP/1.1
IP 10.200.41.218 > 10.200.31.74: ICMP 10.200.51.63 unreachable - need to frag (mtu 1500), length 556
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 1:1449, ack 1, win 491, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 1449:2897, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 2897:4345, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [P.], seq 4345:5148, ack 1, win 491, options [...], length 803: HTTP
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [.], ack 1449, win 479, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [.], ack 5148, win 451, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [P.], seq 1:262, ack 5148, win 451, options [...], length 261: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 262, win 489, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [F.], seq 5148, ack 262, win 489, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [F.], seq 262, ack 5149, win 451, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 263, win 489, options [...], length 0

클라이언트 ENI 트래픽 미러링을 통한 패킷 캡처 결과 – 5번째 라인의 ICMP 메세지

IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [S], seq 3394565049, win 62727, options [mss 8961,...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [S], seq 3394565049, win 62727, options [mss 8961,...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [S.], seq 3948777377, ack 3394565050, win 62643, options [mss 8961,...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [S.], seq 3948777377, ack 3394565050, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [P.], seq 1:5148, ack 1, win 491, options [...], length 5147: HTTP: POST / HTTP/1.1
IP 10.200.41.218 > 10.200.31.74: ICMP 10.200.51.63 unreachable - need to frag (mtu 1500), length 556
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 1:1449, ack 1, win 491, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 1449:2897, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 2897:4345, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [P.], seq 4345:5148, ack 1, win 491, options [...], length 803: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 1:1449, ack 1, win 491, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 1449:2897, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 2897:4345, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [P.], seq 4345:5148, ack 1, win 491, options [...], length 803: HTTP
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [.], ack 1449, win 479, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [.], ack 5148, win 451, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [.], ack 1449, win 479, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [.], ack 5148, win 451, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [P.], seq 1:262, ack 5148, win 451, options [...], length 261: HTTP: HTTP/1.1 200 OK
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [P.], seq 1:262, ack 5148, win 451, options [...], length 261: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 262, win 489, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 262, win 489, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [F.], seq 5148, ack 262, win 489, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [F.], seq 5148, ack 262, win 489, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [F.], seq 262, ack 5149, win 451, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [F.], seq 262, ack 5149, win 451, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 263, win 489, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 263, win 489, options [...], length 0

네트워크 어플라이언스 ENI 트래픽 미러링을 통한 패킷 캡처 결과 – 8번째 라인의 ICMP 메세지

IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [S], seq 3394565049, win 62727, options [mss 8961,...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [S.], seq 3948777377, ack 3394565050, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 1:1449, ack 1, win 491, options [...], length 1448: HTTP: POST / HTTP/1.1
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 1449:2897, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], seq 2897:4345, ack 1, win 491, options [...], length 1448: HTTP
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [P.], seq 4345:5148, ack 1, win 491, options [...], length 803: HTTP
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [.], ack 1449, win 479, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [.], ack 5148, win 451, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [P.], seq 1:262, ack 5148, win 451, options [...], length 261: HTTP: HTTP/1.1 200 OK
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 262, win 489, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [F.], seq 5148, ack 262, win 489, options [...], length 0
IP 10.200.51.63.http > 10.200.31.74.54070: Flags [F.], seq 262, ack 5149, win 451, options [...], length 0
IP 10.200.31.74.54070 > 10.200.51.63.http: Flags [.], ack 263, win 489, options [...], length 0

서버 ENI 트래픽 미러링을 통한 패킷 캡처 결과

그림 26: MTU 제약 환경에서 PMTUD 메커니즘이 적용된 네트워크 어플라이언스 경유 EC2 인스턴스 간 TCP 통신 시퀀스 다이어그램

패킷 캡처 분석 결과, TCP 3-way 핸드셰이크 과정에서 클라이언트와 서버는 MSS 8961바이트(MTU 9001 – IP/TCP 헤더 40바이트)로 협상했습니다. 그러나 클라이언트가 5,148바이트의 대용량 HTTP POST 패킷을 전송하자 MTU 1500바이트로 제한된 네트워크 어플라이언스에서 “ICMP Unreachable – need to frag (MTU 1500)” 메시지를 클라이언트에 반환했습니다.

이에 따라 클라이언트는 PMTUD 메커니즘을 통해 경로상 최소 MTU가 1500바이트임을 자동으로 감지하고, 이 정보를 라우팅 캐시에 저장하여 향후 동일 목적지에 대해서는 패킷 크기를 1448바이트(MTU 1500 – IP/TCP 헤더 40바이트 – TCP 옵션 12바이트)로 조정하여 데이터를 재전송했습니다.

클라이언트에서 PMTUD를 통해 발견된 경로 MTU(Path MTU)는 다음 명령어로 확인할 수 있으며, 해당 정보가 라우팅 캐시에 저장되는 것을 아래와 같이 확인할 수 있습니다.

[ec2-user@client ~]$ ip route get 10.200.51.63
10.200.51.63 via 10.200.31.1 dev ens5 src 10.200.31.74 uid 1000
    cache expires 195sec mtu 1500

TGW의 PMTUD 메커니즘 검증

이어서 TGW에서의 PMTUD 메커니즘 작동을 검증해 보겠습니다. AWS는 2024년 11월, TGW와 Cloud WAN에 PMTUD 지원을 추가했습니다.

TGW의 PMTUD 기능을 검증하기 위해, 클라이언트와 서버는 VPC 피어링 연결을 통해 TCP 연결을 수립한 후 데이터 전송 경로를 VPC 피어링에서 TGW로 전환하는 실시간 마이그레이션을 수행하겠습니다. 이러한 실시간 마이그레이션은 예를 들어, 데이터 스트리밍과 같이 TCP 연결이 장기간 유지되는 경우에 데이터 전송 경로에서 VPC 피어링에서 TGW로의 전환이 일어난다면 데이터 전송 시, MTU의 차이로인하여 TGW에서 패킷 손실이 일어날 수 있습니다. 이 테스트를 통해 데이터 전송 경로 변경 시 발생하는 MTU 차이로 인한 패킷 손실이 PMTUD 메커니즘을 통해 어떻게 자동으로 감지되고 해결되는지 확인할 수 있습니다.

그림 27: TGW의 PMTUD 메커니즘 검증을 위한 VPC 피어링에서 TGW로의 실시간 마이그레이션

  1. 클라이언트와 서버는 리전 내 VPC 피어링을 통해 TCP 3-way 핸드셰이크를 수행하여 MSS 8961바이트를 협상합니다.
  2. 클라이언트는 VPC 피어링 경로를 통해 HTTP POST 데이터 전송을 시작합니다.
  3. 클라이언트에서 서버로 데이터 전송 중에, 클라이언트 인스턴스가 위치한 서브넷의 라우트 테이블을 업데이트하여 타겟 서버로 향하는 경로를 VPC 피어링에서 TGW 경로로 마이그레이션합니다.
  4. 클라이언트는 업데이트된 TGW 경로를 통해 데이터를 계속 전송하며, 이 과정에서 TGW의 PMTUD 메커니즘이 작동합니다.
  5. 서버 인스턴스가 위치한 서브넷의 라우트 테이블을 업데이트하여 클라이언트로 향하는 경로를 VPC 피어링에서 TGW로 변경해서 마이그레이션 작업을 완료합니다.
구분 VPC CIDR IP 주소 MTU 파라미터 설정
클라이언트 10.200.0.0/16 10.200.31.74 9001
서버 10.0.0.0/16 10.0.31.189 9001

표 16: 인스턴스 구성 정보

bash
[ec2-user@client ~]$ curl -X POST -T large\_file http://10.0.31.189/ --limit-rate 10k

PMTUD 동작 관찰을 위한 제한된 대역폭(10KB/s)으로 파일 스트리밍 전송

IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [S], seq 1180035974, win 62727, options [mss 8961,...], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [S.], seq 1573484164, ack 1180035975, win 62643, options [mss 8961,...], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], ack 1, win 491, options [...], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 1:133, ack 1, win 491, options [...], length 132: HTTP: POST /000.csv HTTP/1.1
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 133, win 489, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [P.], seq 1:26, ack 133, win 489, options [...], length 25: HTTP: HTTP/1.1 100 Continue
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], ack 26, win 491, options [...], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 133:9082, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 9082:18031, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 18031:26980, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 26980:35929, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 35929:44878, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 44878:53827, ack 26, win 491, options [...], length 8949: HTTP
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 35929, win 258, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 53827, win 258, options [...], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 53827:62776, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 62776:65669, ack 26, win 491, options [...], length 2893: HTTP
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 65669, win 442, options [...], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 65669:74618, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 74618:83567, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 83567:92516, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 92516:101465, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 101465:110414, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 110414:119363, ack 26, win 491, options [...], length 8949: HTTP
IP 10.200.31.1 > 10.200.31.74: ICMP 10.0.31.189 unreachable - need to frag (mtu 8500), length 36
IP 10.200.31.1 > 10.200.31.74: ICMP 10.0.31.189 unreachable - need to frag (mtu 8500), length 36
IP 10.200.31.1 > 10.200.31.74: ICMP 10.0.31.189 unreachable - need to frag (mtu 8500), length 36
IP 10.200.31.1 > 10.200.31.74: ICMP 10.0.31.189 unreachable - need to frag (mtu 8500), length 36
IP 10.200.31.1 > 10.200.31.74: ICMP 10.0.31.189 unreachable - need to frag (mtu 8500), length 36
IP 10.200.31.1 > 10.200.31.74: ICMP 10.0.31.189 unreachable - need to frag (mtu 8500), length 36
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 65669:74117, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 74117:82565, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 82565:91013, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 91013:92516, ack 26, win 491, options [...], length 1503: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 92516:100964, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 100964:109412, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 109412:117860, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 117860:119363, ack 26, win 491, options [...], length 1503: HTTP
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 65669, win 706, options [...,sack 1 {100964:117860}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 65669, win 846, options [...,sack 1 {100964:119363}], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 65669:74117, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 74117:82565, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 82565:91013, ack 26, win 491, options [...], length 8448: HTTP
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 74117, win 986, options [...,sack 1 {100964:119363}], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 91013:92516, ack 26, win 491, options [...], length 1503: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 92516:100964, ack 26, win 491, options [...], length 8448: HTTP
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 74117, win 1126, options [...,sack 2 {82565:91013}{100964:119363}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 91013, win 1266, options [...,sack 1 {100964:119363}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 92516, win 1406, options [...,sack 1 {100964:119363}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 119363, win 1545, options [...], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 74117:82565, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 119363:127811, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 127811:131205, ack 26, win 491, options [...], length 3394: HTTP
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 119363, win 1545, options [...,sack 1 {65669:74117}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 119363, win 1545, options [...,sack 1 {74117:82565}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 119363, win 1545, options [...,sack 1 {82565:91013}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 119363, win 1545, options [...,sack 1 {91013:92516}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 119363, win 1545, options [...,sack 1 {92516:100964}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 119363, win 1545, options [...,sack 1 {74117:82565}], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 131205, win 1730, options [...], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 131205:139653, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 139653:148101, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 148101:156549, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 156549:164997, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 164997:173445, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 173445:181893, ack 26, win 491, options [...], length 8448: HTTP
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [.], seq 181893:190341, ack 26, win 491, options [...], length 8448: HTTP
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 156549, win 2126, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 181893, win 2205, options [...], length 0
IP 10.200.31.74.44688 > 10.0.31.189.http: Flags [P.], seq 190341:196741, ack 26, win 491, options [...], length 6400: HTTP
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 190341, win 2160, options [...], length 0
IP 10.0.31.189.http > 10.200.31.74.44688: Flags [.], ack 196741, win 2345, options [...], length 0

클라이언트 인스턴스의 커널 레벨 패킷 캡처 결과 – 19 ~ 38번째 라인에서 PMTUD 동작 확인

그림 28: VPC 피어링에서 TGW로의 실시간 마이그레이션 시 PMTUD 메커니즘 작동과 HTTP POST 데이터 전송 시퀀스 다이어그램

VPC 피어링을 통해 연결된 클라이언트와 서버는 TCP 연결 수립 과정에서 MSS 8961바이트(MTU 9001바이트에서 IP/TCP 헤더 40바이트를 제외한 크기)로 협상했으며, 8949바이트 크기의 세그먼트로 데이터를 분할하여 전송하고 있었습니다.

이후 클라이언트 인스턴스가 위치한 서브넷의 라우트 테이블을 변경하여, 클라이언트에서 서버로의 트래픽 경로를 VPC 피어링에서 TGW로 마이그레이션했습니다.

변경된 경로를 통해 전송 중이던 패킷이 MTU 8500바이트로 제한된 TGW에 도달했습니다. TGW는 패킷 크기 제한으로 인해 “ICMP Unreachable – need to frag (MTU 8500)” 메시지를 클라이언트로 반환했으며, 이러한 ICMP 메시지는 클라이언트 인스턴스의 커널 레벨 패킷 캡처를 통해서만 관찰이 가능합니다.

ICMP 메시지를 수신한 클라이언트는 PMTUD 메커니즘에 따라 MSS 값을 수정하고, 라우팅 캐시에 서버를 목적지로 하는 MTU를 8500바이트로 조정했습니다. 이후 TGW MTU를 초과하여 서버로 전송되지 않은 세그먼트를 8448바이트(MTU 8500 – IP/TCP 헤더 40바이트 – TCP 옵션 12바이트) 크기로 분할하여 재전송하고, 나머지 데이터에 대해서도 동일한 세그먼트 크기로 분할 전송했습니다.

클라이언트에서 서버를 목적지로 하는 PMTUD를 통해 발견된 TGW의 MTU 8500바이트는 다음 명령어로 확인할 수 있으며, 해당 정보는 일정 시간이 지나면 다시 원래 값으로 복원됩니다.

[ec2-user@client ~]$ ip route get 10.0.31.189
10.0.31.189 via 10.200.31.1 dev ens5 src 10.200.31.74 uid 1000
   cache expires 563sec mtu 8500

마치며

AWS 클라우드 환경에서 점보 프레임의 효과적인 활용을 위해서는 네트워크 경로 전반에 걸친 MTU 일관성 확보가 핵심 요소입니다. 이를 위해 AWS는 다양한 네트워크 서비스에 MSS 클램핑과 PMTUD 메커니즘을 구현하여 네트워크 안정성과 전송 성능을 최적화하고 있습니다.

하이브리드 클라우드, 멀티 리전 아키텍처, ELB 샌드위치 모델과 같은 복잡한 네트워크 환경에서 점보 프레임을 효과적으로 활용하려면 각 네트워크 구간의 MTU 값을 정확히 파악하고, 적절한 MSS 설정 및 PMTUD 동작을 체계적으로 검증하는 것이 중요합니다. 특히 서드파티 방화벽 어플라이언스를 적용할 경우 해당 장비의 MTU/MSS 설정을 점검해야 하며, TCP가 아닌 프로토콜 기반의 서비스를 사용할 때는 경로상 MTU를 확인해야 합니다. 이러한 세심한 네트워크 설계는 AWS 클라우드 환경에서 데이터 전송의 효율성과 안정성을 크게 향상시킬 수 있습니다.

앞으로도 AWS는 네트워크 서비스의 MTU 지원 범위를 확장하고 PMTUD 메커니즘을 개선하여 고객이 더욱 원활한 네트워크 경험을 누릴 수 있도록 지속적으로 노력할 것입니다. 여러분의 AWS 클라우드 환경에서도 이러한 네트워크 최적화 원칙을 적용하여 더 나은 성능과 안정성을 경험하시기 바랍니다.

Joonghoon Shin

Joonghoon Shin

신중훈 솔루션즈 아키텍트는 금융 고객을 대상으로 클라우드 전략을 제안하고 클라우드 전환을 지원하는 역할을 수행하고 있습니다.