저지연 트레이딩 시스템에서 NIC Offload와 Kernel Networking이 중요한 이유 | Trading Engineering — Deep Dive #7
저지연 트레이딩 시스템에서 NIC Offload와 Kernel Networking이 중요한 이유
Trading Engineering — Deep Dive #7
저지연 트레이딩 시스템에서 네트워크 성능을 이야기할 때 흔히 CPU, Kernel, Socket, TCP/UDP에 집중합니다.
하지만 그보다 먼저 데이터를 받아들이는 장치가 있습니다.
바로 NIC(Network Interface Card) 입니다.
NIC는 단순히 네트워크 케이블을 연결하는 장치가 아닙니다.
최근의 고성능 NIC는
- Packet Receive / Transmit
- DMA
- Checksum 계산
- Packet Segmentation
- Receive Queue 분배
- RSS
- Multi-Queue
- Interrupt 생성
등 다양한 기능을 하드웨어에서 처리할 수 있습니다.
따라서 저지연 시스템에서는
NIC → CPU → Memory → Kernel → Application
전체 경로를 하나의 시스템으로 바라볼 필요가 있습니다.

1. NIC는 어떤 역할을 하는가?
가장 단순한 구조를 생각해보겠습니다.
Network
↓
NIC
↓
Server
↓
CPU / Memory
NIC는 네트워크에서 들어오는 Packet을 받아 서버의 Memory로 전달하고, 반대로 서버가 전송하는 데이터를 Network로 내보냅니다.
하지만 실제 NIC는 이것보다 훨씬 많은 기능을 수행합니다.
NIC의 주요 기능
- Packet I/O
- DMA(Direct Memory Access)
- Hardware Offload
- Receive Queue / Transmit Queue
- RSS(Receive Side Scaling)
- Interrupt Generation
- VLAN 처리 등
즉,
NIC는 CPU가 처리해야 할 네트워크 작업의 일부를 하드웨어에서 대신 처리할 수 있습니다.
이것이 바로 NIC Offload의 핵심입니다.
2. 일반적인 Packet Processing Path
전통적인 Linux Networking 경로를 단순화하면 다음과 같습니다.
NIC
↓
Driver
↓
Interrupt / NAPI
↓
Kernel
↓
Network Stack
↓
Socket
↓
Application
예를 들어 거래소에서 Market Data Packet이 들어온다고 생각해보겠습니다.
Exchange
↓
Network
↓
NIC
↓
Driver
↓
Kernel Network Stack
↓
Socket
↓
Market Data Handler
↓
Order Book
↓
Strategy
이 과정에는 여러 계층이 존재합니다.
각 계층은 안정성과 범용성을 제공하지만 동시에 처리해야 할 작업도 증가합니다.
저지연 시스템에서는 바로 이 지점이 중요합니다.
3. NIC Offload란 무엇인가?
NIC Offload는 원래 CPU나 Kernel이 처리하던 일부 네트워크 작업을 NIC 하드웨어가 대신 처리하는 기술입니다.
대표적인 예가 다음과 같습니다.
Checksum Offload
TCP/IP Packet의 Checksum 계산과 검증을 NIC가 수행합니다.
TSO
TCP Segmentation Offload
CPU가 큰 TCP 데이터를 작은 Packet으로 직접 분할하는 대신 NIC가 segmentation을 수행하도록 합니다.
GSO
Generic Segmentation Offload
Kernel이 큰 Packet 형태로 데이터를 처리한 뒤 실제 전송 과정에서 segmentation하도록 하는 방식입니다.
GRO
Generic Receive Offload
여러 개의 작은 수신 Packet을 Kernel Network Stack에서 하나의 큰 Packet처럼 합쳐 처리할 수 있도록 합니다.
LRO
Large Receive Offload
NIC 또는 driver 수준에서 여러 Packet을 합쳐 처리하는 방식입니다.
VLAN Offload
VLAN tagging / stripping 등의 작업을 NIC가 처리할 수 있습니다.
4. DMA와 Memory Flow
NIC에서 특히 중요한 것이 DMA(Direct Memory Access) 입니다.
Packet이 들어오면 NIC는 CPU가 Packet 데이터를 하나씩 직접 복사하도록 기다리는 대신 DMA를 이용해 Host Memory에 데이터를 전달할 수 있습니다.
개념적으로 보면 다음과 같습니다.
DMA
NIC ─────────────────→ Memory
↑
│
CPU
CPU가 Packet 데이터 자체를 매번 직접 이동시키는 부담을 줄일 수 있습니다.
하지만 여기서 중요한 점이 있습니다.
DMA가 있다고 해서 CPU가 네트워크 처리에서 완전히 사라지는 것은 아닙니다.
CPU는 여전히
- Descriptor 관리
- Interrupt / NAPI 처리
- Network Stack 처리
- Protocol 처리
- Application 처리
등을 수행할 수 있습니다.
따라서 정확하게는
DMA는 데이터 이동에 필요한 CPU 개입을 줄이는 기술이지, 네트워크 처리 전체를 CPU에서 제거하는 기술은 아닙니다.
이 차이를 이해하는 것이 중요합니다.
5. RSS와 Multi-Queue
고성능 NIC에서 또 하나 중요한 기능이 RSS(Receive Side Scaling) 입니다.
서버에 CPU Core가 하나뿐이라면 모든 Packet을 하나의 CPU가 처리해도 됩니다.
하지만 현대 서버는 수십 개 이상의 CPU Core를 가지고 있습니다.
따라서 Network Packet을 여러 Queue로 분산시키고 여러 CPU Core가 병렬로 처리하도록 할 수 있습니다.
Incoming Packets
↓
RSS
┌─────────┼─────────┐
↓ ↓ ↓
RX Queue0 RX Queue1 RX Queue2
↓ ↓ ↓
CPU 0 CPU 1 CPU 2
이렇게 하면 Network Processing을 여러 CPU Core에 분산할 수 있습니다.
6. RSS가 항상 좋은 것은 아니다
여기서도 저지연 시스템에서는 단순히
"Queue를 많이 만들면 빠르다."
라고 생각하면 안 됩니다.
중요한 것은 어떤 Queue가 어떤 CPU에서 처리되는가입니다.
예를 들어,
NIC Queue 0
↓
CPU 0
↓
NUMA Node 0
와
NIC Queue 0
↓
CPU 8
↓
NUMA Node 1
은 같은 서버 안에서도 Memory 접근 특성이 달라질 수 있습니다.
따라서 NIC Queue를 설정할 때는
- CPU Core
- CPU Affinity
- IRQ Affinity
- NUMA Node
- Memory Placement
를 함께 고려해야 합니다.
7. NIC Queue와 NUMA
이 부분은 이전 Deep Dive #4에서 설명했던 NUMA와 직접 연결됩니다.
예를 들어 서버가 다음과 같다고 가정해보겠습니다.
NUMA Interconnect
┌─────────────────────────┐
│ │
NUMA Node 0 NUMA Node 1
NIC CPU Core
↓ ↓
RX Queue Strategy
↓ ↓
CPU Core Local Memory
↓
Local Memory
가장 이상적인 구조는 Network Packet이 들어온 NIC와 이를 처리하는 CPU 및 Memory가 가능한 한 가까운 구조입니다.
즉,
NIC Locality + CPU Affinity + Memory Locality
를 함께 설계해야 합니다.
8. Interrupt, NAPI와 NIC
Deep Dive #6에서 Interrupt와 Polling을 살펴봤습니다.
NIC가 Packet을 받으면 일반적인 Linux 환경에서는 다음과 같은 흐름이 발생할 수 있습니다.
Packet Arrival
↓
NIC
↓
Interrupt
↓
NAPI
↓
Kernel
↓
Network Stack
Linux의 NAPI는 높은 Packet Rate 환경에서 Interrupt만 계속 발생시키는 부담을 줄이기 위해 Interrupt와 Polling 방식을 결합합니다.
즉,
Packet이 들어올 때는 Interrupt를 이용해 CPU에 알리고, 이후 일정량의 Packet을 Polling 방식으로 처리하는 구조
를 사용할 수 있습니다.
이 구조는 높은 Packet Rate에서 Interrupt Storm을 줄이고 효율적인 Packet Processing을 가능하게 합니다.
9. Interrupt Affinity도 중요하다
NIC가 여러 Queue를 가지고 있다면 각 Queue에서 발생하는 Interrupt가 어떤 CPU에서 처리되는지도 중요합니다.
예를 들어,
RX Queue 0 → CPU 0
RX Queue 1 → CPU 1
RX Queue 2 → CPU 2
RX Queue 3 → CPU 3
와 같이 구성할 수 있습니다.
하지만 Application Thread가
Strategy → CPU 8
에서 실행되고 있는데 Network Interrupt가 CPU 0에서 계속 발생한다면 데이터 처리 경로가 분리될 수 있습니다.
따라서 저지연 환경에서는
NIC Queue → IRQ → CPU → Application Thread
의 관계를 함께 확인해야 합니다.
10. Offload가 항상 Latency를 줄이는 것은 아니다
여기서 중요한 함정이 있습니다.
Offload = 무조건 빠름
은 아닙니다.
Offload는 CPU 부담을 줄이고 처리량을 높이는 데 상당히 유용하지만 일부 기능은 Packet을 모아서 처리하기 때문에 Latency와 Trade-off가 발생할 수 있습니다.
예를 들어 GRO와 같은 Packet Aggregation은 여러 Packet을 합쳐 처리함으로써 CPU 효율을 높일 수 있습니다.
하지만 극단적인 저지연 환경에서는
"조금 더 모아서 효율적으로 처리하는 것"
보다
"Packet 하나를 가능한 빨리 처리하는 것"
이 중요할 수도 있습니다.
따라서 일반적인 서버 환경과 Low-Latency Trading 환경의 최적 설정은 다를 수 있습니다.
11. Throughput과 Latency는 같은 목표가 아니다
이것은 금융 시스템에서 특히 중요합니다.
일반적인 서버는 다음을 중요하게 생각할 수 있습니다.
High Throughput
↓
Efficient Processing
↓
Lower CPU Usage
반면 초저지연 시스템에서는 다음이 중요할 수 있습니다.
Packet Arrival
↓
Minimum Processing Delay
↓
Predictable Latency
↓
Low Tail Latency
따라서 CPU 사용률이 낮아졌다고 반드시 시스템이 좋아진 것은 아닙니다.
예를 들어
CPU Usage ↓
Throughput ↑
Average Latency ↓
P99 Latency ↑
와 같은 상황도 가능합니다.
저지연 시스템에서는 평균값만 보면 안 되는 이유입니다.
12. Trading System에서는 어떻게 활용되는가?
예를 들어 Market Data 시스템을 생각해보겠습니다.
Exchange
↓
Network
↓
NIC
↓
RX Queue
↓
CPU Core
↓
Market Data Handler
↓
Order Book
↓
Strategy
여기서 중요한 요소는
- NIC 성능
- RX Queue
- RSS
- IRQ Affinity
- CPU Affinity
- NUMA
- Memory Locality
- Kernel Network Stack
- Application Processing
입니다.
그리고 Order FEP라면 반대 방향도 중요합니다.
Application
↓
Order
↓
Socket
↓
Kernel Network Stack
↓
Driver
↓
NIC
↓
Network
↓
Exchange
즉 Receive Path와 Transmit Path를 모두 봐야 합니다.
13. NIC는 하나의 부품이 아니라 Data Path의 일부다
저지연 시스템을 설계할 때 다음과 같이 생각하면 편합니다.
NIC
↓
Queue
↓
CPU
↓
Cache
↓
Memory
↓
Application
각각을 따로 최적화하는 것보다 전체 경로를 함께 보는 것이 중요합니다.
예를 들어 아무리 빠른 NIC를 사용하더라도
- 잘못된 CPU Affinity
- 잘못된 NUMA 배치
- 불필요한 Memory Copy
- 과도한 Lock
- Cache Miss
- 불필요한 Context Switch
가 발생하면 전체 Latency는 증가할 수 있습니다.
14. 그렇다면 NIC Offload를 어떻게 확인할까?
Linux에서는 NIC 설정을 확인할 때 ethtool을 많이 사용할 수 있습니다.
예를 들어:
ethtool -k eth0
를 이용하면 NIC의 다양한 Offload 설정을 확인할 수 있습니다.
또한 다음과 같은 항목을 확인할 수 있습니다.
ethtool -l eth0
ethtool -S eth0
이를 통해
- Channel / Queue
- RX/TX statistics
- Packet drops
- Error
- Queue 관련 통계
등을 확인할 수 있습니다.
CPU와 IRQ 상태도 함께 확인해야 합니다.
cat /proc/interrupts
그리고 NUMA 환경에서는
numactl --hardware
등을 통해 CPU와 Memory topology를 확인할 수 있습니다.
핵심은 NIC 설정만 보는 것이 아니라 NIC → CPU → Memory → Application을 함께 보는 것입니다.
15. NIC Offload와 Kernel Bypass의 관계
여기서 자연스럽게 다음 질문이 나옵니다.
"Kernel Network Stack 자체가 비용이라면 Kernel을 아예 거치지 않으면 더 빠르지 않을까?"
이 질문에서 등장하는 것이 바로 Kernel Bypass입니다.
일반적인 구조는
NIC
↓
Driver
↓
Kernel
↓
Network Stack
↓
Socket
↓
Application
입니다.
Kernel Bypass 계열의 접근에서는 이 경로에서 Kernel의 역할을 줄이고 Packet을 User Space에서 직접 처리하는 구조를 사용할 수 있습니다.
NIC
↓
User Space Networking
↓
Application
대표적으로 DPDK, AF_XDP, Onload 계열 등의 기술이 있습니다.
물론 각각 구조와 목적은 다릅니다.
그리고 중요한 것은,
Kernel Bypass 역시 무조건 빠른 것은 아닙니다.
구현 복잡도, CPU 사용량, Memory 관리, Queue 관리, NUMA, NIC 지원 여부 등을 모두 고려해야 합니다.
이 부분은 다음 글에서 본격적으로 살펴보겠습니다.
16. 저지연 트레이딩 시스템에서의 핵심 체크포인트
NIC와 Kernel Networking을 최적화할 때는 다음 항목을 함께 확인할 필요가 있습니다.
NIC
- NIC 모델
- Link Speed
- RX/TX Queue
- RSS
- Offload 설정
- Packet Drop
CPU
- CPU Affinity
- IRQ Affinity
- CPU Core 배치
- Context Switch
- CPU Migration
Memory
- NUMA Node
- Memory Locality
- Cache Miss
- Memory Bandwidth
Network
- Packet Rate
- Packet Size
- Interrupt Rate
- Batch Size
- RX/TX latency
Application
- Socket 처리
- Memory Copy
- Lock
- Queue
- Parsing
- End-to-End Latency
그리고 최종적으로는
P50 / P95 / P99 / P99.9
와 같은 Tail Latency를 확인해야 합니다.
17. FontesFintech Engineering Approach
저지연 시스템에서는 특정 기능 하나를 무조건 활성화하거나 비활성화하는 방식보다 전체 Data Path를 기준으로 판단하는 것이 중요합니다.
예를 들어 NIC Offload가 CPU 사용량을 크게 줄였다고 하더라도 실제 거래 시스템의 P99 Latency가 증가한다면 다시 검토해야 합니다.
반대로 CPU 사용량이 증가하더라도
- Latency가 감소하고
- Tail Latency가 안정되고
- Throughput이 충분하다면
그 설정이 해당 시스템에는 더 적합할 수 있습니다.
따라서 저지연 시스템에서는
Configuration → Measurement → Benchmark → Comparison
의 반복이 중요합니다.
특히 NIC, CPU, NUMA, Kernel을 각각 따로 최적화하기보다
NIC → CPU → Memory → Application
전체 경로를 하나의 시스템으로 보고 접근하는 것이 중요합니다.
Conclusion
NIC는 단순히 Network Cable을 연결하는 장치가 아닙니다.
현대의 NIC는
- DMA
- Hardware Offload
- RSS
- Multi-Queue
- Interrupt
- Packet Processing
등 다양한 기능을 수행합니다.
그리고 이러한 기능은 CPU, Kernel, Memory, NUMA와 직접 연결되어 있습니다.
따라서 저지연 트레이딩 시스템에서는
NIC → Queue → CPU → Cache → Memory → Kernel → Application
전체 Data Path를 이해해야 합니다.
특히 중요한 것은 Latency와 Throughput 사이의 Trade-off입니다.
일반적인 서버에서 좋은 설정이 초저지연 트레이딩 시스템에서도 반드시 좋은 것은 아닙니다.
결국 중요한 것은 특정 기술을 사용하는 것이 아니라,
Measure → Understand → Configure → Benchmark
하는 것입니다.
The NIC is not just a card.
It's the first step in your data path.
Next — Trading Engineering Deep Dive #8
Kernel Bypass와 User-Space Networking이 저지연 트레이딩 시스템에서 중요한 이유
다음 글에서는 오늘 살펴본 Kernel Networking의 다음 단계로 넘어가서, DPDK, AF_XDP, Onload 계열 기술이 기존 Linux Networking Path를 어떻게 바꾸는지를 본격적으로 살펴보겠습니다.