Search Unity

Unity Simulation을 활용하면 파라미터화된 Unity 빌드의 수천 개 인스턴스를 클라우드에서 원활하고 효율적인 방식으로 일괄 실행할 수 있습니다. Unity Simulation은 Unity 프로젝트를 실행별로 파라미터화할 수 있도록 지원합니다. 또한 엔드 애플리케이션에 필요한 시뮬레이션 출력 데이터를 지정할 수 있으며 여기에는 머신러닝용 훈련 데이터 생성, AI 알고리즘의 테스트 및 검증, 모델링된 시스템의 평가와 최적화 등이 포함됩니다. Unity Simulation을 활용하면 잡 실행에 사용하는 배치 컴퓨팅 소프트웨어나 서버 클러스터를 설치하고 관리할 필요가 없어 결과를 분석하고 문제를 해결하는 데 집중할 수 있습니다. 이 블로그 포스팅에서는 지속적인 혁신 기술 개발을 통해 Unity Simulation에서 가능한 한 빠르고 비용 효율적으로 잡을 실행하도록 지원하는 방법을 소개합니다.

Unity Simulation과 쿠버네티스

Unity Simulation은 오픈 소스 시스템인 쿠버네티스(Kubernetes)를 활용하여 적합한 수와 유형의 연산 인스턴스로 시뮬레이션 잡을 컨테이너화, 예약, 및 실행합니다. 쿠버네티스를 사용하면 시뮬레이션 출력 데이터를 클라우드 스토리지 위치로 손쉽게 다운로드하여 설계와 훈련, 테스트에 활용할 수 있습니다. 또한 컴퓨팅 리소스 할당이나 용량 계획을 고려할 필요 없이 한 번에 다수의 시뮬레이션을 실행할 수 있습니다.

다음은 Unity Simulation과 쿠버네티스의 주요 개념입니다.

  • RD(Run Definition): 시뮬레이션의 이름과 설명, 시뮬레이션 실행에 사용되는 애플리케이션 파라미터 집합, 사용할 컴퓨팅 리소스를 지정하는 시스템 파라미터, 업로드된 Unity 실행 파일을 참조하는 Unity 빌드 ID를 지정합니다.
  • 쿠버네티스 : 쿠버네티스를 배포하면클러스터가 생깁니다. 쿠버네티스 클러스터는 컨테이너화된 애플리케이션을 실행하는 일련의 작업자 머신(노드)으로 구성됩니다. 작업자 노드는 애플리케이션 워크로드의 컴포넌트인 파드(Pod)를 호스팅합니다. 하나의 파드는 쿠버네티스 시스템의 기본 실행 단위로, 클러스터에서 실행되는 프로세스를 나타냅니다. 쿠버네티스 잡을 관리하는 시스템 수준의 잡 컨트롤러는 특정 시간 동안 실행 후 완료되는 배치 프로세스에 참여하는 파드를 감독합니다. 이 블로그에서 언급되는 “잡”은 모두 쿠버네티스 잡을 가리킵니다.
  • 쿠버네티스 컨트롤러 오퍼레이터: 쿠버네티스 컨트롤러는 리소스의 현재 상태를 원하는 상태로 점진적으로 이동하는 데 관여합니다. 쿠버네티스 잡 컨트롤러는 한 개 이상의 파드를 생성하며 특정 개수의 파드가 성공적으로 완료되도록 합니다. 쿠버네티스 오퍼레이터는 이 패턴을 따르는 컨트롤러이면서 워크로드를 실행하는 데 필요한 특정 운영 지식을 구현하기도 합니다. 유니티의 Simulation Job Operator는 쿠버네티스 오토스케일러의 동작이 각각 현재 상태와 원하는 상태에 미치는 영향을 이해하고 있습니다.

쿠버네티스 잡은 한 개 이상의 파드를 생성하며 정확한 개수의 파드가 성공적으로 완료되도록 합니다. 작업 대기열은 태스크를 잡에 할당된 파드로 배포하는 데 사용됩니다. 컨테이너에서 실행되는 애플리케이션 프로세스는 대기열에서 태스크를 동시에 선택하거나 필요할 때 개별적으로 선택할 수 있습니다. 잡의 병렬성 파라미터는 잡이 동시에 실행하는 병렬 파드의 개수(실행을 위한 동시 시뮬레이션 인스턴스의 개수)를 결정하는 데 사용됩니다. 잡의 완료 파라미터는 반드시 성공적으로 완료되어야 하는 파드의 개수를 결정합니다.

