본문으로 건너뛰기

[Ray] find_gcs_addresses 결과 캐싱으로 프로세스 스캔 비용 제거

PR #61065 - [core] cache find_gcs_addresses

들어가며

Ray의 head 노드에서 RAY_ADDRESS 환경변수가 설정되지 않은 경우, find_gcs_addresses 함수가 시스템의 전체 프로세스 목록을 스캔하여 GCS 주소를 찾습니다. 이 프로세스 스캔은 매우 비용이 크며, Ray Data의 hanging detector에서 detect 함수 실행 시간을 지배할 정도였습니다. 이 PR은 결과를 캐싱하여 반복 호출 시 프로세스 스캔을 건너뜁니다.

핵심 코드 분석

Before

def find_gcs_addresses():
    """Finds any local GCS processes based on grepping ps."""
    return _find_address_from_flag("--gcs-address")

매 호출마다 ps 명령을 실행하고 결과를 파싱합니다.

After

_find_gcs_addresses_lock = threading.Lock()

@cache
def _cached_find_gcs_addresses():
    return frozenset(_find_address_from_flag("--gcs-address"))

def find_gcs_addresses():
    """Finds any local GCS processes based on grepping ps.
    Empty discovery results are not cached.
    """
    with _find_gcs_addresses_lock:
        addresses = _cached_find_gcs_addresses()
        if not addresses:
            _cached_find_gcs_addresses.cache_clear()
        return addresses

캐시 무효화 시점

# ray.init() 시
services.find_gcs_addresses.cache_clear()

# ray.shutdown() 시
services.find_gcs_addresses.cache_clear()

# 클러스터 시작/종료 시
ray._private.services.find_gcs_addresses.cache_clear()

왜 이게 좋은가

  1. 비용이 큰 프로세스 스캔 캐싱: ps 명령 실행과 결과 파싱을 한 번만 수행합니다.
  2. 빈 결과는 캐싱 안 함: GCS가 아직 시작되지 않은 경우 빈 결과를 캐싱하면 안 되므로, 빈 결과 시 캐시를 클리어합니다.
  3. 스레드 안전: threading.Lock으로 동시 접근을 보호하고, frozenset으로 불변 결과를 반환합니다.
  4. 적절한 무효화: ray.init(), ray.shutdown(), 클러스터 시작/종료 시 캐시를 클리어하여 상태 변화를 반영합니다.
  5. hanging detector 성능 개선: detect 함수에서 지배적이었던 GCS 주소 탐색 비용이 사라집니다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글