Rescue에서 Solid Queue로의 성공적인 마이그레이션: Full Script의 경험

RailsConf 2025 From Resque to SolidQueue - Rethinking our background jobs for... by Andrew Markle

작성자
Ruby Central
발행일
2025년 07월 24일

핵심 요약

  • 1 Full Script는 기존 백그라운드 큐 시스템인 Rescue의 불안정성과 의존성 문제를 해결하기 위해 Rails의 새로운 기본 큐 어댑터인 Solid Queue로 성공적으로 전환했습니다.
  • 2 큐 이름을 지연 시간 허용치(latency tolerance) 기반으로 재정의하여 개발자와 운영팀 모두에게 명확한 서비스 수준 목표(SLO)를 제공하고 모니터링 및 자동 확장을 용이하게 했습니다.
  • 3 Solid Queue 마이그레이션 과정에서 발생한 데이터베이스 연결 부족, 메모리 부족, 느린 작업 처리 문제 등을 해결하며 시스템의 안정성과 성능을 크게 향상시켰습니다.

도입

Full Script의 스태프 엔지니어는 2011년부터 급성장한 비즈니스 규모에 맞춰 기존 시스템의 확장성 문제를 해결하고자 했습니다. 특히, 2011년 당시 표준이던 백그라운드 큐 시스템 Rescue는 시간이 지남에 따라 의존성 관리의 어려움과 예측할 수 없는 작업자(worker) 중단 문제로 인해 시스템의 신뢰성을 저해하고 있었습니다. 이에 Rails 8의 새로운 기본 큐 어댑터로 채택된 Solid Queue를 대안으로 검토하게 되었으며, 안정적이고 확장 가능한 큐 시스템으로의 전환을 목표로 마이그레이션을 추진했습니다.

Full Script는 Rescue의 불안정성과 유지보수 어려움을 해결하기 위해 Sidekiq, GoodJob(MySQL 미지원) 등의 대안을 검토한 후, Rails의 기본 어댑터로 통합된 Solid Queue를 선택했습니다. Solid Queue는 MySQL을 지원하며, 데이터베이스 기반으로 메트릭 수집이 용이하고 Rails의 지원을 받는 견고한 솔루션이라는 점이 주요 선택 이유였습니다.

마이그레이션은 다음과 같은 단계와 해결책을 통해 진행되었습니다.

1. Solid Queue 설정 및 아키텍처 결정

  • Active Job 전환: 모든 작업이 Active Job을 사용하도록 보장했습니다 (사전 작업 완료).
  • 데이터베이스 분리: 프로덕션 환경에서는 Solid Queue 전용 MySQL 데이터베이스를 생성하여 주 데이터베이스의 부하를 분리했습니다. 개발/스테이징 환경에서는 비용 절감을 위해 주 데이터베이스의 다른 스키마를 사용했습니다.
  • 트랜잭션 무결성: 초기 마이그레이션 중에는 Rescue와 동일하게 트랜잭션 무결성을 비활성화하여 기존 동작을 유지했습니다. 향후 필요에 따라 활성화할 계획입니다. (Rails 8의 in_queue_after_transaction_commit 옵션 활용)

2. 큐 이름 재정의 및 작업자 구성

  • 지연 시간 허용치 기반 큐: 기존의 우선순위/도메인 기반 큐(예: critical, notifications)의 모호성을 해결하기 위해 within_one_minute, within_one_hour와 같이 지연 시간 허용치(latency tolerance)를 명시한 큐 이름으로 변경했습니다. 이는 개발자와 운영팀에게 명확한 SLO(Service Level Objective)를 제공하고, 큐 지연 시간 모니터링 및 자동 확장의 기준이 됩니다.
  • 전용 작업자: 각 큐에 전용 작업자를 할당하여 리소스 공유 없이 독립적으로 확장할 수 있도록 했습니다. 빠른 큐(within_one_minute)의 경우 서버 부팅 시간으로 인한 SLO 위반을 방지하기 위해 작업자를 선제적으로 과다 할당했습니다.

3. 모니터링 및 마이그레이션 전략

  • 메트릭 수집: Yabeda Gem을 사용하여 Solid Queue 데이터베이스에서 큐 지연 시간(queue latency) 및 작업 수(job count) 메트릭을 수집하고 Prometheus 및 대시보드를 통해 시각화하여 큐의 상태를 실시간으로 모니터링했습니다.
  • 점진적 마이그레이션: ApplicationJob에서 queue_as 메서드를 오버라이드하여 새로운 큐 이름은 Solid Queue를 사용하고, 기존 큐 이름은 Rescue를 사용하도록 설정했습니다. 초기에는 위험도가 낮은 작업부터 Solid Queue로 전환하며 시스템의 안정성을 확보한 후, 점차 고위험 작업을 마이그레이션했습니다.

4. 주요 문제 해결

  • 너무 많은 인자(Arguments): 일부 작업의 인자 길이가 MySQL TEXT 컬럼(65KB) 제한을 초과하여 MEDIUMTEXT 컬럼(16MB)으로 변경했습니다.
  • 메모리 부족: 특정 작업 마이그레이션 후 작업자(worker)가 예기치 않게 종료되는 문제(SIGKILL)는 메모리 부족 때문이었으며, 작업자 메모리를 2GB에서 4GB로 증설하여 해결했습니다.
  • 데이터베이스 연결 부족: 특정 시간에 대량의 작업이 한꺼번에 큐에 등록되면서 작업자 수가 급증하고 데이터베이스 연결이 고갈되는 문제가 발생했습니다. 데이터베이스 규모를 확장하고 작업자 자동 확장 상한선을 설정하여 해결했습니다.
  • 느린 작업 처리: 빠른 큐에 긴 시간이 소요되는 작업이 들어가는 것을 방지하기 위해 around_perform 훅을 사용하여 작업 실행 시간을 모니터링하고, 허용 지연 시간의 10%를 초과할 경우 Sentry로 경고를 보내 해당 작업을 느린 큐로 이동시키거나 최적화하도록 유도했습니다.
  • 지연된 작업(Delayed Jobs) 마이그레이션: Redis에 저장된 수많은 지연된 작업을 Solid Queue로 마이그레이션하기 위해 복잡한 스크립트를 작성하여 처리했습니다.
  • 대량 작업 큐잉 최적화: MySQL이 Redis와 다르다는 점을 인지하고, 대량의 작업을 큐잉할 때 find_in_batchesperform_all_later를 사용하여 SQL INSERT 문 수를 줄이고, 필요에 따라 임의의 대기 시간을 추가하여 작업 부하를 분산시켰습니다.

결론

Full Script는 약 두 달간의 노력 끝에 모든 백그라운드 작업을 Rescue에서 Solid Queue로 성공적으로 마이그레이션했습니다. 이 과정에서 인프라 조정과 문제 해결에 많은 시간이 소요되었으나, 결과적으로 하루 약 3백만 개의 작업을 처리하는 안정적이고 고성능의 시스템을 구축했습니다. 특히, 기존 Rescue에서 발생하던 예측 불가능한 작업 실패가 Solid Queue 전환 후 완전히 사라지면서 시스템의 신뢰성이 크게 향상되었습니다. 큐 이름을 지연 시간 허용치 기반으로 재정의한 것은 개발 및 운영 효율성을 높이는 중요한 변화였으며, Solid Queue의 쉬운 수평 확장성과 뛰어난 관찰 가능성(observability)은 향후 시스템 운영에 큰 이점으로 작용할 것입니다.

댓글 0

댓글 작성

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

아직 댓글이 없습니다

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