Unity Simulation 스케줄러는 쿠버네티스 잡과 대기열 설계 패턴을 활용하여 실행을 조정합니다. 스케줄러는 쿠버네티스 클러스터에 잡을 제출하기 전에 각 시뮬레이션 인스턴스에 전달될 메시지를 독립 실행 대기열에 추가합니다.

다음 다이어그램은 잡을 실행하기 위해 대기열을 사용하여 파드에 메시지를 배포하는 방법을 보여줍니다. 이 다이어그램에는 4개의 병렬 구조로 이루어진 잡이 나와 있습니다. 이는 시뮬레이션에서 실행되는 Unity 프로젝트의 인스턴스가 4개 있음을 의미합니다.

문제

대부분의 경우와 달리, 유니티에서는 쿠버네티스를 적용할 때 배치 프로세싱과 오토스케일링을 결합합니다. 하지만 잡의 배치 프로세싱과 쿠버네티스 오토스케일링이 동시에 진행될 경우 예상치 못한 상호 작용으로 인해 컴퓨팅 리소스가 크게 낭비되고 잡의 비효율성이 발생했습니다. 쿠버네티스 오토스케일러는 클러스터 확장 및 축소를 번갈아 진행하고 잡 컨트롤러는 부정확한 상태를 보고합니다. 이로 인해 잡 예상 완료 시간이 과장되고, 잡 완료 후 보고가 부정확하며, 전반적인 CPU 비효율성이 야기됩니다.

잡 수명 주기 동안 완료 개수가 동일하게 유지되거나 증가해야 하는데, 유니티의 지표에 따르면 잡의 개수가 감소한 것으로 나타났습니다. 부정확한 완료 개수로 인해 잡 컨트롤러는 성공적으로 완료되어야 하는 파드의 개수를 충족하기 위해 더 많은 파드를 생성하게 됩니다. 잡에서 더 많은 파드를 요청하면 쿠버네티스 오토스케일러는 클러스터에 노드를 추가하게 됩니다. 새로 생성된 파드는 대기열에 남은 태스크가 없기 때문에 생성되자마자 완료됩니다. 추가된 노드는 파드를 완료하면 완료 개수가 달성되기 때문에 곧 대기 상태가 됩니다. 그러면 오토스케일러가 대기 상태인 노드를 클러스터에서 제거하여 파드 완료 개수가 줄어듭니다.

이로 인해 다음과 같은 악순환이 발생합니다.

  1. 파드를 더 많이 실행하기 위해 확장됨
  2. 파드가 즉시 완료됨
  3. 노드가 대기 상태가 되어 축소됨

확장 시 문제가 있는 잡이 모든 클러스터 리소스를 활용하기 때문에 클러스터는 다른 작업을 실행할 수 없게 됩니다. 이 때문에 리소스가 낭비되거나 최악의 경우 서비스를 사용할 수 없게 됩니다.

이 문제는 다음 단계에서 자세히 설명합니다.

1단계:

Unity Simulation은 멀티 클라우드 솔루션이며 관리형 쿠버네티스 솔루션인 GKE를 사용하여 Google Cloud Platform에서 실행됩니다. GKE 클러스터에 파드 5개를 호스팅할 수 있는 노드인 Node1이 하나 있다고 가정해 보겠습니다. 새 잡은 15개의 파드를 필요로 하며 GKE 클러스터는 15개의 파드를 실행할 수 있도록 용량을 늘리기 위해 Node2와 Node3을 추가합니다.

2단계:

GKE 클러스터에서 모든 파드가 ‘활성’ 상태입니다.

3단계:

Node1에 있는 파드 5개가 잡 ‘완료’ 상태(녹색)로 바뀝니다.

4단계:

