[reinvent 2024] EC2 Nitro 네트워킹의 내면 탐구
Summary
이 세션에서는 EC2 인스턴스에서 패킷이 이동하는 과정에 대한 깊은 통찰을 제공하고, 워크로드에 맞게 인스턴스 네트워크 성능을 최적화하는 주요 전략을 다룹니다. EC2 인스턴스에서 네트워킹 경험을 혁신하는 최첨단 기술을 살펴보고 성능을 한층 더 끌어올릴 수 있는 방법을 알아보세요. AWS가 단일 VPC를 놀라운 규모로 확장하는 방식과 Nitro에서 다양한 유형의 애플리케이션을 위한 최적의 성능을 달성하는 혁신을 탐구합니다.
리인벤트 2024 테크 블로그의 더 많은 글이 보고 싶다면?
Overview
들어가며
저는 이번 세션을 통해 AWS Nitro 시스템의 네트워크 시스템에 대해서 알아보고 이를 공유하여, 많은 분들에게 AWS의 높은 기술력을 전달하고자 합니다.
Nito 시스템 이해하기
Nitro는 AWS에서 제공하는 시스템으로, 네트워킹, 스토리지, 보안 등의 기능을 통합한 칩셋 시스템입니다. Nitro는 2013년에 처음 도입된 이후 지속적으로 발전해왔으며, 현재는 Nitro D5, C7, GN 등 다섯 번째 세대에 이르고 있습니다.
Nitro는 다양한 기능을 하나의 시스템으로 통합하여 제공함으로써, 서버의 처리 능력을 극대화하고 관리의 복잡성을 줄여줍니다. 네트워크 I/O, 스토리지 I/O, 보안 기능 등이 Nitro의 주요 구성 요소로, 각각의 기능이 고유의 칩셋에서 처리됩니다. 이를 통해 서버는 더 많은 인스턴스를 처리할 수 있게 되었고, 네트워크와 스토리지의 비율이 줄어들어 더 효율적인 자원 활용이 가능해졌습니다.
Nitro의 주요 구성 요소는 다음과 같습니다:
- 네트워크 I/O: Nitro는 고속 데이터 전송을 지원하여 대량의 패킷을 효율적으로 처리할 수 있습니다. 이를 통해 서버 간의 통신 속도가 크게 향상되며, 대규모 데이터 전송이 필요한 애플리케이션에서 뛰어난 성능을 발휘합니다.
- 스토리지 I/O: 빠른 데이터 접근과 저장을 가능하게 하여 애플리케이션의 성능을 최적화합니다. Nitro는 로컬 스토리지 및 블록 스토리지와의 연계를 통해 데이터 처리 속도를 극대화하며, 대용량 데이터를 빠르게 처리할 수 있도록 지원합니다.
- 보안 기능: 강화된 보안 메커니즘을 통해 데이터 보호를 강화합니다. Nitro는 네트워크 트래픽을 암호화하고, 보안 그룹 및 ACL(Access Control List)을 통해 트래픽을 제어함으로써 데이터의 안전성을 보장합니다.
Nitro는 여러 세대에 걸쳐 발전해왔으며, 각 세대마다 성능과 보안이 향상되었습니다. 첫 번째 세대인 C3에서는 네트워킹, 스토리지, 보안 기능을 서버 외부로 분리하는 ‘오프박싱’ 전략을 도입했습니다. 이후 Nitro D5, C7, GN 등으로 발전하며 성능과 안정성을 지속적으로 개선해왔습니다. 이러한 발전을 통해 Nitro는 더 많은 인스턴스를 처리할 수 있게 되었고, 네트워크와 스토리지의 비율이 줄어들어 더 효율적인 자원 활용이 가능해졌습니다.
Nito 네트워크 플로우 이해하기
대부분의 고객에게 AWS Nitro 환경은 블랙박스 환경으로 생각하여 최적화 부분에 어려움이 있지만 내부 동작을 이해하면 훨씬 정교한 성능 튜닝이 가능합니다. 먼저, 단일 패킷이 애플리케이션에서 출발해 커널, 드라이버, Nitro 카드를 거쳐 상대 인스턴스까지 어떻게 전달되는지 알아보겠습니다.
- 애플리케이션 레벨: 웹 서버에서 다른 내부 앱 서버로 HTTP 요청을 보내는 상황을 생각해보겠습니다. 애플리케이션은 TCP 소켓을 열고 DNS로 IP 주소를 확인한 뒤 목적지 IP, 소스 IP, 프로토콜(TCP), 소스 포트, 목적지 포트로 이루어진 5-tuple을 형성합니다.
- 커널 및 드라이버: 5-tuple을 바탕으로 라우팅이 결정되고, ENA(Elastic Network Adapter) 드라이버를 통해 패킷이 Nitro 카드로 전달됩니다. 인스턴스 내부에서는 송신 큐(TX ring)와 수신 큐(RX ring)가 있으며, 패킷은 이 큐를 거쳐 Nitro 카드로 이동합니다.
- Nitro 내부 처리: Nitro 카드는 패킷을 받아 VPC 라우팅 테이블, 네트워크 액세스 제어 리스트(NACL), 보안 그룹(Security Group) 규칙을 적용합니다. Nitro가 처음 보는 패킷이라면, 경로 확인을 위해 내부 매핑 서비스에 질의하여 목적지 인스턴스의 위치를 찾고 상태(Flow State)를 구축합니다. 최초 패킷은 상태 구축 때문에 약간의 오버헤드가 있습니다.
- 초기 설정 후 가속: 최초 요청 이후 응답 패킷을 받으면 이제 플로우가 완전하게 설정되고(connection tracking) Nitro는 플로우 캐시를 활용하여 이후 패킷을 가속 처리합니다(Accelerated Flow). 이후 왕복 트래픽은 훨씬 적은 처리 오버헤드로 빠르게 전달됩니다.
정리하자면, 첫 패킷은 Nitro가 상태를 만드는 초기화 과정 때문에 조금 느려질 수 있지만, 이후 플로우가 확립되면 가속 모드로 전환되어 높은 처리량과 낮은 지연을 달성합니다.
플로우(Flow)는 TCP 연결처럼 일정 기간 지속되는 스트림입니다. 한 번 플로우가 확립되면 Nitro는 더 이상 매번 라우팅, NAC, SG를 전부 재확인하지 않고, 플로우 캐시를 통해 패킷을 빠르게 전달합니다. 이를 통해 최대 5Gbps(기본 상황) 단일 플로우 성능을 얻을 수 있고, 클러스터 플레이스먼트 그룹(CPG)을 사용할 경우 최대 10Gbps, ENA Express 사용 시 최대 25Gbps 단일 플로우 성능을 달성할 수도 있습니다.
패킷 크기에 따라 처리가 PPS(패킷당 처리율) 제약인지, BPS(비트당 처리율) 제약인지 달라질 수 있습니다. 작은 패킷일수록 PPS 한계에 먼저 도달하고, 큰 패킷일수록 BPS 한계에 먼저 도달합니다.
다수의 플로우가 있을 경우, Nitro는 5-tuple 해싱을 통해 다른 큐로 패킷을 분산시키며, 이를 통해 멀티코어 CPU 상에서 처리 병렬성을 극대화합니다. 예를 들어 단일 플로우가 5Gbps에 묶여 있다면, 다중 플로우로 나누어 각각 5Gbps씩 여러 큐에 분산하면 인스턴스의 총 처리량을 올릴 수 있기 때문에 인스턴스의 총 처리 성능을 수평 확장할 수 있습니다.
Nitro 네트워크 시스템 최적화 하기
Microburst란 매우 짧은 시간(수 초 미만)에 트래픽이 급상승하는 현상을 의미합니다. 모니터링 툴은 주로 1분 평균값을 제공하기 때문에, 실제로 1초 동안 10Gbps를 쏴도 1분 평균을 보면 1Gbps로 평활화되는 문제가 발생합니다. 이는 성능 모니터링과 트러블슈팅을 까다롭게 만듭니다.
패킷이 순간적으로 몰려 큐가 가득 차면 패킷 드롭이 발생하고, 지연이 커질 수 있습니다. 이를 완화하기 위한 방법은 다음과 같습니다.
- 큐 심화(Q-depth) 조정: RX/TX 링 깊이를 늘려 일시적인 버스트를 흡수할 수 있습니다.
- 트래픽 컨트롤(TC) 활용: 리눅스의 Qdisc를 사용해 전송 레이트를 제어함으로써 인스턴스가 허용하는 수준으로 신호를 줄여버릴 수 있습니다.
- ENA Express 사용: Nitro v4 이상에서는 SRD 기반 혼잡 제어를 지원하는 ENA Express로 인캐스트(in-cast)나 RX 마이크로버스트 문제를 완화할 수 있습니다.
ENA Express는 ML/HPC 워크로드에서 이미 검증된 SRD(Scalable Reliable Datagram) 기반 혼잡 제어 기술을 일반 TCP/UDP 트래픽에도 적용한 기능입니다. Nitro v4 이상 인스턴스에서 사용 가능하며, 별도 Opt-in으로 활성화할 수 있습니다.
VPC 환경에서 NACL과 SG는 플로우 상태에 영향을 미칩니다.
- NACL(비상태적): 특정 방향 트래픽 허용/차단 규칙 변경 시 기존 플로우를 재평가하게 됩니다. 예를 들어 더 제한적인 NACL로 바꾸면 기존 연결이 끊길 수 있습니다.
- SG(상태 추적형): 첫 패킷 허용 시 반대 방향도 자동 허용하는 특성이 있습니다. 규칙을 더 엄격하게 바꾸면 플로우를 재평가하여 연결이 단절 될 수 있으나, 반대로 완화하면 기존 플로우는 그대로 유지됩니다.
Untracked/Tracked Connection은 HTTP(80/443)처럼 널리 허용되고 상태 추적이 크게 필요 없는 트래픽은 Untracked Connection으로 처리해 Nitro가 상태를 매번 검사하는 부담을 줄여 성능을 향상시킬 수 있습니다. 반면 SSH(22)처럼 민감한 트래픽은 Tracked 상태를 유지해 보안성을 강화할 수 있습니다. 이를 통해 Nitro 내부 상태 검사 부담과 보안 수준 사이의 균형을 상황에 따라 조정할 수 있습니다.
지연을 줄이기 위한 다음과 같은 고려사항도 존재합니다.
- 클러스터 플레이스먼트 그룹(CPG): 인스턴스를 물리적으로 인접하게 배치해 RTT(왕복 시간)를 단축합니다. 이는 단일 플로우 성능 향상뿐 아니라 레이턴시도 줄여 고성능 애플리케이션에 유리합니다.
- DPDK 활용: 커널 네트워킹 스택을 우회해 유저 스페이스에서 패킷 처리를 수행, 커널 오버헤드를 줄여 레이턴시를 단축할 수 있습니다.
- C-state 제어: CPU를 C0 상태로 고정하여 전력 소비는 늘지만 레이턴시를 최소화할 수 있습니다.
- 인터럽트 모드레이션(Interrupt Moderation): 패킷 수신 시 매번 인터럽트를 걸지 않고 20~64마이크로초 단위로 인터럽트를 모아 처리(정적 모드)하거나, 동적 모드레이션으로 상황에 따라 빈도를 조정하면 레이턴시와 PPS 간 균형을 유지할 수 있습니다.
- Pull Mode Operation: CPU가 지속적으로 NIC 큐를 폴링(Polling)하여 패킷 도착 즉시 처리, 레이턴시를 극단적으로 낮출 수 있지만 전력 소비 증가라는 트레이드오프가 있습니다.
Nitro 시스템의 성능을 극대화하기 위해서는 체계적이고 단계적인 접근이 필수적입니다. 먼저 애플리케이션의 트래픽 특성을 면밀히 파악한 뒤, 이를 바탕으로 상세한 트래픽 프로파일을 작성하고 Nitro 인스턴스의 제한 사항을 정확히 분석합니다. 이후 테스트 환경에서 배포와 검증을 통해 성능을 확인하며, 최신 드라이버 및 모니터링 도구를 활용해 지속적으로 지표를 점검하고, 최종적으로 튜닝과 CPU 상태 관리를 통해 네트워크 성능과 효율성을 최적화할 수 있습니다.
결론
이번 가이드를 통해 Nitro 시스템의 복잡한 구조와 동작 원리를 체계적으로 이해할 수 있었습니다. 특히, Nitro가 단순한 네트워크 장비를 넘어 서버의 전반적인 성능과 효율성을 어떻게 향상시키는지에 대한 깊은 통찰을 얻을 수 있었습니다.이를 통해 Nitro의 처리 능력을 정확히 파악하고 최적화 전략을 수립하는 것이 네트워크 성능 향상에 얼마나 중요한지 깨달았습니다. 또한, Nitro의 플로우 캐시와 다중 플로우 처리 메커니즘이 대규모 트래픽 환경에서의 성능을 어떻게 극대화하는지 이해하게 되었습니다.
Nitro 시스템을 최적화하는 과정은 처음에는 복잡하고 어려울 수 있지만, 체계적으로 접근하면 그 효율성과 성능 향상폭이 높게 나타납니다. 특히, CPU 상태 관리와 같은 세부적인 최적화 기법을 통해 전력 소비와 성능 간의 균형을 맞추는 것이 얼마나 중요한지 실감할 수 있었습니다. 이번 세션을 통해서 Nitro의 잠재력을 최대한 활용하는 방법을 배울 수 있었으며, 이는 앞으로의 네트워크 관리와 최적화에 큰 도움이 될 수 있을 것이라 기대합니다.