OpenAI가 7,500노드로 Kubernetes를 확장

OpenAI는 머신러닝 연구 팀이 코드를 수정하지 않고 워크로드를 확장할 수 있도록 단일 Kubernetes 클러스터를 7,500노드로 확장했습니다. 이 인프라는 단일 파드가 종종 전체 노드를 차지하여 NVLink와 GPUDirect를 통해 하드웨어 효율성을 극대화하는 대규모 작업을 지원합니다.

워크로드 특성

OpenAI의 Kubernetes 워크로드는 일반적인 엔터프라이즈 애플리케이션과 크게 다릅니다. 주요 초점은 bin-packing이나 fragmentation보다 하드웨어 리소스 접근을 우선시하는 대규모 머신러닝 작업에 있습니다.

  • 리소스 활용: 파드는 일반적으로 전체 노드를 차지하여 GPUs가 NVLink를 통해 직접 통신하고 NIC가 GPUDirect를 통해 통신하도록 허용하며, NUMA 또는 CPU 경합에 기반한 복잡한 스케줄링의 필요성을 줄입니다.
  • 작업 특성: 작업은 종종 MPI(Message Passing Interface)를 실행하여 "반 상태형"이 됩니다. MPI 커뮤니케이터 내의 한 파드가 죽으면 전체 작업이 중단되고 마지막 체크포인트에서 다시 시작됩니다.
  • 네트워킹 패턴: Kubernetes 로드 밸런싱, HTTPS 트래픽, 또는 서비스 디스커버리에 대한 의존도가 최소입니다. 파드는 pod IP 주소를 사용하여 MPI over SSH를 통해 직접 통신합니다.
  • 스토리지: 시스템은 주로 blob 스토리지를 통해 데이터셋 스트리밍과 체크포인팅에 의존하며, POSIX 시맨틱이 필요한 경우에만 PersistentVolumes를 사용합니다.

네트워킹 최적화

7,500노드와 약 200,000개의 동시 IP 주소를 지원하기 위해 OpenAI는 Azure VMSS(Virtual Machine Scale Sets)와 관련된 CNI 플러그인에 대한 네이티브 pod 네트워킹으로 Flannel에서 벗어났습니다.

고처리량 네트워킹

경로 기반 네트워킹 대신 별칭 기반 IP 주소 지정을 사용하면 효과적인 라우트 수의 제한을 피하고 호스트 수준 네트워크 처리량을 제공할 수 있습니다. 이 접근 방식은 캡슐화를 제거하여 설정을 단순화하고 MTU와 관련된 패킷 단편화 문제를 방지합니다.

네트워크 모니터링

OpenAI는 iptables 매글 규칙을 사용하여 패킷을 내부 또는 인터넷 바운드로 태그 지정합니다. 이러한 카운터는 오픈소스 iptables-exporter를 통해 추적되고 Prometheus에 통합되어 연구자들이 네트워크 병목 현상을 시각화할 수 있게 합니다.

클러스터 격리

클러스터는 허브-스포크 모델로 구성됩니다. 연구자들은 허브를 통해 개별 클러스터(스포크)에 접근할 수 있지만, 클러스터 간 통신은 불가능하여 장애 격리를 보장합니다.

API 서버 및 etcd 안정성

규모에서 클러스터 건강을 유지하기 위해 OpenAI는 클러스터 외부의 전용 노드에서 API 서버와 etcd를 실행합니다.

  • 배포: 가장 큰 클러스터는 로드를 분산하기 위해 다섯 개의 API 서버와 다섯 개의 etcd 노드를 사용합니다.
  • 리소스 사용량: API 서버 메모리 사용량은 클러스터 크기와 선형적으로 증가하여 7,500노드에 대해 힙이 최대 70GB에 도달할 수 있습니다.
  • EndpointSlices: Kubernetes 1.17에서 도입된 EndpointSlices의 채택은 Endpoints에 대한 WATCHes로부터의 부하를 1,000배 줄여 노드가 추가되거나 제거될 때 $N^2$ 대역폭 급증을 방지했습니다.
  • 확장 전략: API 서버 과부하를 피하기 위해 OpenAI는 API 상호작용에 DaemonSets를 사용하지 않고 자동 스케일링 이벤트 동안 새 노드 추가를 부드럽게 처리합니다.