Node1에 있는 파드가 완료되어 대기 상태가 되고 축소됩니다. Node1이 클러스터에서 제거되면 Node1의 완료 개수인 5는 지워지고 잡의 완료 개수는 5가 아닌 0이 됩니다. 그러면 잡에서 예상하는 15개의 파드가 아닌 10개의 파드만 집계되기 때문에 오류가 발생합니다. 다시 잡 컨트롤러는 5개의 새 파드를 요청하고 오토스케일러는 클러스터에 노드를 추가합니다.

이 문제를 해결하기 위해서는 쿠버네티스의 잡 컨트롤러 소스 코드를 자세히 살펴봐야 합니다. 가령 SyncJob 함수는 잡에서 관리하는 파드의 현재 상태를 기반으로 잡의 상태를 동기화합니다. SyncJob은 getStatus를 호출하여 잡에서 성공한 파드와 실패한 파드의 개수를 파악합니다. 이를 위해 getPodsForJob 함수의 선택자를 사용하여 현재 클러스터에 존재하는 파드를 쿼리하여 파드 정보를 확인합니다.

하지만 쿠버네티스 클러스터에서 노드가 제거되는 경우 해당 노드에서 실행되던 파드의 메타데이터가 삭제됩니다. 오토스케일러가 노드를 제거한 뒤 잡 컨트롤러가 잡의 파드에 대해 쿠버네티스에 쿼리하는 경우, 잡 컨트롤러는 부정확한 완료 개수를 전달받습니다. 이 동작은 장기 실행되는 sleep 명령어 하나와 실행 시간이 더 짧은 다수의 sleep 명령어를 별도의 태스크에서 실행하는 간단한 잡을 생성하면 쉽게 재현할 수 있습니다.

해결책

잡 컨트롤러 소스 코드를 더 살펴본 후 파드의 상태를 지속하여 스케일링 문제를 해결할 수 있었습니다. 이렇게 하면 쿠버네티스 클러스터에서 확인할 수 없는 경우에도 파드 메타데이터를 캡처할 수 있습니다. 유니티는 시뮬레이션을 실행하기 위한 오퍼레이터를 개발하는 것이 다른 이점도 있다는 사실을 발견했습니다.

유니티에서 구현한 커스텀 리소스 정의와 오퍼레이터는 오토스케일링 문제 해결을 위해 수정된 현재 쿠버네티스 잡 컨트롤러와 매우 유사합니다. 유니티의 시뮬레이션 잡(SimJob) 오퍼레이터는 컨트롤 루프가 실행될 때마다 성공한 파드와 실패한 파드의 목록을 각각 업데이트합니다. 파드의 현재 상태는 쿠버네티스 클러스터 내에 있는 SimJob의 현재 상태와 성공한 파드, 실패한 파드의 고유한 집합을 포함하는 데이터 저장소의 현재 상태를 결정합니다.

다음 다이어그램은 클러스터가 축소된 경우에도 시뮬레이션 잡 오퍼레이터가 정확한 ‘완료’ 개수를 유지하는 모습을 보여줍니다.

지난 두 달간 시뮬레이션 잡 오퍼레이터를 운영 환경에서 실행해 보았습니다. 시뮬레이션 잡 오퍼레이터는 1,000건 이상의 시뮬레이션을 실행했으며 총 실행 인스턴스 수는 약 50,000개에 달했습니다. 파드당 시뮬레이션 인스턴스 수가 한 개 이상이기 때문에 파드 수 또한 약 50,000개라고 볼 수 있습니다. 이제 클러스터와 Unity Simulation 서비스의 가용성을 보장하면서 시뮬레이션 실행을 안전하게 오토스케일링할 수 있습니다. 만족스러운 이번 성과를 바탕으로 추후 시뮬레이션 잡 오퍼레이터를 더 개선하고 새로운 기능을 추가할 예정입니다.

결론

Unity Simulation은 머신러닝용 훈련 데이터 생성, AI 알고리즘의 테스트 및 검증, 모델링된 시스템의 평가와 최적화 등 데이터 기반 AI 분야를 선도하고 있습니다. 유니티 팀은 최상의 시뮬레이션 서비스 생태계를 제공하기 위해 매일 혁신을 거듭합니다.

유니티와 함께 Unity Simulation을 발전시키고 AI분야의 당면 과제를 해결하고 싶다면 유니티 채용 공고를 통해 지원하세요.

자세한 내용은 Unity Simulation을 참고하세요.