비싼 GPU가 노는 시간을 줄이는 법
수천만 달러짜리 GPU 클러스터가 절반만 일하는 이유를 따라가며 gang scheduling과 topology 배치와 bin packing과 탄력적 스케줄링이 실제 처리량을 어떻게 바꾸는지 풀어낸 실용 해설
원문 논문 보기
안녕하세요, 패트릭입니다.
이번 글에서 다루는 글은 Impactful scheduling for GPU clusters이며, Allen Institute for AI 연구팀이 Hugging Face 블로그에 공개한 기술 글입니다. 원문 링크는 제목 아래에 붙어 있습니다.
이 글의 주장은 수천만 달러짜리 GPU 클러스터가 topology와 packing을 모르는 스케줄러 때문에 30%에서 50% 수준으로만 돌 때가 많으며, 배치와 스케줄링을 바꾸는 것만으로 같은 기계에서 훨씬 많은 일을 해낼 수 있다는 것입니다.
연구실 복도에서 자주 듣는 말이 있습니다. GPU가 모자라서 실험이 밀렸다는 말인데요. 그런데 막상 클러스터 대시보드를 열어보면 이상하게 빈칸이 보입니다. 어떤 노드는 GPU 메모리가 남아서 한가하고, 어떤 노드는 CPU가 모자라서 GPU를 묶어둔 채 기다립니다. 제 입장에서는 이 장면이 가장 아깝게 느껴졌습니다. 기계가 없어서 느린 게 아니라, 기계를 엇박자로 써서 느린 것처럼 보였기 때문입니다. 그렇다면 비어 있는 GPU와 밀린 줄서기는 어떻게 같이 존재할 수 있을까요. 오늘은 그 어긋남을 스케줄링의 언어로 풀어보겠습니다.

