/ The Blog of Jinho Ko / Computer science

·

5 min read

Constructing a GPU Cluster

By Jinho Ko

벌써 오래 전 일이다. 과거의 경험을 되살려 많은 사람이 사용하기 위한 GPU 클러스터를 구축했던 경험을 써 본다.

Motivation

“Don’t ever let your GPU be idle”

GPU를 사용하는 딥 러닝 연구에 가장 중요한 말이 아닐까 싶다. 일반적으로 딥러닝 학습은 꽤 길다. 그래서 가설에 대한 결과 검증이 오래 걸리고, 반대로 얘기하면 GPU를 놀게 하지 않는 법을 찾아야 실험이든 학습이든 빠르게 진행된다는 것이다.

개인적인 노력으로도 어느 정도는 극복이 가능하겠지만, 단순히 개인의 노력에만 맡기기에는, 특히 사용하는 사람이 여럿이라면 한계가 있는 것이 사실이다. 따라서 시스템적인 노력이 필요하며, 딥 러닝 연구 자체이 사이클이 빠르다는 점에서 이러한 시스템은 절실하다. 실제로 많은 기업들은 각자의 딥 러닝 클러스터를 구축해서 운영 중이기도 하다.

일반적으로 학습용 머신에는 GPU가 여러 대 꽂혀 있고 그 머신들이 여러 대 있을 것이다. 여러 사람이 수요에 맞게 GPU를 사용하고 학습이 끝나면 GPU를 반환하는 클러스터가 필요하다. 또 모델이 계속 커짐에 따라 단일 GPU로는 트레이닝이 안 되는 경우도 많다. 이럴 땐 Distributed training을 해야 하는 복잡함까지 발생한다.

이러한 모든 경우를 고려한 GPU 클러스터 매니저 및 스케쥴러를 만드는 것이 목적이었다.

Environment & Decisions

내가 세팅해야 하는 환경은 개당 8대의 GPU가 꽂혀 있고, 그 서버가 10-20대정도는 있었다. 그리고 총 세 종류의 GPU가 있었다. 각 수요에 맞게 자원을 할당하는 것은 정말 어려운 일이었다.

우선 가장 먼저 알아본 것이 네이버에서 공개한 NSML이었다. Hadoop 기반의 HDFS, YARN을 통해 클러스터를 관리했다. 알던 소프트웨어들이기 떄문에 쉽게 deploy가 가능해 보였다. 다만 이 플랫폼에서 코딩 환경이 까다롭고, 계속 업데이트 되는 딥러닝 환경에 맞추려면 유지보수 코스트가 너무 컸다. 그리고 결과적으로 리소스 간 격리가 되지 않았다.

그래서 다른 플랫폼을 알아 보니, Microsoft에서 만든 OpenPAI라는 오픈소스가 있었다. 여기서 가정하는 학습 환경은 우리가 필요한 환경(테스트 및 학습 등)과는 좀 달랐지만서도, 사용성은 가장 좋았기에 올려보기로 했다. 예를 들어 사용자가 딥러닝 구현을 할 때 모델을 테스트 해 보는 과정이 필요하고 또 테스트가 끝나면 학습을 시키는 과정이 필요한데, 그 두 경우에 GPU 사용 패턴이 달랐다.

또 스토리지의 경우, NFS 서버를 구축해서 쓰기로 했다.

Development Stage & Breakthroughs

이 시스템은 Kubernetes 위에서 돌아가는데, 처음에는 아무것도 모르고 일단 설치 매뉴얼을 그대로 따라했다. 그래서 그런지 이 초기의 작업(과정 수행 도중 엄청난 걸 하는 줄 알았으나, 나중에 보니 kuberspray를 이용해 kubernetes를 설치하는 것 뿐이었음)은 엄청난 지옥이었다.

그리고, 가장 큰 문제는 머신들이 다 제각각(OS, 디스크 상태 등)이며 clean state에서 시작하지 않았 보니, 각 머신마다 kuberspray requirements를 만족하지 못한느 경우가 너무 많이 있었다. 또 클러스터가 학교 안에 있었어서 DNS문제로 설치가 제대로 안되는 점 등, 꽤 까다로운 점들이 많았고 이런 점들을 계속 부딪히며 수정해 나갔다.

또 심지어 오픈소스이다 보니 설치 과정에서 버그가 몇 개 있었다. 당연히 라이브러리에는 버그가 없겠거니 하는 가정을 하고 진행했기 때문에, 이 가정에 문제가 있다는 사실을 깨닫기까지 엄청난 뻘짓을 하고 그 과정이 매우 오래 걸렸다.

