[발표영상정리] Better Bandwidth Management with eBPF

https://youtu.be/QTSS6ktK8hY?feature=shared

 

기존 쿠버네티스 대역폭 제한의 문제점

쿠버네티스에는 파드 네트워크 대역폭 제한을 위한 기능이 있습니다.
ingress / egress 어노테이션에 50Mbit/sec 같은 값을 넣으면 제한이 걸립니다.
하지만 이 기능은 bandwidth meta plugin에서만 지원하며, 내부적으로 토큰 버킷 필터(Token Bucket Filter, TBF) 를 사용합니다.

문제는 이 방식이 프로덕션 환경에서 확장성이 떨어진다는 점입니다.

 

 

Pod 유입 속도를 제한하려면 호스트 veth의 유출 경로에 규칙을 설정해야 합니다.

예를 들어, ingress 트래픽 제어 설정인 kubernetes.io/ingress-bandwidth="50M"의 경우 veth의 TBF qdisc에 설정됩니다.

 

이 TBF qdisc는 셰이핑 상태를 추적해야 해서, 모든 CPU에 걸쳐 단일 락을 잡습니다. 여러 CPU가 동시에 트래픽을 받으면 심각한 경합이 생겨 물리 NIC의 멀티 큐 능력이 무력화됩니다.

그리고 이 TBF는 단일 큐로 되어있습니다. 아래 그림에서 처럼 여러 클라이언트들로부터 들어오는 패킷이 하나의 TBF 큐로 가는것을 볼 수 있습니다.  이렇다보 인그레스에서 여러 CPU가 동시에 트래픽을 받을 경우, 모든 패킷이 하나의 TBF 락(lock)에 걸려 병목이 발생합니다. 이는 물리 NIC의 멀티큐 성능을 망가뜨립니다. 또, 수신측에서 큐잉이 발생하면, 이미 네트워크 대역을 소비한 후 노드에서 패킷을 버리는 ‘버퍼블로트(bufferbloat)’ 문제가 생깁니다.

 

 

 

파드의 Egress 트래픽이 호스트 네임스페이스 입장에서는 Ingress 트래픽에 해당하고, 커널 구조상 ingress 경로에서는 shaping이 불가능해 IFB 장치를 추가로 만들어야 하고, 결국 이중 큐잉과 락 병목이 다시 발생합니다.

그리고, TSQ라는 TCP 스택이 큐에 과도하게 많은 패킷을 쌓지 않도록 하여 레이턴시를 줄이는 기능이 있는데 IFB를 사용하게 되면 패킷이 물리 NIC로 나가기 전에 IFB Qdisc의 큐에 있는데도 TCP 스택은 해당 패킷이 이미 전송된 것으로 잘못인식하여 버퍼블로트를 악화시키게 됩니다. 

 

 

정리해보면

  • CPU 멀티큐 활용 불가: 여러 CPU가 동시에 트래픽을 처리해도, 하나의 TBF 락(lock)에 걸려 병목 발생
  • 버퍼블로트(Bufferbloat): 수신 측에서 큐잉이 발생해 지연 증가
  • 이중 큐잉: Egress shaping을 위해 IFB 장치를 추가하면서 큐가 두 번 쌓임
  • TCP Small Queue와 충돌: 불필요한 대기와 지연 발생

결국 지연이 커지고, 고성능 NIC의 멀티큐 성능을 살리지 못합니다.

 

 

구글의 Earliest Departure Time(EDT) 모델

 

구글 연구팀이 제안한 EDT 모델은 큐잉 자체를 없애고, 패킷마다 “최소 전송 가능 시각” 타임스탬프를 부여해 스케줄링하는 방식입니다.
이를 Timing Wheel Scheduler가 관리합니다.

 

핵심 아이디어

  1. EDT: 패킷에 Earliest Departure Time 타임스탬프 부여
  2. Timing Wheel Scheduler: 지정된 시각이 되면 네트워크로 전송
    → 큐에서 기다리는 시간을 줄여 지연(latency)을 크게 감소

 

Cilium Bandwidth Manager: eBPF + EDT

 

Cilium 팀은 eBPF를 활용해 EDT 모델을 쿠버네티스에 적용했습니다.

 

구현 방법

  • 속도 제한 적용 지점은 veth가 아닌 물리 NIC로 변경: 이렇게 함으로써 패킷이 큐를 두 번 거치는 문제를 없앴고, 물리 장치에서 바로 처리해 추가적인 버퍼블로트도 방지하게 됨
  • bpf host routing을 사용: 상위 네트워크 스택을 거치지 않고, 모든 라우팅을 tc eBPF 계층에서 처리한 뒤 곧바로 물리 장치로 전달-→ 네트워크 스택의 기능(예: FIB lookup)도 eBPF 내부에서 그대로 재사용할 수 있어 TCP Small Queue(TSQ) 의 피드백이 정상적으로 유지됨

 

 

