본문으로 건너뛰기

[Ray Core] Memory Monitor의 OS별 조건부 컴파일 패턴 적용

PR 링크: ray-project/ray#59368 상태: Merged | 변경: +1585 / -1012

들어가며

Ray Core의 메모리 모니터는 시스템 메모리 사용량을 추적하여 OOM(Out of Memory)을 방지합니다. 기존 구현은 단일 파일에 Linux과 다른 OS의 로직이 혼재되어 있었고, raylet의 메인 I/O 컨텍스트에서 주기적으로 폴링하는 방식이었습니다. 이 PR은 인터페이스 분리와 OS별 조건부 컴파일 패턴을 적용하여 아키텍처를 개선합니다.

핵심 코드 분석

인터페이스 분리

memory_monitor_interface.h   # 추상 인터페이스
├── threshold_memory_monitor  # Linux 전용 구현
├── noop_memory_monitor       # 비 Linux 플랫폼용 no-op
└── memory_monitor_factory    # OS에 따라 적절한 구현 선택

Bazel 빌드 규칙: OS별 조건부 컴파일

config_setting(
    name = "is_linux",
    constraint_values = ["@platforms//os:linux"],
)

ray_cc_library(
    name = "memory_monitor_factory",
    srcs = select({
        ":is_linux": ["threshold_memory_monitor_factory.cc"],
        "//conditions:default": ["noop_memory_monitor_factory.cc"],
    }),
    deps = [
        ":memory_monitor_interface",
        ":noop_memory_monitor",
    ] + select({
        ":is_linux": [
            ":ray_config",
            ":threshold_memory_monitor",
        ],
        "//conditions:default": [],
    }),
)

Linux에서는 cgroup 기반의 ThresholdMemoryMonitor가 컴파일되고, 다른 OS에서는 NoopMemoryMonitor가 사용됩니다.

별도 스레드로 분리

기존에는 raylet의 메인 I/O 컨텍스트에 주기적 러너를 등록하는 방식이었지만, 새 구현은 메모리 모니터를 별도 스레드에서 실행합니다. 이는 향후 폴링 방식에서 커널 알림(push) 방식으로 전환할 때 메인 이벤트 루프를 블로킹하지 않기 위한 준비입니다.

왜 이게 좋은가

  1. 컴파일 시 바이너리 크기 최적화: Linux 전용 코드가 macOS/Windows 빌드에 포함되지 않습니다.
  2. 안전한 라이프타임 관리: 메모리 모니터가 자체 스레드를 소유하므로, 외부 I/O 컨텍스트의 라이프타임에 의존하지 않아 use-after-free 위험이 제거됩니다.
  3. 확장 용이: MemoryMonitorInterface를 구현하는 새로운 OS별 모니터를 쉽게 추가할 수 있습니다.
  4. 향후 push 기반 전환 준비: 별도 스레드로 분리하여 커널 이벤트 수신 시 메인 이벤트 루프에 영향을 주지 않습니다.

코드량 변화(-1012/+1585)가 크지만, 핵심은 단일 파일의 모노리식 구현을 인터페이스-구현 분리 + 팩토리 패턴 + OS별 조건부 컴파일로 정리한 것입니다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글