SolidQueue: 관계형 데이터베이스 기반의 새로운 Ruby on Rails 백그라운드 작업 처리 시스템

[EN] Solid Queue internals, externals and all the things in between - Rosa Gutierrez

작성자
Visuality
발행일
2025년 03월 17일

핵심 요약

  • 1 SolidQueue는 Redis 의존성을 줄이고 관계형 데이터베이스를 활용하여 Ruby on Rails의 백그라운드 작업을 처리하는 새로운 Active Job 백엔드입니다.
  • 2 `FOR UPDATE SKIP LOCKED`와 최적화된 테이블 설계를 통해 데이터베이스 폴링의 비효율성을 극복하고 높은 처리량을 달성합니다.
  • 3 Rails 8의 기본값으로 채택되었으며, 37signals의 Hey 서비스에서 하루 2천만 건 이상의 작업을 안정적으로 처리하며 그 효용성을 입증했습니다.

도입

본 발표는 Ruby on Rails의 새로운 Active Job 백엔드인 SolidQueue에 대해 다룹니다. 37signals의 개발자인 Rossa Gutierrez는 SolidQueue가 기존의 Redis 기반 솔루션(Resque, Sidekiq 등)과 달리 관계형 데이터베이스를 활용하여 백그라운드 작업을 처리한다고 설명합니다. 이는 Redis와 Memcached 같은 키-값 저장소의 사용을 대체하려는 "Solid Trifecta"의 일환으로 개발되었으며, Rails 8의 기본 백엔드로 채택되었습니다. SolidQueue 개발의 주된 동기는 37signals가 기존에 사용하던 7가지 Resque 관련 젬들의 복잡한 조합을 단순화하고, 데이터베이스 중심의 일관된 아키텍처를 구축하는 데 있었습니다.

SolidQueue는 데이터베이스를 활용한 백그라운드 작업 큐잉 시스템이 직면하는 고유한 도전 과제, 특히 “폴링 경쟁(polling contention)” 문제를 해결하는 데 중점을 둡니다. 기존 데이터베이스 기반 큐 시스템은 여러 워커가 동시에 새 작업을 찾기 위해 테이블을 폴링할 때, 작업 잠금으로 인해 대기 시간이 발생하는 문제가 있었습니다. SolidQueue는 MySQL과 PostgreSQL에서 제공하는 FOR UPDATE SKIP LOCKED 기능을 활용하여 워커들이 서로 대기하지 않고 잠긴 행을 건너뛰고 다음 작업을 즉시 가져갈 수 있도록 함으로써 이 문제를 해결합니다.

또한, SolidQueue는 큐 테이블의 크기를 최소화하는 독창적인 설계 방식을 채택했습니다. 모든 작업을 하나의 거대한 테이블에 저장하는 대신, ready, scheduled, claimed 등 작업의 상태에 따라 별도의 작은 테이블에 메타데이터를 분리하여 저장합니다. 이를 통해 폴링 쿼리의 성능을 극대화하고, 데이터베이스 부하를 줄입니다. 예를 들어, 미래에 실행될 작업은 scheduled 테이블에, 즉시 실행될 준비가 된 작업은 ready 테이블에 보관하며, 워커가 작업을 가져가면 claimed 테이블로 이동시킵니다. 작업이 완료되면 claimed 테이블에서 제거되어 테이블 크기가 항상 작게 유지됩니다.

SolidQueue는 지연 작업(delayed jobs), 반복 작업(recurring jobs), 큐 일시 중지(pausing queues), 그리고 동시성 제어(concurrency controls)와 같은 다양한 Active Job 기능을 지원합니다. 특히 동시성 제어는 특정 작업들이 동시에 실행되지 않도록 보장하며, 이는 기존 Resque 시스템에서 Redis의 데이터 구조를 활용하여 구현했던 복잡한 로직을 세마포어(semaphore) 개념을 도입하여 데이터베이스 수준에서 간결하게 처리합니다.

성능 측면에서, SolidQueue는 높은 부하를 처리하기 위해 자체 데이터베이스 인스턴스를 사용하는 것을 권장합니다. 이는 특히 SQLite와 같이 동시 쓰기(concurrent writes)를 지원하지 않는 데이터베이스에서 애플리케이션의 성능 저하를 방지하는 데 중요합니다. 폴링 쿼리는 큐 이름과 우선순위에 대한 커버링 인덱스(covering indexes)를 활용하여 최적화되었으며, 이를 통해 초당 수백 건의 쿼리에도 불구하고 각 쿼리당 평균 110 마이크로초의 매우 낮은 실행 시간을 보여줍니다.

SolidQueue의 작업 인큐잉 속도는 Redis 기반 솔루션(예: Resque)보다 느리지만(약 3~6ms vs 1ms 미만), 대부분의 Rails 애플리케이션에서 작업 인큐잉이 쓰기 요청(POST/PUT)에서 발생하고, 이러한 요청 자체가 데이터베이스 쓰기로 인해 느리다는 점을 고려할 때, 전체 응답 시간에 미치는 영향은 미미합니다. 오히려 대량 작업 인큐잉 시 SolidQueue의 일괄 처리 기능은 Resque보다 빠른 성능을 제공합니다. 운영적인 측면에서 SolidQueue는 Active Record 객체를 통해 작업을 관리하므로, 기존 Rails 애플리케이션 데이터를 다루는 것처럼 직관적이고 문제 해결이 용이하다는 큰 이점이 있습니다.

결론

SolidQueue는 37signals의 Hey 서비스에서 하루 2천만 건 이상의 작업을 성공적으로 처리하며 그 견고함과 실전 검증을 마쳤습니다. 개발 과정에서 실제 프로덕션 환경에서의 경험을 바탕으로 기능이 추가되고 개선되었으며, 이는 "battle-tested"를 넘어 "fun-tested"라는 표현으로 그 안정성을 강조합니다. 발표자는 PostgreSQL 및 SQLite와 같은 다른 데이터베이스 환경에서의 개선을 위해 커뮤니티의 기여를 독려하며, SolidQueue가 Ruby on Rails 생태계에 중요한 기여를 할 것으로 기대합니다. SolidQueue는 관계형 데이터베이스의 장점을 최대한 활용하여 단순하면서도 강력하고, 운영하기 쉬운 백그라운드 작업 큐잉 시스템의 새로운 표준을 제시합니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!