그림에서 처럼 파드 스펙에 예를 들어 50 Mbit/s를 설정하면, 물리 디바이스에 붙은 eBPF 프로그램이 패킷에 전송 타임스탬프(EDT)를 설정합니다. 그리고 Cilium이 디바이스에 멀티큐 qdisc를 구성하는데, 그 리프 큐디스크로 FQ(Fair Queue) 를 사용합니다. 이 FQ가 앞서 말한 타이밍 휠 스케줄러를 구현합니다.

 

(요건.. 요즘 NIC이 전부 멀티 큐를 지원하니까 MQ를 사용해서 멀티코어 확장성과 락 없는 병렬 처리 기반을 만들고, FQ로 EDT 타임스탬프를 활용한 타이밍 휠 스케줄링을 안정적으로 구현하기 위해서이지 않을까..?)

 


정리하면

  • 락 없는( lockless ) 속도 제한 구현
  • 제한 지점을 물리 NIC 레벨로 이동 → 이중 큐잉 방지
  • TCP Small Queue 피드백이 정상 작동
  • NIC 멀티큐 성능 100% 활용 가능

 

성능 테스트 결과 (256개 동시 연결)

  • 중앙값 지연: 기존 대비 7배 감소
  • p99 지연: 4배 감소
  • 처리량: 7배 증가

 

BBR 지원

2024.10.27 - [CS/network] - BBR(Bottleneck Bandwidth and RTT) 혼잡 제어 알고리즘

BBR(Bottleneck Bandwidth and RTT)은 구글이 개발한 TCP 혼잡 제어 알고리즘으로, 손실 기반이 아닌 전송 속도와 RTT를 기반으로 동작합니다.

 

장점:

  • 저속·마지막 구간(last mile) 네트워크에서 지연과 버퍼블로트 감소
  • 장거리 고속 네트워크에서 처리량 향상

 

Cilium에서 BBR을 쓰려 했지만, 기존 리눅스 커널은 veth로 네트워크 네임스페이스를 넘을 때 패킷 타임스탬프를 0으로 초기화해 BBR이 제대로 동작하지 않는 문제가 있었습니다. BBR은 언제 패킷을 보낼지(페이싱)를 정하는 타임스탬프가 매우 중요한데, 네임스페이스를 지나는 과정에서 커널이 그 값을 지워버렸기 때문입니다.

 

커널의 SKB(socket buffer) 에는 타임스탬프를 담는 단일 64비트 필드가 있고, 이를 수신(RX)  송신(TX) 에서 서로 다른 기준 시계로 사용합니다(RX는 CLOCK_TAI, TX는 CLOCK_MONOTONIC). 이처럼 기준 시계가 달라 veth를 통해 RX→TX로 전환될 때 RX(TAI) 값을 TX(MONOTONIC) 용도로 안전하게 쓸 수 없으므로, 커널은 혼선을 피하려고 해당 값을 0으로 클리어해 왔습니다. (과거에 RX/TX 시계를 통일하려는 시도도 있었지만, 하드웨어 타임스탬프 편차/스큐 때문에 너무 큰 미래값이 들어와 FQ 스케줄러의 페이싱이 깨지거나 드롭이 발생해 되돌려졌습니다.)

 

쉽게 문제를 설명해보면 veth로 A 네임스페이스에서 받았던(RX/TAI) 시간값을 B 네임스페이스로 내보낼 때(TX/MONOTONIC) 그대로 쓰면 오해석 위험이 커서, 커널이 RX→TX 전환 시 0으로 지웠다는 얘기입니다

 


그래서 Cilium 팀은 Facebook과 함께 이 문제를 해결해, 네임스페이스를 거쳐도 송신 타임스탬프가 유지되도록 커널을 수정했습니다. 이제 이 SKB에 타임스탬프 값이 지워지지 않다보니 Cilium Bandwidth Manager 과 결합되어 쿠버네티스에서도 BBR 알고리즘이 잘 동작하게 됩니다. 

 

 

데모: Cubic vs BBR 비교

테스트 환경:

  • 작은 쿠버네티스 클러스터
  • 동일 조건: 100ms 지연, 1% 패킷 손실

결과:

  • Cubic: SD 품질에 머물고 HD 로딩 불가, 버퍼링 잦음
  • BBR: HD 품질 유지, 손실 후에도 빠르게 회복

 

주의할 점

  • BBR은 Cubic보다 공격적이라 혼합 환경에서 불공정성(fairness) 문제가 있을 수 있음
  • Google은 이를 개선한 BBR v2를 개발 중
  • 이미 대규모 환경에서 BBR은 널리 사용되고 있음

 

다 듣고나니.. 커널 버전을 최신으로 계속 업그레이드 하는 것도 중요해보이네요