[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) 방식으로 전환할 때 메인 이벤트 루프를 블로킹하지 않기 위한 준비입니다.
왜 이게 좋은가
- 컴파일 시 바이너리 크기 최적화: Linux 전용 코드가 macOS/Windows 빌드에 포함되지 않습니다.
- 안전한 라이프타임 관리: 메모리 모니터가 자체 스레드를 소유하므로, 외부 I/O 컨텍스트의 라이프타임에 의존하지 않아 use-after-free 위험이 제거됩니다.
- 확장 용이:
MemoryMonitorInterface를 구현하는 새로운 OS별 모니터를 쉽게 추가할 수 있습니다. - 향후 push 기반 전환 준비: 별도 스레드로 분리하여 커널 이벤트 수신 시 메인 이벤트 루프에 영향을 주지 않습니다.
코드량 변화(-1012/+1585)가 크지만, 핵심은 단일 파일의 모노리식 구현을 인터페이스-구현 분리 + 팩토리 패턴 + OS별 조건부 컴파일로 정리한 것입니다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [pydantic-ai] Temporal/DBOS MCP 서버에서 매번 도구 목록을 다시 가져오는 문제 수정
- 현재글 : [Ray Core] Memory Monitor의 OS별 조건부 컴파일 패턴 적용
- 다음글 [Ray RLlib] SingleAgentEnvRunner의 validate 호출 위치 최적화로 3.1배 속도 향상
댓글