Byeo

Understanding Host Network Stack Overheads 1 / 네트워크 스택 비용의 이해 1 본문

프로그래밍 (Programming)/논문 (Paper)

Understanding Host Network Stack Overheads 1 / 네트워크 스택 비용의 이해 1

BKlee 2023. 7. 16. 21:22
반응형

Understanding Host Network Stack Overheads

해당 논문은 Sigcomm 21년에 공개된 논문으로, 현존 NIC이 제공하는 기능들, 커널의 네트워크 스택의 작업, 그리고 CPU 사이에서의 연관관계를 잘 정리하였다. [링크

 

초록

 Moore의 법칙과 Dennard 스케일링이 더 이상 적용되지 않아 host CPU의 성능은 그대로인 반면, 네트워크의 대역폭은 꾸준히 증가함에 따라 기존의 네트워크 스택은 한계에 도달했다. 대안으로 하드웨어 오프로딩, Linux 커널을 탈피하고 유저 레벨 네트워크 스택을 구현하는 방법, 또는 FPGA와 같이 특별한 하드웨어를 사용하는 방법 등을 선택하고 있다.

 

 해당 논문은 100Gbps를 처리해야 하는 Linux 커널이 'CPU 속도와 개수', 'CPU 캐시 사이즈', 'NIC 버퍼 사이즈' 등의 다양한 자원을 고려하여 어떠한 부담을 지는지 측정하였다. 이러한 분석을 통해서 결과적으로 네트워크 스택과 CPU 사이의 비효율적인 구현이 CPU scalability에 한계가 있음을 지적하고 차기 운영체제, 프로토콜, 하드웨어 등을 논의한다.

 

Glossary

  • Moore's law: 트랜지스터의 개수가 2년마다 2배가 된다는 관측 (법칙이 아닌 역사적인 흐름의 의미) [위키]
  • Dennard scaling: 반도체에서 트랜지스터의 크기가 작아질수록 필요 전력 비용이 낮아져, 단위 면적에 필요한 전력은 일정 [위키]
  • 하드웨어 오프로딩 (h/w offload): NIC 하드웨어가 Linux 커널의 할 일을 일부 대신 처리해주는 방법
  • NIC (Network Interface Card): 네트워크 처리 장치

Network Interface Card

 

서문

 개요에 서술된 대로, 네트워크의 대역폭 (Throughput)은 몇 년간 4 ~ 10배 증가한 반면 host의 다양한 자원들은 점차 성장이 침체됐다. 이를 해결하고자 Linux 네트워크 스택 최적화 [a], RDMA, 유저레벨 TCP stack, 그리고 특별 하드웨어를 사용하는 방법을 도입했다. 이들은 비효율적인 CPU사용을 줄이지만, 커널의 복잡함과 다양한 모듈이 강하게 엮여있다는 점은 이해를 어렵게하는데 변함이 없다. 

 

 네트워크 트래픽은 통신의 양이 적은 short flow와 많은 데이터를 송/수신하는 long flow로 나뉜다. 데이터센터에서는 short flow가 다수 존재한다는 점에서 이를 분석했던 연구가 많았다. 하지만 해당 분석은 (1) 데이터의 많은 부분은 long flow가 차지하고 이들이 많은 CPU를 소모한다는 점, (2) short flow와 long flow뿐만 아니라 그 중간의 형태도 다양하게 존재한다는 점에서 효과가 약했다. 해당 논문은 데이터센터에서 발생하는 다양한 traffic pattern의 종류에 따라 CPU와 host network stack이 어떠한 영향을 받는지 정밀하게 분석한다.

 

해당 논문이 시사하는 바는 다음과 같다.: 

 

  •  고성능 네트워크는 병목 지점을 protocol processing에서 data copy로 옮겼다.

 현대 Linux 네트워크 스택은 NIC의 모든 기능들 (segmentation, receive offload, jumbo frame, packet steering)을 사용하더라도 코어당 최대 성능은 42Gbps이다. 단일 long flow가 싱글 코어 best 시나리오인데, 해당 시나리오에서 가장 큰 비용은 일정하게도 전체 CPU의 절반을 넘게 사용하는 Kernel buffer에서 application buffer로의 복사였다. (short flow의 경우에는 프로토콜 처리의 비용이 더 주된 원인)

 

  • Bandwidth-delay product (BDP)와 캐시 사이즈의 차이 감소는 최적이 아닌 결과를 가져오게 되었다.

 최근 CPU는 NIC에서 곧바로 L3 cache로 데이터를 보낼 수 있는 Direct Cache Access (DCA)를 지원한다. 이를 활용하면 기존의 NIC → DRAM → L3 cache 와 같은 data path를 거쳐야 했던 부분에서 DRAM을 제거하여 NIC → L3 cache가 가능해진다. 즉, copy가 1회 제거된다. 하지만 생각보다 효과가 적었다. Host가 병목이 되면서 처리 시간 (latency)이 늘어났고, BDP가 증가하여 L3 cache size를 초과하게 되었기 때문이다. 결국에는 L3가 수용할 수 없게되어 cache miss가 급증해 성능 상승폭이 크게 감소했다.

 

  • 자원 공유 (host resource sharing)는 해롭다.

 해당 연구는 자원 공유로 인한 성능 저하때문에 트래픽 패턴 (single flow, one-to-one, incast, outcast, all-to-all)에 따라 코어당 대역폭 효율이 최대 66% 차이가 난다는 것을 발견했다. 예를 들어, 같은 NUMA node에 여러 flow가 존재할 경우, 같은 NUMA node끼리 공유해서 사용하는 L3 cache의 공간이 부족해져 성능 저하를 야기한다. 

 

  • 패킷 처리 파이프라인부터 host까지 재구성 할 필요가 있다.

 해당 연구는 applicatioin이 long flow와 short flow를 같은 CPU 코어에서 담당하는 경우 코어 당 대역폭 효율이 single flow대비 43%가 낮은 현상을 발견했다. 이는 short flow의 큰 프로토콜 처리 비용과 scheduling overhead 때문인 것으로 파악하였다. 특히, short flow와 long flow는 각각 병목지점이 프로토콜 처리와 data copy에 해당하는 반면, Linux 네트워크 스택은 이 둘을 구분하지 않고 동등하게 처리하는 점도 지적하고 있다.

 

Glossary

  • BDP: bandwidth (bit / second) * delay (second) 
  • jumbo frame: 일반적으로 packet의 MTU는 1500 bytes로 지정되어 있다. 이를 넘어서 MTU size를 지정한 것을 jumbo frame이라고 한다. (보통 9000bytes 이내)

 

Reference

[a] MSG_ZEROCOPY, zerocopy tcp_receive, megapipe, i10, stackmap

 

 

End-to-End Data Path

End-to-end data path

  • Sender-side

 Sender application이 write 시스템 콜을 호출하면 kernel은 socket buffer (skbs)를 위한 공간을 할당하고 이 공간에 application data를 복사한다. 해당 skbs는 TCP/IP 계층에 의해 처리되고 window control (congestion control / flow control / rate limiting)이 허락하면 network subsystem에 의해 처리된다. 이 흐름 속에서 buffer는 MTU size로 segmentation 되어야 한다. 이를 software적으로 처리하면 GSO (Generic Segmentation Offload)이고, 이 과정이 하드웨어가 처리한다면 TSO (TCP Segmentation Offload)라고 칭한다. 최종적으로 드라이버는 Tx queue에 인입된 내용들을 처리하고 NIC으로 DMA하여 보내는 구조이다. 현대 Linux는 application 코어와 Tx를 처리하는 코어가 일치하도록 구현되어 있다.

 

  • Receiver-side

 NIC은 여러 개의 Rx-queue를 가지고 있고, Rx-queue마다 DMA를 위한 page-pool이 할당되어 있다. 또한, NIC은 여러개의 수신된 frame을 DMA할 수 있는 메모리 주소인 Rx descriptor를 갖고 있다. Frame을 수신하면 NIC은 여러 Rx descriptor중에 1개를 사용하여 frame을 해당 메모리로 DMA한다. 일반적으로 host memory로 DMA하나, 최신 CPU의 경우 DCA를 사용하여 L3 cache로 DMA하는 것도 가능하다. 

 

 NIC은 비동기적으로 Interrupt ReQuests (IRQ)를 CPU에 보내어 driver에게 새로운 데이터가 도착했음을 알린다. 이 때 어떤 CPU가 IRQ를 처리할까?

그 매커니즘은 위와 같이 4개로 나뉜다. 보통 많이 알려져 있는 것은 Receive Side Steering (혹은 Scaling이라고도 하는 것 같다., RSS)인 듯 하다 (필자의 의견) . RPS는 src ip, dst ip, src port, dst port를 hashing하여 CPU를 선택하는 것이고, RFS는 application이 실행중인 CPU core를 찾아 그 곳에 IRQ를 주는 방법이다. RSS와 aRFS는 RPS와 RFS 매커니점을 하드웨어가 실행하여 어느 CPU core로 보낼지 결정한다. (aRFS 동작원리는 조금 더 조사필요)

 

 CPU는 IRQ를 수신하면 driver가 NAPI polling을 수행한다. NAPI는 기존의 interrupt 기반이 아닌, 일정 개수의 frame을 받거나 일정 시간이 지나기 전까지 busy polling을 수행하는 것을 의미한다 (net.core.netdev_budget, net.core.netdev_budget_usecs로 설정 가능).  해당 과정동안 드라이버는 각 frame에 대해 skb를 할당하고 이 reference를 kernel과 공유하여 kernel이 데이터를 가져갈 수 있도록 한다. 

 

 skb가 많으면 많을수록 overhead가 크다. 따라서 skb의 개수를 줄이기 위한 노력으로 Generic Receive Offload (GRO)와 Large Receive Offload (LRO)가 있다. Tx-side와 비슷하게, software가 수행하면 GRO, hardware로 offloading 되어있으면 LRO라 칭한다. 최종적으로 CPU core가 결정되었으면 IRQ와 TCP/IP를 수행하고 skb의 데이터를 application buffer로 전달한다. 이 과정에서 1 copy가 발생한다.

 

  • Sender-side vs Receiver-side (필자의 의견)

일반적으로 Sender-side보다 Receiver-side가 훨신 복잡하다. Sender-side는 application이 어떤 core에서 돌고 있는지 미리 알 수 있고, device에게 보낼 내용이 있다라고만 알리면 된다 (Doorbell 혹은 MMIO [링크]). 하지만 Receiver-side는 frame이 도착했을 때, packet header를 분석해서 이 데이터가 어느 application을 위한 데이터인지 먼저 파악해야 한다. 그 다음에야 어느 CPU가 application을 처리하고 있는지 알 수 있다. 또한, device는 CPU에게 data를 도착했음을 알려야 한다. CPU는 IRQ만 처리하는 장치가 아니기에 바로 처리되리라고 기약할 수 없다. 

 

Traffic pattern에 따른 실험 결과 및 분석

다음 포스트: 네트워크 스택의 비용에 관한 이해 2

 

네트워크 스택의 비용에 관한 이해 2

해당 게시글은 Sigcomm '21 Understanding Host Network Stack Overheads를 번역하여 정리한 글입니다. 이전 게시글 네트워크 스택의 비용에 관한 이해 1 네트워크 스택의 비용에 관한 이해 1 Understanding Host Network

byeo.tistory.com

 

반응형
Comments