Nomad 스케줄링이 작동하는 방식

Nomad 스케줄링이 작동하는 방식

Nomad는 잡(job), 노드(node), 할당(allocation), 평가(evaluation)라는 네 가지 구성 요소로 잡 스케줄링을 구현해요. 이 페이지에서는 잡 라이프사이클과, 스케줄러가 서버가 구현하는 할당 계획을 어떻게 만들어 내는지 설명드릴게요. 스케줄러는 service, batch, system, sysbatch, core 중 하나로 동작해요.

출처: Hashicorp 공식 문서 - How Nomad job scheduling works

본문

Nomad에는 네 가지 핵심 구성 요소가 있어요: 잡(job), 노드(node), 할당(allocation), 평가(evaluation). 잡은 사용자가 제출하고 원하는 상태(desired state) 를 나타내요. 잡은 실행할 태스크를 선언적으로 기술한 것이며, 제약 조건으로 한정되고 리소스를 요구해요. 태스크는 Nomad 클라이언트가 실행 중인 클러스터의 노드에 스케줄될 수 있어요. 잡의 태스크를 클라이언트로 매핑하는 것이 바로 할당이에요. 할당은 잡의 태스크 집합을 특정 노드에서 실행해야 한다고 선언하는 데 사용돼요. 스케줄링은 적절한 할당을 결정하는 과정이며, 평가의 일부로 수행돼요.

**평가(evaluation)**는 외부 상태(원하는 상태든 발생한 상태든)가 바뀔 때마다 생성돼요. 원하는 상태는 잡에 기반을 두므로, 새 잡이 제출되거나 기존 잡이 갱신되거나 잡이 등록 해제되면 원하는 상태가 변해요. 발생한 상태는 클라이언트 노드에 기반을 두므로, 시스템의 어떤 클라이언트가 실패해도 처리해야 해요. 이런 이벤트가 새 평가 생성을 촉발해요. Nomad가 세계의 상태를 평가 하고 이를 원하는 상태와 맞춰야 하기 때문이죠.

평가의 라이프사이클은 어떤 이벤트가 평가 생성으로 이어지는 데서 시작돼요. 평가는 pending 상태로 생성되고 평가 브로커(evaluation broker)에 큐에 들어가요. 평가 브로커는 리더 서버에서 실행되고, 대기 중인 평가의 큐를 관리하고, 우선순위 순서를 제공하고, 적어도 한 번(at least once) 전달을 보장해요.

Nomad 서버는 스케줄링 워커를 실행하는데, 기본적으로 CPU 코어당 하나예요. 이 워커들이 평가를 처리해요. 워커는 브로커에서 평가를 꺼내고(dequeue), 잡이 지정한 적절한 스케줄러를 호출해요. Nomad에는 장기 실행 서비스에 최적화된 service 스케줄러, 배치 잡의 빠른 배치에 쓰는 batch 스케줄러, 모든 노드에서 잡을 실행하는 systemsysbatch 스케줄러, 내부 유지보수용 core 스케줄러가 함께 제공돼요.

스케줄러는 평가를 처리하고 할당 계획(plan) 을 생성하는 책임이 있어요. 계획은 축출(evict)하거나, 갱신하거나, 생성할 할당의 집합이에요. 계획을 만드는 구체적 로직은 스케줄러마다 다를 수 있지만, 대체로 스케줄러는 먼저 원하는 상태와 실제 상태를 조정해 무엇을 해야 하는지 결정해요. 새 할당을 배치해야 하고, 기존 할당은 갱신·마이그레이션·중지해야 할 수 있어요.

할당 배치는 **가능성 확인(feasibility checking)**과 **순위 매기기(ranking)**라는 두 단계로 나뉘어요. 첫 단계에서 스케줄러는 잡이 사용하지 않는 데이터센터와 노드 풀의 노드, 비정상( unhealthy) 노드, 필요한 드라이버가 없는 노드, 지정된 제약 조건을 통과하지 못한 노드를 필터링해 가능한(feasible) 노드를 찾아요.

두 번째 단계는 순위 매기기예요. 스케줄러가 가능한 노드에 점수를 매겨 가장 좋은 조합(best fit)을 찾아요. 점수 매김은 주로 빈 패킹(bin packing)에 기반하는데, 이는 애플리케이션의 리소스 활용률과 밀도를 최적화하기 위한 것이에요. 여기에 친화성(affinity)과 반친화성(anti-affinity) 규칙이 더해져요. Nomad는 자동으로 잡 반친화성 규칙을 적용해 태스크 그룹 여러 인스턴스의 동일 위치 배치(co-location)를 권장하지 않아요. 이 반친화성과 빈 패킹의 조합은 밀도를 최적화하면서 상관된 실패(correlated failures)의 확률을 줄여줘요.

스케줄러가 충분한 노드에 순위를 매기면 가장 높은 순위의 노드를 선택해 할당 계획에 추가해요.

계획 수립이 끝나면 스케줄러는 계획을 리더에 제출하고, 리더는 이를 계획 큐(plan queue)에 추가해요. 계획 큐는 대기 중인 계획을 관리하고, 우선순위 순서를 제공하며, Nomad가 동시성 경합(concurrency race)을 처리할 수 있게 해요. 여러 스케줄러가 락이나 예약 없이 병렬로 실행되므로 Nomad는 낙관적 동시성(optimistically concurrent)을 띠어요. 그 결과 스케줄러가 같은 노드에서 작업이 겹쳐 리소스 초과 예약(over-subscription)을 일으킬 수 있어요. 계획 큐는 리더 노드가 이로부터 보호하고, 계획을 부분 또는 전체 거부할 수 있게 해줘요.

리더가 계획을 처리하면서 충돌이 없으면 할당을 만들고, 그렇지 않으면 계획 결과의 실패를 스케줄러에 알려요. 계획 결과는 스케줄러에 피드백을 제공해서, 이전 계획이 부분 또는 전체 거부됐다면 종료하거나 대안 계획을 탐색하게 해요.

스케줄러가 평가 처리를 마치면 평가 상태를 갱신하고 평가 브로커에 전달을 확인(acknowledge)해요. 이로써 평가의 라이프사이클이 완료돼요. 그 결과 생성·수정·삭제된 할당은 클라이언트 노드가 가져가서 실행을 시작해요.

더 알아보기