비어 있는 GPU 옆에서 줄 서는 일들
클러스터 운영자와 이야기를 나누다 보면 비슷한 하소연이 반복됩니다. GPU를 수백 장에서 수천 장까지 사 모았는데 체감 성능은 기대에 못 미친다는 것입니다. 기계값만 수천만 달러인데, 실제 사용률은 30%에서 50% 사이를 오간다고 합니다. 처음에는 이 숫자가 과장처럼 느껴졌는데요. 그런데 구조를 뜯어보면 과장이 아니라 관측에 가깝다는 생각이 들었습니다. GPU는 혼자 돌지 않기 때문입니다. CPU와 메모리와 네트워크와 저장장치가 함께 맞아야 일이 돌아가는데, 그중 하나라도 어긋나면 GPU는 멀쩡해도 놀게 됩니다.
생각해보면 사람도 비슷하게 일합니다. 회의실은 비어 있는데, 정작 필요한 사람이 다른 회의에 묶여 있으면 회의가 열리지 않죠. GPU 클러스터도 같은 모양입니다. GPU 자리는 남았는데 CPU 코어가 모자라고, 메모리는 남았는데 네트워크 대역이 겹치고, 이런 어긋남이 쌓이면 놀고 있는 GPU가 생깁니다. 이를_stranding_이라고 부르는데, 말 그대로 자원이 고립되어 묶인 상태입니다. 기계가 고장 난 게 아니라 배치가 꼬인 것인데, 밖에서 보면 기계가 부족한 것처럼 보입니다.
여기서 재미있는 질문이 생깁니다. GPU를 더 사면 문제가 풀릴까요. 저는 이 숫자보다 그 뒤의 구조가 더 중요하다고 봅니다. 빈칸이 배치 때문에 생긴 것이라면, 기계를 늘려도 빈칸의 모양만 커질 수 있기 때문입니다. 실제로 많은 팀이 GPU를 추가했는데 대기 시간이 그대로인 경험을 합니다. 기계가 아니라 자리 배치표가 병목인 셈이죠. 그래서 이 글은 모델 구조 이야기가 아니라 자리 배치표 이야기로 읽어야 합니다. 같은 돈을 쓰고도 일을 더 해내는 방법은 기계 바깥이 아니라 기계 사이의 순서에 있습니다.
왜 분산 학습은 따로 출발할 수 없을까
분산 학습을 처음 접하면 드는 의문이 있습니다. 여덟 장으로 학습하는데, 다섯 장만 먼저 시작하고 세 장은 나중에 합류하면 안 될까요. 답은 할 수 없다는 것이고, 이유는 학습의 동작 방식 때문입니다. 분산 학습의 worker들은 매 스텝마다 gradient를 모아 평균을 내는데, 이 all-reduce 과정에서 모두가 같은 리듬으로 움직여야 합니다. 일부만 스케줄되면 나머지를 기다리다가 멈추고, 기다림이 길어지면 서로를 붙잡고 놓지 않는 deadlock에 빠집니다.
그래서 등장하는 개념이 gang scheduling입니다. 갱이라는 말이 어감이 조금 거칠지만 뜻은 단순합니다. 같이 일할 식구면 같이 입장시키고, 같이 못 들어가면 아예 들여보내지 않는다는 것입니다. 여덟 장이 필요하면 여덟 장이 동시에 비어야 실행합니다. 다섯 장만 비었다고 다섯 장부터 미리 돌리면, 그 다섯 장이 통신 상대를 기다리느라 GPU 시간을 허비하기 때문입니다. 식당에서 여덟 명이 앉을 테이블이 날 때까지 기다리는 것과 같습니다. 다섯 명부터 앉히면 나머지 세 명이 올 때까지 주문도 못하고 시간만 갑니다.
그렇다면 왜 이런 당연한 원칙이 매번 깨질까요. 이유는 클러스터에 섞여 있는 다양한 작업 때문입니다. 누군가는 1장짜리 추론 테스트를 돌리고, 누군가는 64장짜리 학습을 돌립니다. 작은 작업이 빈틈을 먼저 채우면 큰 작업이 필요한 여덟 자리가 한 번에 나지 않습니다. 이때 스케줄러가 원칙 없이 먼저 온 순서대로 채우면 큰 작업은 계속 미뤄집니다. 저는 이 대목을 읽으면서 예전의 배치 시스템을 떠올렸는데요. 공평해 보이는 선착순이 실제로는 큰 작업을 굶기는 구조였던 적이 많았습니다. 공평함도 설계하지 않으면 한쪽으로 기울기 때문입니다.