그래서 이 하나의 오픈소스를 설치 성공해서 처음 돌려보는 데 까지만 해도 몇 달이 걸렸다.

지금부터 이 플랫폼을 어떻게 수정했는지 서술해보겠다.

  • 시스템 concept 변경 (debug / train 모드 두 개 유지)
    • Debug모드에서는 리소스가 부족해도 진행 작업이 날라가므로 존재하는 container를 절대 evict하면 안되었다.
    • PAI에서는 retry와 같은 개념이 있었지만, 나는 이 개념이 필요없다고 봤다. 어짜피 고정된 resource, 고정된 task에서 학습이 돌기 때문에, 될 학습은 무조건 되고 안될 학습은 무조건 안된다고 봤기 때문이다. 따라서 이러한 기능들은 없애고, 반대로 debug모드에는 절대 container가 유지되도록 하는게 필요했다.
    • 이 방법을 엄청 찾아봄, 이 과정에서 kubernetes docs가 매우 부실하다는 것을 깨달음.
    • 결과적으로는, kubelet의 storage eviction threshold를 엄청 낮추는 것으로 했다. 즉 사실상 eviction이 발생하지 않게 했다. 물론 완전한 솔루션은 아니고 어느 정도 요행을 바라는 솔루션이었다.
  • Infiniband를 위한 IP 분리
    • 빠른 intercommunication을 위해 infiniband의 IPoIB를 사용하기로 했는데, 그러면 머신끼리 통신하는 내부 망 IP랑 외부로 연결되는 IP 두개를 유지해야 했다. 이를 지원하기 위해 오만 시스템 로직을 수정했다.
  • 등등…

위 모든 과정은 사실 처음부터 잘 설계된 것이 아니라, 엄청난 삽질을 통해 incremental한 solution을 찾아 나갔던 것이다.

Some Maintenance Issues

  • Storage
    • storage monitoring process가 필요하다!
  • Docker 이미지 사이즈가 너무 크다.
    • 우리는 image storage로 dockerhub를 쓰는데, 문제는 이게 너무 느리다는 것이다.
    • 이미지가 로컬 디스크에 캐시되면 로컬 디스크의 스토리지 프레셔가 생긴다.
    • 사용자 데이터는 NFS에 저장되어 각 컨테이너에 마운트되는데, NFS가 single file io에는 불편함이 없지만, 문제는 multiple file stream을 처리하는 데 너무 시간이 오래 걸린다는 것이다. 딥러닝 특성 상 데이터셋이 수많은 tiny files로 이뤄진 경우가 많은데, nfs의 특성 상 이 파일들을 불러오는 데 throughput이 너무 낮다는 문제가 있었다.

Documentation ; for admins and for users

  • 쓰고 보니까 admin docs가 user docs보다 더 길더라. 그만큼 복잡한 시스템을 관리하는 것은 쉽지 않은 일이다. admin docs를 쓰느 principle은, 다음과 같다.
    • 내가 당장 내일 사라져도, 어느 정도의 지식을 가진 사람이 왔을 때 (완전 초짜는 조금 힘들 것이다), 이 시스템을 100% 이해할 수 았는가?
    • 이걸 만족하려면, admin docs를 엄청 자세하게 써야 하는데, 특히 유의할 점은 내가 삽질해서 깨닫게 된 점을 나중에는 그 사람도 당연하게 알 것이라고 생각하고 생략하는 것이다. 같은 실수를 반복하게 하지 말아야 한다.

운영 및 홍보 후기

  • 사용자들은 생각보다 많은 뻘짓을 한다. (well-formed documentation의 중요성)

Summing Up

후기:

  1. 내가 사용자로써 써봤을 때, 아주 사용하기 편한 시스템이 완성되긴 했다.
  2. 다만, NLP같은 작업은 embedding도 불러 와야 하고, 태생적으로 좀 더 복잡한데 그런 것을 다루는 용이성도 지원되어야 함.
  3. 부족한 부분이 너무 많다. 편하다고 하지만 또 처음 쓰는 사람이 쓰기엔 좀 어렵다.

하지만 여기까지 온 것 만으로도 일개 학부생이 할 수 있는 정도로는 충분히 많이 했다고 본다. 좋은 경험이었다 ;)

last modified June 2, 2024
comments powered by Disqus

© Copyright 2024. Jinho Ko. All rights reserved. Last updated: June 02, 2024.