본문 바로가기
카테고리 없음

NAPI(Network API)는 왜 리눅스 네트워크 성능을 높였을까

by by_merry 2026. 5. 25.

고성능 서버 구조를 공부하다 보면 어느 순간부터는 CPU 계산 속도보다 “패킷을 얼마나 효율적으로 처리하느냐”가 훨씬 더 중요한 문제처럼 느껴질 때가 많다. 나도 예전에는 인터넷 데이터가 그냥 네트워크 카드에서 CPU로 들어오는 단순한 흐름이라고 생각했었다. 그런데 DMA, Epoll, Zero-Copy 같은 구조를 하나씩 보다 보니까 실제 서버는 엄청난 양의 네트워크 패킷을 동시에 처리해야 하고, 그 과정에서 CPU가 단순 패킷 처리만 하다가 과부하에 걸릴 수도 있다는 걸 알게 됐다. 그리고 이런 문제를 해결하기 위해 리눅스에서 등장한 대표적인 네트워크 최적화 구조 중 하나가 바로 NAPI(Network API)다. 처음 이름만 들었을 때는 그냥 리눅스 내부 API 정도로 느껴졌는데, 구조를 이해하고 나니까 왜 현대 Linux 서버 성능에서 굉장히 중요한 역할을 하는지 조금 감이 오기 시작했다. 특히 인상 깊었던 건, NAPI가 단순히 네트워크 속도를 높이는 기술이 아니라 “인터럽트 폭주(Interrupt Storm)” 자체를 줄이기 위해 만들어진 구조라는 점이었다. 나도 처음에는 인터럽트가 CPU 성능 문제까지 연결될 거라고는 전혀 생각하지 못했다.

예전 네트워크 구조에서는 패킷마다 인터럽트가 발생했다

컴퓨터에서 네트워크 패킷이 도착하면 CPU는 그 사실을 알아야 한다. 예전 방식에서는 네트워크 카드(NIC)가 패킷 하나가 들어올 때마다 CPU에게 인터럽트(Interrupt)를 발생시키는 구조가 일반적이었다. 쉽게 말하면 “패킷 왔어요!”라고 CPU를 계속 깨우는 방식이었다. 처음에는 나도 이 방식이 굉장히 당연하게 느껴졌다. 데이터가 오면 CPU한테 바로 알려줘야 빠르게 처리할 수 있을 것 같았기 때문이다. 실제로 트래픽이 적을 때는 이런 인터럽트 기반 구조가 꽤 효율적으로 동작했다고 한다. 문제는 네트워크 속도가 빨라지고 서버 트래픽이 폭발적으로 증가하기 시작하면서 발생했다. 예를 들어 초당 수십만 개 패킷이 들어오기 시작하면 NIC는 패킷마다 계속 CPU 인터럽트를 발생시키게 된다. 결국 CPU는 실제 데이터 처리보다 인터럽트 처리 자체에 더 많은 시간을 쓰게 되는 상황이 생길 수 있었다. 나도 처음에는 “인터럽트 처리 정도야 CPU가 금방 하지 않을까?” 싶었는데, 현대 서버 환경에서는 패킷 양 자체가 워낙 많다 보니까 인터럽트만으로도 CPU 자원을 엄청 소모할 수 있다고 한다. 특히 작은 패킷이 엄청 빠르게 몰려오는 상황에서는 CPU가 거의 인터럽트 대응만 하다가 실제 애플리케이션 처리를 제대로 못 하는 경우도 생길 수 있었다고 한다. 이걸 Interrupt Storm(인터럽트 폭주)이라고 부른다는 걸 보고 처음으로 “네트워크 처리도 결국 CPU 병목 문제구나”라는 걸 느끼게 됐다.

NAPI는 인터럽트와 Polling을 섞어서 CPU 부담을 줄였다

NAPI의 핵심은 굉장히 흥미롭다. 바로 인터럽트 방식과 Polling 방식을 혼합한 구조라는 점이다. 처음에는 나도 Polling이 오히려 비효율적인 방식 아닌가 싶었다. 왜냐하면 Polling은 CPU가 직접 계속 “데이터 왔나?”를 확인하는 구조이기 때문이다. 그런데 NAPI는 상황에 따라 인터럽트와 Polling을 적절히 전환하면서 사용한다. 예를 들어 평소처럼 트래픽이 적을 때는 기존 인터럽트 기반 방식처럼 동작한다. 즉 패킷이 도착하면 NIC가 CPU를 깨운다. 하지만 패킷이 갑자기 엄청 많이 들어오기 시작하면 상황이 달라진다. CPU는 “지금 패킷 너무 많으니까 인터럽트 계속 받지 말고 내가 직접 한꺼번에 처리할게”라는 방식으로 전환한다. 즉 인터럽트를 잠시 비활성화하고 Polling 기반으로 여러 패킷을 묶어서 처리하는 것이다. 나도 처음에는 이 구조를 보고 꽤 신기했다. 예전에는 인터럽트냐 Polling이냐 둘 중 하나만 사용하는 줄 알았는데, 실제로는 서버 상황에 따라 둘을 섞어서 최적화하고 있었던 것이다. 특히 이 방식은 인터럽트 폭주를 크게 줄일 수 있어서 고속 네트워크 환경에서 CPU 사용량을 훨씬 안정적으로 유지할 수 있다고 한다. 결국 NAPI는 단순히 네트워크를 빠르게 만드는 기술이라기보다, CPU가 인터럽트 때문에 과부하에 빠지지 않도록 만드는 구조에 가까웠다.

그래서 현대 Linux 서버는 패킷 처리 자체를 최대한 효율적으로 바꾸고 있다

지금까지 공부했던 서버 최적화 흐름을 보면 공통점이 하나씩 보이기 시작한다. Epoll은 불필요한 연결 확인을 줄이고, Zero-Copy는 메모리 복사를 줄이고, io_uring은 시스템 콜 왕복을 줄이고, DMA는 CPU 없이 데이터 이동을 처리하려고 했다. 그리고 NAPI 역시 결국 같은 방향 위에 있었다. 바로 CPU가 불필요한 작업에 시간을 쓰지 않게 만드는 것이다. 특히 현대 데이터센터나 대규모 웹서비스 환경에서는 초당 엄청난 양의 네트워크 패킷이 계속 들어오기 때문에, 인터럽트 처리조차 큰 병목이 될 수 있다고 한다. 그래서 Linux 커널은 단순히 “빠르게 계산하는 구조”보다 “패킷 흐름을 얼마나 효율적으로 관리할 것인가”에 훨씬 집중하게 된 것이다. 나도 처음에는 서버 최적화라는 게 그냥 비싼 CPU 쓰는 문제라고 생각했는데, 실제로는 운영체제 커널과 NIC, 메모리, CPU 캐시 구조까지 전부 연결된 엄청 복잡한 흐름이라는 걸 느끼게 됐다. 특히 NAPI는 현대 Linux 네트워크 구조가 왜 이벤트 기반과 배치 처리(batch processing)를 중요하게 생각하는지를 보여주는 대표적인 기술처럼 느껴졌다. 결국 현대 서버는 단순 계산 성능 경쟁이 아니라, 얼마나 CPU를 덜 괴롭히고 데이터 흐름을 효율적으로 유지할 수 있느냐가 핵심이 된 것이다.

한 줄로 정리하면 NAPI는 인터럽트와 Polling 방식을 상황에 따라 혼합하여 사용하는 Linux 네트워크 처리 구조이며, 인터럽트 폭주를 줄여 고속 네트워크 환경에서 CPU 부담을 크게 낮추는 중요한 최적화 기술이다.