통신 거리가 곧 학습 시간인 이유
같은 여덟 장을 써도 학습 속도가 달라지는 경우가 있습니다. 기계 값은 같은데 어떤 날은 빠르고 어떤 날은 느립니다. 차이는 대개 통신 거리에서 생깁니다. 분산 학습은 계산만큼이나 통신을 많이 하는데, GPU끼리 얼마나 가깝게 붙어 있느냐에 따라 all-reduce 시간이 크게 달라지기 때문입니다. 가까우면 NVLink나 NVSwitch로 빠르게 주고받고, 멀어지면 노드 바깥의 InfiniBand를 타야 하며, 그마저도 NUMA 구조를 잘못 타면 돌아가는 길이 생깁니다.
이 글에서 소개하는 측정 하나가 눈에 밟혔습니다. topology를 고려한 배치, 우리 말로 풀면 기계의 연결 구조에 맞춘 배치가 all-reduce 통신 시간을 30% 넘게 줄였다는 대목입니다. 같은 연산, 같은 모델, 같은 GPU 수인데 배치만 바꿨을 뿐인데 통신이 그만큼 줄었다는 것은 배치표가 곧 성능이라는 뜻이죠. 고속도로 옆에 창고를 지으면 운반 시간이 줄고, 강 건너에 지으면 다리 정체에 걸리는 것과 같습니다. 계산은 공장에서 하고, 통신은 도로에서 하는데, 우리는 자꾸 공장만 보고 도로를 잊습니다.
여기서 조금 조심해서 읽을 필요가 있습니다. 30%라는 숫자는 통신 시간의 감소이지 전체 학습 시간의 감소와 같지 않기 때문입니다. 통신 비중이 큰 모델에서는 전체 시간도 크게 줄지만, 계산 비중이 큰 모델에서는 효과가 작아질 수 있습니다. 그럼에도 이 차이가 중요한 이유는 대규모 학습일수록 통신 비중이 커지기 때문입니다. 모델이 커지고 worker가 늘어날수록 all-reduce는 더 자주, 더 무겁게 일어납니다. 작은 실험에서는 못 느끼던 도로 정체가 큰 실험에서는 출근길처럼 느껴지는 셈이죠. 실제 시스템 관점에서 보면 다음 질문이 바로 생깁니다. 우리 스케줄러는 GPU 사이의 거리를 알고 고르고 있을까요.
전부 함께가 아니라면 아예 시작하지 않는 원칙
앞 절의 gang scheduling 이야기로 다시 돌아오겠습니다. 왜냐하면 이 원칙은 말로는 쉬운데 구현은 까다롭기 때문입니다. 여덟 장이 동시에 비기를 기다리다 보면 클러스터에 빈틈이 생기고, 그 빈틈을 그냥 두면 사용률이 떨어집니다. 그래서 현장에서는 작은 작업을 빈틈에 끼워 넣고 싶은 유혹이 생깁니다. 그런데 작은 작업을 무턱대고 끼우면 정작 큰 작업이 들어갈 여덟 칸이 계속 안 나옵니다. 빈틈을 메우려다 큰길이 막히는 모양입니다.
저는 이 숫자보다 그 뒤의 구조가 더 중요하다고 봅니다. gang scheduling의 진짜 어려움은 기다림 자체가 아니라 기다림을 설계하는 일이기 때문입니다. 얼마나 기다릴지, 기다리는 동안 빈칸을 무엇으로 채울지, 큰 작업에 양보할 우선순위를 어떻게 둘지가 함께 정해져야 합니다. 예를 들어 큰 학습 작업이 곧 들어갈 예정이라면, 몇 분짜리 짧은 추론 작업만 빈틈에 넣고 긴 학습은 넣지 않는 식입니다. 주차장에서 대형 버스가 들어올 자리를 비워두려고 승용차 두 대는 세우되, 장기 주차 차량은 들이지 않는 것과 같습니다.
(참고로 현장에서 이 원칙을 어기면 어떤 일이 생기는지 저는 예전에 비슷한 장애로 배웠는데요. 일부 worker만 살아서 서로의 응답을 기다리다가 타임아웃이 났고, 로그에는 통신 오류만 남아서 네트워크를 의심했습니다. 나중에 알고 보니 네트워크가 아니라 스케줄링 순서 문제였습니다.) 이런 경험이 있어서인지, 저는 gang scheduling을 성능 기능이 아니라 안전장치로 봅니다. 없으면 가끔 느려지는 게 아니라, 있으면 안 되는 멈춤이 생기기 때문입니다.
조각난 빈칸이 GPU를 묶어두는 방식
클러스터가 비효율적으로 보이는 또 다른 이유는 파편화 때문입니다. GPU는 남았는데 CPU가 모자라고, CPU는 남았는데 메모리가 모자라는 식으로 요청 단위가 어긋나면 기계는 애매하게 남습니다. 8장이 있는 노드에 1장짜리 요청이 여기저기 흩어져 앉으면, 나중에 8장이 한 번에 필요한 작업은 들어가지 못합니다. 자리는 있는데 앉을 수 없는 영화관의 흩어진 빈자리와 같습니다.
그래서 이 글이 말하는 bin-packing이 나옵니다. 짐을 쌀 때 큰 짐부터 빈틈없이 넣고 작은 짐으로 사이를 메우는 것처럼, GPU 요청도 남는 자원을 적게 만드는 방향으로 모아서 배치한다는 것입니다. 그런데 packing만으로는 부족합니다. 시간이 지나면 작업이 끝나고 나가면서 다시 구멍이 생기기 때문입니다. 그래서 주기적인 defragmentation과 migration이 함께 필요합니다. 흩어진 작업을 조용히 옮겨서 빈 노드를 통째로 비워내고, 그 빈 노드에 큰 작업을 앉히는 것입니다. 이사할 때 짐을 한쪽으로 몰아서 큰 가구가 들어갈 벽을 비우는 것과 같습니다.
문제는 그다음입니다. 옮긴다는 것은 비용이 들기 때문입니다. 실행 중인 작업을 옮기려면 체크포인트를 만들고 다시 읽어야 하며, 그 사이에는 일이 멈춥니다. 자주 옮기면 packing은 좋아지지만 이주 비용이 쌓이고, 거의 옮기지 않으면 이주 비용은 없지만 파편화가 쌓입니다. 그래서 저는 이 대목을 효율 공식이 아니라 간격 조절 문제로 읽었습니다. 얼마나 자주 다듬을지, 어떤 작업은 옮기지 말지, 야간처럼 한가한 시간에 몰아서 할지가 운영의 감각입니다. 좋은 스케줄러는 빽빽하게 채우는 기계가 아니라, 언제 채우고 언제 비워둘지 아는 기계에 가깝습니다.

