본 문서는 Ruby의 병렬성 프리미티브인 Ractor에 대한 현황과 저자의 견해를 설명합니다. Ractor는 Ruby 3.0에 도입되었으나, 기대와 달리 Ractor 기반 웹 서버와 같은 애플리케이션에서의 광범위한 채택이 이루어지지 않았습니다. 본 글은 Ractor의 설계 목표, 작동 방식, 현재의 제약 사항 및 잠재적 활용 분야를 탐구하여 Ruby HTTP 서버 설계의 맥락에서 Ractor의 타당성을 논합니다.
Ractor의 핵심 아이디어는 GVL(Global VM Lock)을 완전히 제거하지 않으면서도 진정한 인프로세스 병렬성을 구현하는 것입니다. 이는 가변 객체의 Ractor 간 직접 공유를 허용하지 않고, 객체 복사 또는 이동(move)을 통해 통신하는 액터 모델(Actor model)에 기반합니다. 이는 JavaScript의 Web Worker나 Python의 서브 인터프리터와 유사하지만, Ruby Ractor는 전역 네임스페이스를 공유한다는 점에서 차이가 있습니다. 이로 인해 기존 코드를 쉽게 활용할 수 있는 장점이 있으나, 가변 객체가 포함된 상수 접근 시 Ractor::IsolationError
가 발생하는 등 기존 Ruby 코드의 상당 부분이 Ractor에서 실행될 수 없는 제약이 발생합니다. 예를 들어, 기본값 설정을 위한 가변 해시 상수는 Ractor 호환성을 저해합니다. 또한, 데이터베이스 연결과 같은 C 확장으로 구현된 객체는 현재 Ractor 간 이동(move)이 불가능하여, 연결 풀과 같은 필수적인 구조를 Ractor 환경에서 구현하기 어렵게 만듭니다. 저자는 연결 객체를 별도의 Ractor 내부에 캡슐화하고 메시지 패싱을 통해 통신하는 우회 방법을 제시하지만, 이는 복잡하고 비효율적임을 지적합니다. 이러한 제약으로 인해 Rails와 같은 복잡한 애플리케이션의 전면 Ractor화는 현재 비실용적입니다. 더불어, Ractor는 여전히 많은 구현 문제(세그멘테이션 오류, 교착 상태)와 성능 문제를 가지고 있습니다. 특히, JSON 파싱 예제에서 보듯이, 일부 VM 내부 루틴은 여전히 모든 Ractor를 잠그는 ‘하나 더 남은 전역 잠금(One More Global Lock)’ 문제로 인해 기대만큼의 병렬 성능을 제공하지 못하기도 합니다.
결론적으로, Ractor는 Ruby에 병렬성을 도입하려는 중요한 시도이지만, 현재로서는 실험적이며 버그와 성능 제약이 많아 프로덕션 환경에서의 전면적인 활용은 어렵습니다. 가변 객체 공유 및 C 확장 호환성 문제는 기존 Ruby 코드와의 통합을 어렵게 만듭니다. 하지만, statsd-instrument나 OpenTelemetry와 같이 백그라운드에서 데이터를 수집/전송하는 라이브러리 내부의 저수준 병렬 처리와 같은 특정 사용 사례에는 현재의 제약 하에서도 유용하게 활용될 잠재력이 있습니다. Ractor 개발 과정에서 발생하는 동시성 해시 맵 구현 등은 향후 Ruby의 GVL 제거 작업에도 기여할 수 있는 중요한 진전으로 평가됩니다.