본문으로 건너뛰기

[Ray Core] OOM Killer에서 대용량 메모리를 점유한 유휴 워커를 우선 종료

PR 링크: ray-project/ray#60330 상태: Merged | 변경: +305 / -114

들어가며

Ray의 메모리 모니터는 노드의 메모리 사용량이 임계치를 초과하면 워커 프로세스를 종료하여 OOM(Out of Memory)을 방지한다. 그런데 조사 결과, 태스크 완료 후 IDLE 상태가 된 워커가 여전히 약 1GB의 메모리를 점유하는 현상이 발견되었다. 기존 OOM Killer는 태스크가 스케줄된 워커만 종료 대상으로 삼았기 때문에, 이런 유휴 워커들은 메모리를 잡고 있으면서도 종료되지 않았다.

핵심 코드 분석

새로운 설정값

// ray_config_def.h
RAY_CONFIG(int64_t,
           idle_worker_killing_memory_threshold_bytes,
           1024 * 1024 * 1024)  // 1GB

유휴 워커 메모리 조회 유틸리티

// memory_monitor_utils.cc
int64_t MemoryMonitorUtils::GetProcessUsedMemoryBytes(
    const ProcessesMemorySnapshot &snapshot, pid_t pid) {
  const auto it = snapshot.find(pid);
  if (it == snapshot.end()) {
    return 0;
  }
  return it->second;
}

OOM Killer 로직 변경

기존: 태스크가 할당된 워커 중에서만 종료 대상 선택 변경: 유휴 워커 중 메모리 사용량이 임계치(기본 1GB)를 초과하는 워커를 먼저 확인하고, 해당 워커가 있으면 우선 종료한 뒤 기존 로직으로 진행

왜 이게 좋은가

  1. 즉각적 메모리 회수: IDLE 워커가 1GB 이상의 메모리를 점유하고 있다면, 새 태스크를 위해 해당 메모리를 즉시 회수할 수 있다. 기존에는 이런 워커들이 자연적으로 종료될 때까지 기다려야 했다.
  2. 설정 가능한 임계치: idle_worker_killing_memory_threshold_bytes 설정으로 임계치를 조절할 수 있다. 기본 1GB로 설정하여 워커 프리스타트로 생성된 가벼운 유휴 워커가 불필요하게 종료되는 것을 방지한다.
  3. 기존 메트릭 확장: ray_memory_manager_worker_eviction_total 메트릭에 IdleWorkerEviction.Total 타입을 추가하여 유휴 워커 종료 횟수를 별도로 추적할 수 있다.
  4. 단기 완화 + 장기 과제: 이 PR은 근본 원인(왜 IDLE 워커가 메모리를 해제하지 않는지) 해결이 아닌 단기 완화책임을 명확히 하고, 후속 과제로 근본 원인 조사를 남겨두었다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글