[IT 심층 분석]
멀티 테넌트 GPU 추론 환경에서 발생하는 간헐적 CUDA 메모리 세그멘테이션 폴트 격리
김민준 · IT 시스템 엔지니어|
저희 팀이 심혈을 기울여 구축한 사내 공용 AI 추론 파이프라인에서 밤마다 슬랙 알람이 비명을 질렀습니다. 여러 개의 서로 다른 머신러닝 프로세스가 하나의 거대한 NVIDIA A100 GPU를 잘 분할해서 쓰고 있었는데, 잊을 만하면 랜덤한 프로세스가 CUDA 런타임 오류(Segmentation fault)를 뿜어내며 모델 로딩에 처참하게 실패하는 현상 때문이었습니다. 낮에는 너무나 평온했기에, 재현조차 마음대로 되지 않는 이 희대의 '귀신 들린 버그'를 잡기 위해 꼬박 2주를 nvidia-smi 워치독과 cuda-gdb 툴에 파묻혀 살아야 했습니다. 몸은 피곤했지만, 도무지 이유를 알 수 없는 오기에 밤잠을 설치며 디버그 로그의 매트릭스 세계를 헤엄쳤습니다.
원인은 자원 공유 환경에서의 고질병, 바로 독립성의 파괴였습니다. 각 프로세스가 IPC(Inter-Process Communication) 공유 메모리 영역을 통해 GPU에 포팅할 텐서 데이터를 주고받았는데, 다수의 딥러닝 프레임워크 데몬이 컨텍스트 스위칭을 하며 미세한 찰나의 타이밍에 같은 주소의 CUDA 메모리 할당 번지를 참조해버린 탓이었습니다. 즉 A 모델이 자신의 쓰레기를 버리러 간 빈칸에, B 모델이 엉뚱한 데이터를 올리려고 다투다 발생한 포인터 엇갈림. 운영체제 메인 램에서나 일어날 법한 메모리 레이스 컨디션(Race Condition)이 통제하기 어려운 GPU 디바이스의 독립된 VRAM 세계 안에서 벌어지고 있었던 충격적인 진실과 마주했습니다.
이 상황을 근본적으로 타도하기 위해서는 어설픈 시그널이나 락(Lock)을 거는 것으론 부족했습니다. 그래서 NVIDIA의 MPS(Multi-Process Service) 데몬을 아키텍처에 긴급히 이식했습니다. 클라이언트 프로세스들이 직접 GPU 하드웨어에 접근하지 못하게 전면 차단막을 치고, 오직 MPS 서버 스레드를 통해서만 CUDA 컨텍스트가 하달되도록 아예 통신 규격을 강제화했습니다. 나아가 cgroups를 결합해 각 컨테이너 별 VRAM 점유 한도에 하드 리밋(Hard Limit)을 물리게 만들자 폴트는 즉각 소거되었습니다. 이 프로젝트를 해결하고 나니, 복잡한 병렬 환경에서는 어설픈 신뢰가 아닌 하드웨어 레벨에 가까운 무자비한 분리벽(Isolation)만이 시스템 안정성의 핵심이라는 강박에 가까운 신념을 얻게 되었습니다.