한 장을 일곱 장처럼 쓰는 날들
모든 작업이 GPU 한 장을 통째로 필요로 하지는 않습니다. 작은 파인튜닝이나 추론 테스트, 전처리와 맞물린 가벼운 학습은 한 장의 일부만 써도 충분합니다. 이때 한 장을 통째로 주면 나머지 성능이 버려집니다. 그래서 등장하는 것이 NVIDIA의 MIG와 MPS입니다. 하나의 물리 GPU를 최대 일곱 개의 격리된 조각으로 나누어, 여러 작업을 함께 올리는 방식입니다.
처음 이 방식을 보면 가상화처럼 느껴질 수 있는데요. 그런데 논의를 조금 더 들여다보면 진짜로 달라지는 부분은 나누는 기술 자체보다 어떤 일을 함께 두어도 되는지를 판단하는 기준에 있습니다. 추론처럼 지연에 민감한 작업과 학습처럼 처리량 위주의 작업을 한 장에 함께 두면 서로를 방해할 수 있기 때문입니다. 메모리 대역과 연산 유닛을 나누는 방식, 격리 수준, 스케줄링 우선순위가 함께 정해져야 합니다. 원룸을 칸막이로 일곱 개로 나눈다고 끝이 아니라, 누가 밤에 시끄럽게 일하는지와 누가 낮에만 쓰는지를 보고 방을 배정해야 하는 것과 같습니다.
그렇다면 왜 일곱 개까지 나누는데도 현장에서는 통째로 쓰는 경우가 많을까요. 이유는 운영의 번거로움 때문입니다. 조각을 나누고 회수하고 크기를 바꾸는 일이 수작업이면, 엔지니어는 그냥 통째로 주는 쪽을 택합니다. 바빠서 칸막이를 치기보다 넓은 방을 통째로 빌려주는 셈이죠. 그래서 MIG와 MPS의 효과는 하드웨어 기능만으로 정해지지 않습니다. 스케줄러가 작은 작업을 자동으로 감지해서 조각에 앉히고, 끝나면 조각을 회수해서 다음 작업에 넘기는 흐름까지 있어야 합니다. 저는 그래서 이 기술을 가속기 기능이 아니라 스케줄러와 함께 봐야 하는 운영 장치로 봅니다.
탄력적으로 늘었다 줄었다 하는 클러스터
큰 학습 작업은 오래 갑니다. 며칠에서 몇 주까지 가는 경우도 있는데, 그 사이 클러스터 상황은 계속 바뀝니다. 낮에는 추론이 몰리고 밤에는 학습이 몰리며, 급한 실험이 끼어들기도 합니다. 이때 학습 크기를 고정해두면 대응이 어렵습니다. 그래서 Microsoft Singularity가 보여준 방향이 눈에 들어옵니다. 작업이 늘었다 줄었다 할 수 있게 만들고, 밀리면 잠시 멈췄다가 체크포인트부터 다시 시작하는 elastic하고 preemptible한 운영입니다.
여기서 말하는 goodput이라는 표현이 재미있습니다. throughput이 기계가 한 일을 재는 말이라면, goodput은 그중에서 실제로 쓸모 있게 된 일을 재는 말에 가깝습니다. 중간에 끊겨서 버려진 계산은 throughput에는 잡히지만 goodput에는 잡히지 않습니다. 체크포인트와 재시작이 중요한 이유가 여기에 있습니다. 끊길 수 있는 구조에서는 끊긴 뒤에 얼마나 빨리, 얼마나 손해 없이 돌아오느냐가 실력입니다. 마라톤에서 넘어졌을 때 어디까지 되돌아가야 하는지가 기록을 가르는 것과 같습니다.
그런데 탄력 운영은 공짜가 아닙니다. 작업이 worker 수에 따라 속도가 매끄럽게 변해야 하고, 체크포인트를 자주 만들면 저장장치 부담이 커지며, 뺏고 빼앗기는 preemption이 잦으면 모두가 불안해집니다. 그래서 저는 이 방식을 만능 처방이 아니라 조건이 붙는 처방으로 읽었습니다. 체크포인트가 가볍고, worker 수 변화에 잘 적응하고, 중단되어도 처음부터 다시 하지 않는 작업에 잘 맞습니다. 반대로 통신 구조가 worker 수에 민감하거나 체크포인트가 무거운 작업은 탄력 운영의 이득이 작아질 수 있습니다. 유연함도 재료가 받쳐줘야 맛이 납니다.

