Cilium 최적화하기: irqbalance 중지 후 cpu pinning하기

irqbalance와 CPU Pinning의 원리

시스템에서 발생하는 하드웨어 인터럽트(IRQ)는 프로세서가 작업을 수행하는 동안 네트워크 패킷 처리, 디스크 I/O 등 다양한 작업을 중단시키는 역할을 한다. irqbalance는 이러한 인터럽트를 여러 CPU 코어에 분산시켜 특정 코어에 과부하가 걸리지 않도록 도와준다. 하지만 모든 환경에서 항상 효과적이지는 않다. 특히 Cilium과 같이 높은 네트워크 성능이 필요한 경우, 인터럽트가 무작위로 여러 코어에 분산되면 캐시 미스가 발생하고 인터럽트 처리 지연이 늘어나면서 성능이 저하될 수 있다.
 
이러한 문제를 해결하기 위해 CPU Pinning을 적용하면 특정 NIC 인터럽트를 특정 CPU 코어에 고정할 수 있다. 이를 통해 CPU 코어와 메모리 간의 캐시 로컬리티를 개선해 네트워크 패킷 처리 속도를 높일 수 있다.
 

 

Cilium에서 NIC 인터럽트 핀닝이 필요한 이유

Cilium은 eBPF를 활용하여 네트워크 패킷을 효율적으로 처리하는 네트워킹 솔루션이다. 그러나 최상의 성능을 발휘하려면 인터럽트가 적절하게 처리되어야 한다. 여러 CPU 코어에 인터럽트가 분산되면 인터럽트 처리에 대한 오버헤드가 증가하고 패킷 처리 지연이 발생할 수 있다. 이러한 상황에서는 특정 NIC 인터럽트를 CPU 코어에 고정시켜 CPU와 NIC 간의 데이터 교환을 최적화하는 것이 효과적이다. 이를 통해 Cilium의 네트워크 처리 성능을 향상시킬 수 있다.
 

irqbalance 중지 및 NIC 인터럽트 핀닝 설정

irqbalance를 중지하고 NIC 인터럽트를 특정 CPU 코어에 pinning하는 단계는 다음과 같다.
 

⏸️ irqbalance 중지하기

먼저 irqbalance 서비스를 중지한다. 이를 통해 인터럽트가 자동으로 분산되는 것을 막을 수 있다.

systemctl stop irqbalance

 

🔍 인터페이스 확인 및 IRQ 목록 확인하기

인터페이스 이름 확인

pinning하려는 네트워크 인터페이스 이름을 확인한다.

ip link show

 

인터럽트 목록 확인

/proc/interrupts 파일에서 해당 인터페이스에 대한 IRQ를 확인한다.

cat /proc/interrupts | grep eth0

 
예를 들어 eth0과 연관이 있는 인터럽트는 eth0-rx-0, eth0-rx-1, eth0-tx-0, eth0-tx-1로 총 4개다.

           CPU0       CPU1       CPU2       CPU3
 40:    102394        0          0          0      IR-PCI-MSI 262144-edge      eth0-rx-0
 41:         0     94832          0          0      IR-PCI-MSI 262145-edge      eth0-rx-1
 42:         0         0      80328          0      IR-PCI-MSI 262146-edge      eth0-tx-0
 43:         0         0          0      73284      IR-PCI-MSI 262147-edge      eth0-tx-1

 

📌 IRQ를 특정 CPU 코어에 Pinning하기

CPU 마스크 설정하기

위에서 확인한 IRQ 번호를 토대로 각 IRQ에 대한 CPU 마스크를 설정하여 pinning할 CPU 코어를 결정한다.

# 0x3는 이진수 11로 표현되며, 이는 CPU 0과 CPU 1에 인터럽트를 핀ning한다는 의미이다. 
# <IRQ 번호>는 이전 단계에서 확인한 NIC의 인터럽트 ID를 대체한다.
echo 0x3 > /proc/irq/<IRQ 번호>/smp_affinity

 

💡 CPU 마스크 설정 예시

예를 들어 eth-rx-0의 IRQ는 40이고 이를 0번 CPU에 pinning하려면 다음과 같이 한다.

echo 0x1 > /proc/irq/40/smp_affinity

 만약 여러 CPU에 pinning하려면, 각 CPU 번호에 해당하는 이진수의 자리값을 더한 값을 사용해야 합니다.

이진수의 각 자리는 특정 CPU 번호에 대응합니다. 예를 들어:

• 첫 번째 자리는 0번 CPU,
• 두 번째 자리는 1번 CPU,
• 세 번째 자리는 2번 CPU,
• …
• 일곱 번째 자리는 6번 CPU를 의미합니다.

즉, CPU 번호에 해당하는 자리의 값을 더하면 됩니다.
 
만약 여러 CPU에 pinning하려면 pinning하고자 하는 CPU 번호를 모두 더한 값을 사용하면 된다.
 
예를 들어 40번 IRQ에 1번, 4번, 6번 CPU를 pinning하려면 다음과 같이 계산한다.
 
CPU 1: 00000010 (2진수, 뒤에서 두번째)
CPU 4: 00010000 (2진수, 뒤에서 5번째)
CPU 6: 01000000 (2진수, 뒤에서 7번째)
 
다음의 값을 다 더하면  01010010(2진수) 이고 이를 16진수로 변환하면 0x52가 된다 

echo 0x52 > /proc/irq/15/smp_affinity

 

✅ 설정이 잘되었는지 확인해보기

설정이 잘 적용되었는지 확인하려면 다음과 같이 확인한다.

cat /proc/irq/123/smp_affinity

 

이 설정은 서버가 재시작되면 초기화되므로 영구적으로 설정되도록 추가 작업이 필요하다.

 
 

🚨 주의 사항 

numa 노드가 2개 이상일 때에는 어떤 cpu core에 pinning을 하느냐에 따라 성능이 더 떨어질 수 있습니다.