고스트 점유 탐지기: Kueue 클러스터에서 유휴 GPU를 안전하게 회수하는 다중신호 프로토콜
Kueue로 GPU 큐를 관리하는 클러스터를 운영하면서 “분명 여유가 있는데 왜 8/8로 꽉 찼다고 나오지”라는 화면을 본 적이 있다면 이 논문을 읽을 이유가 있습니다. ThakiCloud AI Research가 오늘 낸 이 연구는 큐 매니저가 절대 보지 못하는 GPU 점유, 그러니까 끝났거나 죽었는데 자리만 지키고 있는 Deployment를 어떻게 안전하게 찾아 회수할지를 다룹니다. 결론은 단순하지 않습니다. 유틸리제이션 하나만 여러 번 재는 방식은 아무리 샘플을 늘려도 활성 잡을 죽일 위험을 완전히 없애지 못하고, 프로세스 개수라는 전혀 다른 축을 하나 더 붙여야 그 위험이 정확히 0이 됩니다.
큐는 정확한데 GPU는 이미 없다
Kueue는 자기가 admission으로 받아들인 Job만 추적합니다. 그 안에서는 회계가 정확합니다. 문제는 Deployment나 StatefulSet입니다. 노트북 세션이든 서빙 엔드포인트든 실험용 파드든, 이런 오브젝트는 Kueue의 admission 경로를 아예 거치지 않습니다. 파드가 한 번 스케줄되면 그 안 프로세스가 일을 하든 안 하든 GPU를 계속 쥐고 있습니다.
여기서 두 가지 실패가 반복됩니다. 하나는 연구자가 Deployment를 띄우고 실험이 끝났는데 아무도 그걸 지우지 않는 경우입니다. Kueue의 장부에 애초에 없던 물건이니 이상해 보일 것도 없습니다. 다른 하나는 컨테이너 안 프로세스가 죽는 경우입니다. 대개 GPU 드라이버가 fault를 내면서 컨테이너는 Kubernetes 눈에는 여전히 “Running”인데 실제로는 아무 일도 하지 않는 상태가 됩니다. 두 경우 모두 큐가 보는 자원 현황은 틀렸습니다. 논문은 이 괴리를 quota-accounting gap이라 부르고, 처음으로 이를 정식화했습니다. 소수의 고가 GPU를 여러 팀이 나눠 쓰는 클러스터에서는 이런 유령 점유 몇 개만으로도 바로 스케줄되는 잡과 존재하지 않는 자원 뒤에서 하염없이 대기하는 잡이 갈립니다.
세 갈래로 나눠야 풀리는 문제
당장 떠오르는 해법은 유휴로 보이는 Deployment를 주기적으로 스캔해 지우는 자동화입니다. 말은 쉬운데 함부로 짜면 위험합니다. GPU 유틸리제이션은 깨끗한 이진 신호가 아닙니다. 정상적으로 도는 잡도 데이터로더가 멈추거나 배치 경계를 지나거나 체크포인트를 쓰는 동안 잠깐씩 0에 가까운 값을 찍습니다. 논문은 이를 batch gap이라 이름 붙이고, 이 잠깐의 0 구간과 진짜 유휴를 못 가르는 detector가 결국 언젠가는 살아있는 잡을 지운다고 지적합니다.
그래서 논문은 점유를 세 갈래로 나눕니다. ACTIVE는 진짜 살아서 진행 중인 잡이고, batch gap 동안에도 프로세스는 살아있습니다. FINISHED_IDLE은 작업이 끝났는데 스케일다운되지 않은 Deployment로, 유틸리제이션은 완전히 0에 고정되고 남은 프로세스도 없습니다. ZOMBIE_CRASHED는 드라이버 fault로 프로세스가 죽었는데 파드만 남은 경우입니다. 여기서 까다로운 지점이 하나 있습니다. 좀비 컨테이너 넷 중 하나꼴로 죽은 드라이버가 못 거둔 defunct 자식 프로세스를 하나 남깁니다. 프로세스 개수만 보는 판정 기준은 이 소수의 좀비를 활성 잡과 구분하지 못하는데, 이것이 뒤에서 나오는 재현율 손실의 정체입니다.
5개 시드 x 2,000개 인스턴스 평균입니다. 유틸리제이션만 보는 두 detector는 재현율은 완벽하지만 오탐률이 남습니다. 관측 윈도를 늘리면 오탐률이 10.93%에서 3.50%로 줄지만 0에는 닿지 않습니다. 0에 닿는 조합은 프로세스 개수와 산출물 증가 여부를 함께 보는 것뿐이며, 그 대가로 재현율 6.10%p를 내줍니다. 이 실험은 CPU 전용 컨테이너에서 측정한 결과입니다.
왜 다섯 번 재도 0이 안 되나
논문에서 가장 흥미로운 대목은 산술입니다. 5개 샘플 창을 쓰고 다섯 번 모두 0이어야 회수 대상으로 판정하는 detector는 오탐률을 10.93%에서 3.50%로 줄입니다. 여기서 멈추면 창을 더 늘리고 싶어집니다. 그런데 batch gap은 개별 읽음값이 아니라 그 인스턴스 전체의 상태입니다. 한 잡이 배치 경계에 걸릴 확률이 15%이고, 그 안에서 각 읽음값이 0이 아닐 확률이 1/4이라면, 다섯 번 모두 0으로 읽힐 확률은 0.15 곱하기 (3/4)^5, 즉 3.56%입니다. 6,000개 ACTIVE 평가 중 214개에 해당하는 숫자이고, 논문이 실제로 관측한 210개와 거의 일치합니다. 창을 한 번 늘릴 때마다 남는 오탐은 고정된 비율(3/4)만큼만 줄어드는 기하급수적 감쇠라서, 0에는 다가가지만 절대 닿지 않습니다. 반면 대기 시간은 창 길이에 비례해서 그냥 늘어납니다.
5개 시드 풀링 카운트입니다. 유틸리제이션 단독 detector에 남은 오탐 210건은 전부 batch gap 때문입니다. 한 잡이 창 전체를 gap 안에서 보내면 다섯 번 다 0으로 읽힙니다. 프로세스 개수를 함께 보는 조합은 이 오탐을 통계적으로 줄이는 게 아니라 구조적으로 없앱니다. batch gap이 프로세스 생존 여부는 건드리지 않기 때문입니다. 이 실험도 CPU 전용 컨테이너에서 측정했습니다.
비대칭 비용과 다중신호 판정
이 논문이 세우는 원칙은 하나입니다. 살아있는 잡을 잘못 지우는 것(false reclaim)과 죽은 자원을 한 사이클 늦게 회수하는 것(false keep)은 비용이 다릅니다. 후자는 다음 폴링 때 다시 검토하면 그만이지만, 전자는 되돌릴 수 없습니다. 그래서 논문은 정확도나 F1이 아니라 오탐률(FPR)을 안전 지표로 세우고, 그 지표를 0에 최대한 가깝게 만든 detector 중에서만 재현율을 비교합니다.
이 원칙을 코드로 옮긴 것이 다중신호 프로토콜입니다. 다섯 번의 유틸리제이션 읽음값이 전부 0이고, 컨테이너 안에 살아있는 프로세스가 하나도 없고, 산출물 크기가 창이 열린 동안 늘지 않았을 때만 회수 대상으로 판정합니다. 벤치마크 10,000개 인스턴스(5개 시드 x 2,000개, ACTIVE 60% / FINISHED_IDLE 30% / ZOMBIE_CRASHED 10%)에서 이 조합은 6,000개 ACTIVE 평가 전부에서 오탐 0을 기록했습니다. 활성 잡은 batch gap 중에도 항상 프로세스 1개에서 4개를 유지하기 때문에, 유틸리제이션이 어떻게 나오든 프로세스 개수 조건을 절대 만족시키지 못합니다. 대가는 재현율 93.90%입니다. 4,000개 회수 대상 중 244개를 놓치는데, 대부분 우연히 defunct 자식이 살아있던 좀비입니다.
정확도만 보면 틀린 선택을 한다
표를 그대로 읽으면 다중신호 프로토콜이 최선의 detector처럼 보이지 않습니다. 정확도는 97.56%로, 다중샘플 유틸리제이션 단독(97.90%)보다 낮습니다. 하지만 정확도는 비대칭 비용을 평균 내버리는 지표라서, 스물아홉 번에 한 번꼴로 살아있는 잡을 죽이는 detector에 더 높은 점수를 줍니다. 논문이 강조하는 지점이 바로 이것입니다. 정확도는 이 문제의 배포 기준이 될 수 없고, 되돌릴 수 없는 비용을 따로 떼어 보는 정밀도(precision)라야 두 detector를 제대로 가릅니다.
다중신호 프로토콜은 가장 정확한 detector가 아닙니다. 다중샘플 유틸리제이션이 정확도에서는 앞섭니다(0.9790 대 0.9756). 정확도는 비대칭 비용 구조를 평균 내기 때문에, 실제로는 스물아홉 번에 한 번꼴로 살아있는 잡을 죽이는 쪽에 유리하게 작동합니다. 되돌릴 수 없는 비용만 따로 보는 정밀도가 두 detector를 가르는 진짜 지표입니다. 이 실험 역시 CPU 전용 컨테이너에서 측정했습니다.
에이전트는 신호를 모으고, 결정은 코드가 한다
이 논문에서 가장 실무적인 설계 결정은 LLM 에이전트의 역할을 명확히 자르는 부분입니다. 유틸리제이션 메트릭을 조회하고, 컨테이너 안에 exec으로 들어가 프로세스 목록을 세고, 오브젝트 스토리지 리스팅을 비교하는 일은 도구마다 인터페이스가 다르고 출력도 지저분합니다. 이런 이질적인 도구 호출을 정리해 세 가지 정규화된 feature로 만드는 일은 에이전트가 잘하는 영역입니다. 반면 그 feature를 보고 “이 Deployment가 유휴로 보인다”고 자연어로 판단하는 일은 에이전트에게 맡기지 않습니다. 회수 여부는 고정된 논리곱 하나가 정합니다. 같은 신호를 두 번 넣어도 같은 결론이 나오고, 오탐률을 정확히 측정할 수 있고, 실패 양상을 미리 다 나열할 수 있다는 이유에서입니다. 실행 전 판단을 이렇게 결정론적 코드에 묶어두는 접근은 되돌릴 수 없는 행동을 하는 에이전트를 다루는 최근 안전성 연구 흐름과도 맞닿아 있습니다.
프로세스 목록을 확인하려면 컨테이너에 exec 권한으로 들어가야 한다는 점도 짚어둘 만합니다. 이는 접근 권한이 큰 만큼 위험도도 큰 영역이라, 읽기 전용 프로세스 나열로 좁히고 네임스페이스 단위로 자격증명을 스코프해야 한다는 것이 논문의 입장입니다.
한계와 다음 실험
논문은 스스로 네 가지 한계를 명시합니다. 첫째, 이는 실제 클러스터에서 돌린 필드 트라이얼이 아니라 통제된 합성 벤치마크입니다. 둘째, 다중신호 프로토콜이 내주는 6% 정도의 재현율 손실은 실제 운영 비용이고, 감당할 만한지는 폴링 주기와 클러스터 자원 부족 정도에 달려 있습니다. 셋째, 산출물 업로드 완료 여부라는 네 번째 신호를 논문이 제안은 하지만 평가에는 전혀 쓰지 않았습니다. 넷째, ACTIVE 60% / FINISHED_IDLE 30% / ZOMBIE_CRASHED 10%라는 클래스 비율은 실측이 아니라 모델링 선택입니다.
다음 단계로 논문은 실제 클러스터에 이 판정 규칙을 읽기 전용 shadow 모드로 붙여 무엇을 회수했을지 로그만 남기고 검증하는 실험을 제안합니다. 놓친 6.10%가 다음 사이클에 저절로 사라지는 지연인지, defunct 자식 프로세스가 계속 살아남아 매번 같은 좀비를 놓치는 구조적 손실인지도 이 shadow 트라이얼이 있어야 답할 수 있습니다.
논문 상세와 원문은 여기서 확인할 수 있습니다: https://huggingface.co/datasets/thaki-AI/daily-paper-2026-08-19-ghost-occupancy-gpu-reclaim