공평함도 결국 설계의 문제다
연구 조직의 클러스터에는 늘 긴장이 있습니다. 각 팀은 자기 실험이 급하고, 운영자는 전체 사용률을 올려야 하며, 프로덕션은 안정적으로 돌아야 합니다. 이때 선착순만으로 줄을 세우면 특정 팀이 기계를 독식하거나 급한 작업이 묻히는 일이 생깁니다. 그래서 Slurm과 Volcano와 YARN의 Capacity Scheduler 같은 fair-share 스케줄러가 quotas와 priorities와 preemption을 씁니다. 말 그대로 몫을 나누고, 순서를 정하고, 필요하면 양보시키는 것입니다.
이 구조를 아파트 관리에 비유해볼 수 있습니다. 각 세대에 주차 몫이 있고, 손님이 오면 빈자리에 잠시 세울 수 있으며, 주인이 돌아오면 손님 차는 비켜줘야 합니다. quota가 세대별 몫이고, priority가 손님과 주인을 구분하는 규칙이며, preemption이 비켜주기입니다. 비켜준 손님 차가 갈 곳이 있어야 하듯, preemption당한 작업도 체크포인트부터 다시 시작할 곳이 있어야 합니다. 그래서 공평함은 단순한 마음씨가 아니라 저장과 재시작과 큐 설계가 함께 있어야 하는 기술입니다.
그렇다면 공평과 효율 중 무엇을 먼저 둘까요. 저는 이 질문 자체가 함정이라고 봅니다. 둘 중 하나만 고르면 어느 쪽이든 어딘가는 막히기 때문입니다. 공평만 따지면 기계가 조각나고, 효율만 따지면 특정 팀이 굶습니다. 현장에서 통하는 답은 대개 섞기입니다. 평소에는 팀별 몫을 지키되, 빈 기계는 누구든 빌려 쓰고, 주인이 돌아오면 돌려주는 식입니다. 빈방을 묵히느니 손님을 재우되, 주인이 오면 방을 비워주는 운영이죠. 이런 운영이 되려면 빌려준 자리를 얼마나 빨리 비울 수 있는지가 관건이고, 그 속도가 결국 체크포인트와 preemption 설계로 돌아옵니다.
스케줄러를 고를 때 제가 따지는 것들
저희가 새로운 AI 인프라 글을 볼 때도 benchmark 숫자만 보지는 않습니다. 실제로 무엇이 바뀌었고, 그 변화가 시스템에서 어떤 비용 구조를 만드는지를 함께 봅니다. 이 글도 같은 눈으로 읽었는데요. 제가 이 글에서 가장 흥미롭게 본 부분은 빠른 기계 이야기가 아니라 비어 있는 기계 이야기로 성능을 설명하는 방식이었습니다. 보통은 GPU 자체의 flops나 메모리 대역을 말하는데, 여기서는 배치표와 순서와 양보 규칙이 주인공입니다.
실제 시스템 관점에서 보면 다음 질문이 바로 생깁니다. 우리 워크로드는 통신에 민감한가, 아니면 계산에 민감한가. 작은 작업이 많은가, 큰 학습이 많은가. 체크포인트가 가벼운가, 무거운가. 야간과 주간의 패턴이 다른가. 이 질문에 답이 다르면 좋은 스케줄러의 모양도 달라집니다. 통신이 무거운 팀에는 topology 배치가 먼저이고, 작은 작업이 많은 팀에는 packing과 MIG 조각이 먼저이며, 급한 실험이 자주 끼어드는 팀에는 preemption과 체크포인트가 먼저입니다. 만능 스케줄러를 찾기보다 우리 병목을 먼저 재는 쪽이 빠릅니다.
여기서는 조금 조심해서 읽을 필요가 있습니다. topology 배치로 통신이 30% 넘게 줄었다는 결과는 조건이 맞는 곳에서는 크게 먹히지만, 모든 클러스터에서 같은 숫자가 나오지는 않기 때문입니다. 이미 배치가 잘 되어 있는 곳에서는 개선이 작고, 네트워크가 충분히 빠른 곳에서는 통신 자체의 비중이 작습니다. 숫자를 그대로 외우기보다 조건을 함께 외우는 편이 좋습니다. 어떤 기계에서, 어떤 규모에서, 어떤 통신 패턴에서 나온 이득인지를 묻는 것이죠. 저는 그래서 단일 숫자보다 그 숫자가 나온 배치를 더 오래 봅니다.