Prometheus와 Grafana를 사용한 모니터링

OpenAI는 시계열 메트릭에 Prometheus를, 시각화에 Grafana를 사용하지만 상당한 확장 장애에 직면했습니다.

  • 메모리 누수: /api/v1/series API의 버그로 인해 Grafana가 히스토그램 메트릭을 쿼리할 때 무한 메모리 소비로 Prometheus가 충돌했습니다. OpenAI는 Context를 사용하여 타임아웃을 강제하도록 Prometheus를 패치했습니다.
  • WAL 재생 성능: Prometheus 시작 시간이 Write-Ahead-Log(WAL) 재생으로 인해 몇 시간 지연되었습니다. GOMAXPROCS=24를 설정하면 고코어 서버에서의 CPU 경합을 줄여これを 완화시켰습니다.
  • 메트릭 필터링: 데이터 양을 관리하기 위해 Prometheus 규칙을 사용하여 섭취에서 세분화되거나 사용되지 않는 메트릭을 "삭제"합니다.

노드 건강 및 GPU 검증

수동 및 능동 건강 검사의 조합을 통해 비정상적인 노드를 감지하고 제거하기 위해 자동화가 사용됩니다.

수동 건강 검사

시스템은 dcgm-exporter와 NVML Device Query API를 통해 네트워크 도달 가능성, 디스크 건강, GPU 오류(수정 불가능한 ECC 오류 등)를 모니터링합니다. 실패한 노드는 자동으로 cordon되며, 심각한 오류는 파드 퇴출 및 eventual VM 종료를 트리거합니다.

능동 GPU 테스트

일부 GPU 문제는 오류 코드를 트리거하지 않기 때문에 OpenAI는 "preflight" 시스템을 사용합니다. 새 노드는 테인트와 레이블과 함께 클러스터에 참여하며, DaemonSet이 철저한 GPU 테스트를 실행한 후 테인트를 제거하여 일반 워크로드를 허용합니다.

리소스 관리 및 스케줄링

OpenAI는 경쟁하는 연구 팀을 위한 리소스 할당과 갱 스케줄링을 처리하기 위해 맞춤형 메커니즘을 구현했습니다.

  • 팀 테인트: team-resource-manager 서비스는 테인트(openai.com/team=teamname:NoSchedule)와 입학 웹훅을 사용하여 연구 팀에 특정 노드 용량을 할당하면서 저우선순위 파드가 사용되지 않은 용량을 빌릴 수 있도록 합니다.
  • 리소스 풍선: 클러스터-오토스케일러가 유휴 노드를 제거하지 못하도록(이로 인해 스핀업 지연과 API 서버 부담이 증가함) OpenAI는 "풍선" Deployments를 사용합니다. 이 저우선순위 파드는 공간을 차지하지만 실제 작업이 도착하면 즉시 퇴출됩니다.
  • 갱 스케줄링: 여러 실험이 각각 클러스터 용량의 절반을 차지하여 교착 상태가 발생하는 것을 방지하기 위해 OpenAI는 Kubernetes 1.18에서 도입된 Coscheduling 플러그인을 사용하여 StatefulSet의 모든 파드가 훈련 시작 전에 스케줄링되도록 보장합니다.

남아 있는 과제

OpenAI는 두 가지 주요 미해결 문제를 식별했습니다:

  1. 메트릭 스토리지: Prometheus TSDB 엔진은 컴팩트가 느리고 "너무 많은 샘플" 오류에 취약합니다. OpenAI는 다른 Prometheus 호환 스토리지 및 쿼리 엔진으로 마이그레이션 중입니다.
  2. 트래픽 셰이핑: 연구자들이 사용하는 aggregate 인터넷 대역폭이 외부 데이터 세트와 소프트웨어 패키지 저장소에 부담을 줄 수 있어, pod 네트워크 트래픽 셰이핑이 필요합니다.

Sources