Redis를 떠나 SolidQueue로 옮기는 이유

1 day ago 6

  • Rails 8은 기본 스택에서 Redis 의존성을 제거하고, SolidQueue·SolidCache·SolidCable을 통해 모든 작업을 관계형 데이터베이스(RDB) 위에서 처리하도록 전환
  • Redis는 빠르고 안정적이지만, 설정·보안·클러스터 관리·백업 등 운영 복잡성을 초래함
  • SolidQueue는 PostgreSQL의 FOR UPDATE SKIP LOCKED 기능을 활용해 경쟁 없는 병렬 작업 처리를 구현
  • 주기적 작업, 동시성 제어, 모니터링 대시보드(Mission Control) 등 Redis+Sidekiq 유료 기능을 무료로 제공
  • 대부분의 Rails 애플리케이션은 SolidQueue로 충분하며, 초고속·실시간 처리가 필요한 일부 경우만 Redis 유지 필요

Redis의 숨은 비용

  • Redis는 단순한 호스팅 비용 외에도 설치·유지보수·보안 구성·HA 클러스터 관리 등 지속적 관리 부담이 존재
    • Rails와 Redis 간 네트워크 연결 및 방화벽 설정, 클라이언트 인증, Sidekiq 프로세스 오케스트레이션 필요
  • 장애 발생 시 Redis와 RDBMS 두 시스템을 동시에 디버깅해야 하며, 이중 백업 전략도 요구됨
  • 반면 Redis 없는 Rails 스택에서는 PostgreSQL 하나만 관리하면 되어 단순화 가능

SolidQueue의 동작 원리

  • PostgreSQL의 FOR UPDATE SKIP LOCKED 기능을 이용해 잠금 충돌(lock contention) 없이 여러 워커가 동시에 작업을 가져감
  • 주요 테이블 구조
    1. solid_queue_jobs: 작업 메타데이터 저장
    2. solid_queue_scheduled_executions: 예약된 작업 대기
    3. solid_queue_ready_executions: 실행 준비된 작업 큐
  • 워커·디스패처·스케줄러·슈퍼바이저 프로세스가 각기 다른 테이블을 주기적으로 폴링하며 협력
  • PostgreSQL의 MVCC 설계와 autovacuum 덕분에 대량의 삽입·삭제 작업도 안정적으로 처리

반복 작업 스케줄링

  • SolidQueue는 cron 스타일의 반복 작업을 기본 제공하며, config/recurring.yml 파일로 설정
  • 스케줄러는 실행 시점이 된 작업을 큐에 넣고, 다음 실행 시점을 자동 예약
  • Fugit 라이브러리로 자연어 스케줄을 파싱하고, Concurrent::ScheduledTask로 스레드를 생성
  • GoodJob의 결정적(deterministic) 스케줄링 방식을 차용해 프로세스 재시작에도 일정 유지

동시성 제어 기능

  • SolidQueue는 POSIX 세마포어 패턴을 사용해 작업 단위별 동시 실행 제한을 지원
    • 예: limits_concurrency to: 1, key: ->(user) { user.id } 설정 시 사용자별 1개 작업만 실행
  • 세마포어 만료(duration)를 지정해 작업 충돌·데드락 방지
  • 관련 테이블
    • solid_queue_semaphores: 동시성 제한 추적
    • solid_queue_blocked_executions: 대기 중인 작업 저장

Mission Control을 통한 모니터링

  • Mission Control Jobs는 Rails 8용 무료 오픈소스 대시보드로, /jobs 경로에 간단히 마운트 가능
  • 주요 기능
    • 실시간 큐 상태, 실패 작업 추적, 재시도/폐기 제어
    • 예약·반복 작업 타임라인 시각화
    • 큐별 처리량 및 메트릭 그래프
  • SQL 기반 조회를 지원해 추가 도구 없이 데이터베이스에서 직접 분석 가능

Sidekiq에서 SolidQueue로의 마이그레이션

  • 1단계: config.active_job.queue_adapter = :solid_queue 설정
  • 2단계: bundle add solid_queue 후 rails solid_queue:install 및 db:migrate 실행
  • 3단계: sidekiq.yml의 cron 스케줄을 recurring.yml로 변환
  • 4단계: Procfile에 jobs: bundle exec rake solid_queue:start 추가
  • 5단계: Redis·Sidekiq 관련 gem 삭제
  • 기존 ActiveJob 코드는 수정 없이 그대로 작동

Redis가 여전히 필요한 경우

  • 초당 수천 건 이상의 지속적 작업 처리
  • 1ms 미만 지연(latency) 이 필수인 실시간 시스템
  • 복잡한 pub/sub 구조 또는 정교한 rate limiting·카운터 연산 필요
  • 예시로 Shopify는 초당 833 요청, 1,172 워커 프로세스를 운영하며 Redis 인프라를 사용

실제 구현 가이드

  • Rails 8 신규 앱 생성 시 SolidQueue·SolidCache·SolidCable 자동 구성
  • config/database.yml에 별도 queue 데이터베이스 연결 설정 권장
  • Mission Control 인증 추가 및 /jobs 라우트 마운트
  • Procfile.dev에 jobs: bundle exec rake solid_queue:start 추가 후 bin/dev 실행으로 전체 구동
  • 테스트 작업 생성 후 Mission Control에서 상태 확인 가능

자주 발생하는 문제와 해결

  • 단일 데이터베이스 구성도 가능하지만, 운영 유연성 저하
  • 프로덕션 환경 Mission Control에는 반드시 인증 추가 필요
  • 폴링 간격 기본값은 예약 1초, 즉시 작업 0.2초로 대부분의 앱에 적합
  • ActionCable/Turbo Streams 사용 시 SolidCable을 별도 DB 연결로 설정해야 함

확장성과 성능

  • SolidQueue는 대부분의 Rails 앱에서 충분히 확장 가능
  • PostgreSQL 기반으로 초당 200~300 작업 처리 가능하며, 37signals는 하루 2천만 작업을 Redis 없이 처리
  • 비교표
    항목 Redis + Sidekiq SolidQueue
    설정 복잡도 별도 서비스 필요 내장 DB 사용
    쿼리 언어 Redis 명령어 SQL
    모니터링 별도 대시보드 Mission Control
    장애 시나리오 6개 이상 2개
    처리량 수천 건/초 200–300건/초
    적합 대상 99.9% 앱 95% 앱

결론

  • Redis와 Sidekiq는 뛰어난 기술이지만, 대부분의 Rails 애플리케이션에는 과도한 복잡성과 비용을 초래
  • SolidQueue는 단일 데이터베이스 기반으로 운영 단순화·비용 절감·유지보수 효율화를 실현
  • Rails 8 시대의 기본 선택지로 SolidQueue 전환이 권장됨

Read Entire Article