숫자를 읽기 전에 조건을 먼저 묻는 이유
이 글의 숫자들은 얼핏 보면 단순합니다. 사용률은 30%에서 50%, 통신은 30% 넘게 감소, 조각은 최대 일곱 개. 그런데 숫자를 나란히 놓고 보면 서로 다른 종류의 숫자라는 점이 보입니다. 사용률은 관측이고, 통신 감소는 특정 배치의 효과이며, 일곱 개는 하드웨어가 허용하는 상한입니다. 관측과 효과와 상한을 같은 선에 놓고 비교하면 판단을 그르치기 쉽습니다. 일곱 개로 나눌 수 있다는 말이 일곱 개로 나누면 항상 좋다는 말은 아니기 때문입니다.
좋은 건 알겠는데, 이걸 실제로 어떻게 운영할까요. 제가 앞으로 보고 싶은 것은 바로 이 운영의 디테일입니다. topology 배치를 매번 수작업으로 할 수는 없으니, 스케줄러가 자동으로 거리를 재는지, gang scheduling 대기 때문에 생기는 빈틈을 어떤 길이의 작업으로 채우는지, defrag 이주를 하루에 몇 번 어느 시간에 하는지, MIG 조각의 크기를 워크로드에 맞춰 바꾸는지 같은 것들입니다. 논문 속 숫자는 출발점이고, 운영 속 숫자가 진짜 성적표입니다. 클러스터는 논문이 아니라 달력으로 돌아가기 때문입니다.
겉보기에 좋아 보이는 숫자 뒤에 숨은 비용도 함께 봐야 합니다. packing을 빽빽하게 하면 사용률은 오르지만, 한 노드에 일이 몰리면서 장애의 blast radius가 커집니다. preemption을 자주 쓰면 급한 일은 빨라지지만, 밀려난 일의 재시작 비용이 쌓입니다. 탄력 운영을 켜면 빈틈은 줄지만, 체크포인트 저장장치와 네트워크에 새로운 짐이 생깁니다. 그래서 저는 효율 이야기를 들을 때마다 반대쪽 저울을 함께 봅니다. 얻은 것과 함께 잃은 것이 무엇인지, 그 교환이 우리 팀에는 남는 장사인지를 묻는 것이죠.
다음 실험을 본다면 어디를 볼까
이 글을 덮으면서 남는 질문이 있습니다. 그렇다면 우리 클러스터의 다음 병목은 어디일까요. 저는 답을 숫자보다 장면에서 찾고 싶은데요. 밤사이 대형 학습이 gang 대기로 멈춰 있는지, 아침에 출근하면 작은 추론들이 큰 자리를 조각내어 앉아 있는지, 특정 랙에만 통신이 몰려서 InfiniBand가 붐비는 시간대가 있는지 같은 것들입니다. 대시보드의 평균 사용률은 60%인데 정작 급한 실험은 계속 밀린다면, 평균이 아니라 분포와 순서의 문제일 가능성이 큽니다.
제가 앞으로 보고 싶은 연구는 실패 장면의 기록입니다. topology 배치를 켰는데 효과가 작았던 곳은 어떤 통신 패턴이었는지, MIG로 나눴는데 오히려 느려진 조합은 무엇이었는지, preemption을 켰다가 재시작 비용 때문에 다시 끈 팀은 어디에서 선을 그었는지 같은 것들입니다. 성공 사례는 방향을 알려주지만, 실패 사례는 경계를 알려주기 때문입니다. 경계를 알아야 우리 팀에 맞게 옮길 수 있습니다. 남의 정답을 베끼는 것보다 남의 오답을 피하는 쪽이 운영에서는 faster합니다.

