Linux 기반 EC2 인스턴스의 네트워크 지연 시간 개선
Linux 기반 EC2 인스턴스의 네트워크 지연 시간 개선 (Improve network latency for Linux based EC2 instances)
네트워크 지연 시간(latency)은 데이터 패킷이 출발지에서 목적지까지 이동하는 데 걸리는 시간이에요. 네트워크를 통해 데이터를 보내는 애플리케이션은 긍정적인 사용자 경험을 위해 적시에 응답을 받아야 해요. 높은 네트워크 지연 시간은 다음과 같은 다양한 문제로 이어질 수 있어요.
출처: 문서
본문
- 웹 페이지의 느린 로드 시간
- 비디오 스트림 지연
- 온라인 리소스 접근 어려움
이 섹션은 Linux에서 실행되는 Amazon EC2 인스턴스의 네트워크 지연 시간을 개선하기 위해 취할 수 있는 단계를 설명해요. 최적의 지연 시간을 얻으려면 다음 단계에 따라 인스턴스, 커널, ENA 드라이버 설정을 구성해요. 추가 구성 지침은 GitHub의 ENA Linux Driver Best Practices and Performance Optimization Guide를 참고하세요.
참고 단계와 설정은 특정 네트워크 하드웨어, 인스턴스를 시작한 AMI, 애플리케이션 사용 사례에 따라 약간 다를 수 있어요. 변경하기 전에 네트워크 성능을 철저히 테스트하고 모니터링해서 원하는 결과를 얻고 있는지 확인해요.
데이터 패킷의 네트워크 홉 수 줄이기 (Reduce the number of network hops for data packets)
데이터 패킷이 라우터에서 라우터로 이동하면서 거치는 각 홉(hop)은 네트워크 지연 시간을 늘려요. 일반적으로 트래픽은 목적지에 도달하기 위해 여러 홉을 거쳐야 해요. Amazon EC2 인스턴스의 네트워크 홉을 줄이는 방법은 두 가지예요.
- 클러스터 배치 그룹(Cluster placement group) – 클러스터 배치 그룹을 지정하면 Amazon EC2가 물리적으로 같은 가용 영역(AZ) 안에서 더 빡빡하게 배치된 인접한 인스턴스를 시작해요. 그룹의 인스턴스가 물리적으로 가깝기 때문에 고속 연결을 활용할 수 있어서 낮은 지연 시간과 높은 단일 흐름 처리량을 얻을 수 있어요.
- 전용 호스트(Dedicated Host) – 전용 호스트는 여러분의 사용을 위해 전용된 물리 서버예요. 전용 호스트를 사용하면 인스턴스를 같은 물리 서버에서 실행하도록 시작할 수 있어요. 같은 전용 호스트에서 실행되는 인스턴스 간의 통신은 추가 네트워크 홉 없이 일어날 수 있어요.
Linux 커널 구성이 지연 시간에 미치는 영향 (How Linux kernel configuration affects latency)
Linux 커널 구성은 네트워크 지연 시간을 늘리거나 줄일 수 있어요. 지연 최적화 목표를 달성하려면 워크로드의 특정 요구 사항에 따라 Linux 커널 구성을 미세 조정하는 것이 중요해요.
네트워크 지연 시간을 줄이는 데 도움이 될 수 있는 Linux 커널 구성 옵션은 많아요. 가장 영향력 있는 옵션은 다음과 같아요.
- Busy poll 모드 활성화 – Busy poll 모드는 네트워크 수신 경로에서 지연 시간을 줄여요. busy poll 모드를 활성화하면 소켓 계층 코드가 네트워크 장치의 수신 큐를 직접 폴링할 수 있어요. busy polling의 단점은 빡빡한 루프에서 새 데이터를 폴링하는 호스트의 CPU 사용률이 더 높아진다는 것이에요. 모든 인터페이스에 대해 패킷을 기다리는 마이크로초를 제어하는 전역 설정 두 가지가 있어요.
busy_read– 소켓 읽기를 위한 저지연 busy poll 타임아웃. 장치 큐에서 소켓 계층이 패킷을 읽을 때까지 기다릴 마이크로초 수를 제어해요. sysctl 명령으로 이 기능을 전역적으로 활성화하려면 Linux Kernel 조직이 50 마이크로초 값을 권장해요. 자세한 내용은 Linux kernel user's and administrator's guide의 busy_read를 참고하세요.
[ec2-user ~]$ sudo sysctl -w net.core.busy_read=50
busy_poll– poll과 select를 위한 저지연 busy poll 타임아웃. 이벤트를 기다릴 마이크로초 수를 제어해요. 폴링하는 소켓 수에 따라 권장 값은 50-100 마이크로초예요. 소켓을 추가할수록 숫자가 높아져야 해요.
[ec2-user ~]$ sudo sysctl -w net.core.busy_poll=50
- CPU 전원 상태(C-states) 구성 – C-states는 코어가 비활성일 때 들어갈 수 있는 절전 수준을 제어해요. 지연 시간과 성능을 위해 시스템을 튜닝하려면 C-states를 제어하고 싶을 수 있어요. 더 깊은 C-states에서 CPU는 본질적으로 "잠들어" 있으며, 깨어나 활성 상태로 전환될 때까지 요청에 응답할 수 없어요. 코어를 절전 상태로 만드는 데 시간이 걸리며, 절전 코어는 다른 코어가 더 높은 주파수로 부스트할 수 있는 여유를 허용하지만, 그 절전 코어가 깨어나 작업을 수행하는 데도 시간이 걸려요. 예를 들어 네트워크 패킷 인터럽트를 처리하도록 할당된 코어가 절전 상태라면 해당 인터럽트를 처리하는 데 지연이 있을 수 있어요. 더 깊은 C-states를 사용하지 않도록 시스템을 구성할 수 있어요. 하지만 이 구성은 프로세서 반응 지연 시간을 줄이는 대신, 다른 코어가 Turbo Boost에 사용할 수 있는 여유도 줄여요. 프로세서 반응 지연 시간을 줄이려면 더 깊은 C-states를 제한할 수 있어요. 자세한 내용은 Amazon Linux 2 User Guide의 High performance and low latency by limiting deeper C-states를 참고하세요.
인터럽트 조절 (Interrupt moderation)
ENA 네트워크 드라이버는 인스턴스와 네트워크 간의 통신을 가능하게 해요. 드라이버는 네트워크 패킷을 처리해 네트워크 스택이나 Nitro 카드로 전달해요. 네트워크 패킷이 들어오면 Nitro 카드가 이벤트를 소프트웨어에 알리기 위해 CPU에 인터럽트를 생성해요.
인터럽트 (Interrupt)
인터럽트는 장치나 애플리케이션이 프로세서로 보내는 신호예요. 인터럽트는 이벤트가 발생했거나 즉각적인 주의가 필요한 조건이 충족되었음을 프로세서에 알려요. 인터럽트는 네트워크 인터페이스에서 데이터 받기, 하드웨어 이벤트 처리, 다른 장치의 요청 처리 같은 시간에 민감한 작업을 처리할 수 있어요.
인터럽트 조절 (Interrupt moderation)
인터럽트 조절은 장치가 생성하는 인터럽트 수를 집계하거나 지연시켜 줄이는 기술이에요. 인터럽트 조절의 목적은 많은 수의 인터럽트 처리와 관련된 오버헤드를 줄여 시스템 성능을 개선하는 것이에요. 인터럽트가 너무 많으면 CPU 사용률이 높아져 처리량에 부정적 영향을 미치고, 인터럽트가 너무 적으면 지연 시간이 늘어나요.
동적 인터럽트 조절 (Dynamic interrupt moderation)
동적 인터럽트 조절은 현재 시스템 부하와 트래픽 패턴에 따라 인터럽트 비율을 동적으로 조정하는 향상된 형태의 인터럽트 조절이에요. 인터럽트 오버헤드와 초당 패킷 수 혹은 대역폭 사이의 균형을 맞추는 것을 목표로 해요. 참고 동적 인터럽트 조절은 일부 AMI에서 기본적으로 활성화되어 있어요(하지만 모든 AMI에서 활성화/비활성화할 수 있어요).
네트워크 지연 시간을 최소화하려면 인터럽트 조절을 비활성화해야 할 수 있어요. 하지만 이는 인터럽트 처리의 오버헤드를 증가시킬 수도 있어요. 지연 시간을 줄이는 것과 오버헤드를 최소화하는 것 사이의 올바른 균형을 찾는 것이 중요해요. ethtool 명령이 인터럽트 조절을 구성하는 데 도움이 될 수 있어요. 기본적으로 rx-usecs는 20으로, tx-usecs는 64로 설정돼요.
현재 인터럽트 수정 구성 정보를 얻으려면 다음 명령을 사용해요.
[ec2-user ~]$ ethtool -c interface | egrep "rx-usecs:|tx-usecs:|Adaptive RX"
Adaptive RX: on TX: off
rx-usecs: 20
tx-usecs: 64
인터럽트 수정과 동적 인터럽트 조절을 비활성화하려면 다음 명령을 사용해요.
[ec2-user ~]$ sudo ethtool -C interface adaptive-rx off rx-usecs 0 tx-usecs 0