같은 돈으로 더 일하는 감각
돌아보면 이 글의 메시지는 한 문장으로 모입니다. GPU가 부족해서가 아니라 GPU 사이의 순서와 거리와 나눔을 몰라서 손해가 난다는 것입니다. 그래서 처방도 기계를 더 사는 것이 아니라 배치표를 고치는 쪽에 가깝습니다. 함께 가야 할 일은 함께 들여보내고, 가까운 자리끼리 붙여 앉히고, 빈틈은 작은 일로 메우되 큰길을 막지 않으며, 한 장이 남으면 나누어 쓰고, 바쁠 때는 양보시키고 체크포인트부터 돌아오는 것입니다. 말로 풀면 상식처럼 들리는데, 막상 자동화된 규칙으로 만들려면 손이 많이 갑니다.
다행히 시작점은 소박합니다. 당장 내일 아침에 할 수 있는 일부터 떠올리면 됩니다. 큰 학습이 어느 큐에서 얼마나 기다리는지 재어보고, 통신이 무거운 작업이 노드 바깥에 흩어져 있는지 확인하고, 1장짜리 작업이 큰 노드를 조각내고 있지는 않은지 보고, 체크포인트가 얼마나 자주 저장되고 복구에 얼마나 걸리는지 재보는 것입니다. 거창한 교체가 아니라 재는 일부터 시작하는 것이죠. 재야 고칠 곳이 보이고, 고쳐야 산 숫자가 나옵니다.
그렇다면 사람의 역할은 무엇일까요. 스케줄러가 똑똑해질수록 사람의 일은 줄어드는 것처럼 보이지만, 저는 반대로 봅니다. 어떤 기다림을 허용할지, 어떤 양보를 정당하다고 볼지, 어떤 손해를 감수하고 빈틈을 메울지는 결국 사람이 정해야 하기 때문입니다. 기계는 빈칸을 잘 메우지만, 어떤 빈칸은 비워둬야 한다는 판단은 사람이 합니다. 좋은 스케줄링은 그래서 기술이면서 운영 철학입니다. 같은 돈으로 더 일하는 감각, 그 감각을 규칙으로 옮기는 일이 남습니다.
참고 자료
- Impactful scheduling for GPU clusters · huggingface.co
리뷰 원문