Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

Ruby on Rails 백그라운드 작업 처리, Sidekiq 완벽 활용 가이드

Sidekiq은 시간이 오래 걸리는 작업을 백그라운드로 이관함으로써 Ruby 개발자가 빠르고 반응성 좋은 웹 애플리케이션을 유지할 수 있도록 도와주는 도구입니다.

Sidekiq은 멀티스레딩을 핵심으로 하여 여러 잡(job)을 동시에 처리할 수 있습니다. 덕분에 높은 부하를 감당하거나 이메일 발송, 파일 처리 같은 작업을 수행하는 Ruby 또는 Rails 애플리케이션에서 Sidekiq은 필수적인 요소로 자리 잡았습니다. 백그라운드 처리가 없다면 오래 실행되는 작업이 애플리케이션의 메인 스레드를 차단하게 되고, 그 결과 응답 속도가 느려지고 사용자 경험이 크게 저하됩니다.

이 글에서는 Sidekiq을 효과적으로 활용해 백그라운드 잡을 관리하고 처리하는 방법에 초점을 맞춰 살펴보겠습니다.

그럼 시작해 보겠습니다!

Sidekiq의 기본 개념

핵심만 말하자면, Sidekiq은 Ruby를 위한 풀 기능(full-featured) 백그라운드 처리 프레임워크입니다. 백그라운드 작업을 동시에(concurrently) 실행할 수 있게 해 주며, 이는 반응성과 신뢰성이 중요한 웹 애플리케이션에서 필수적인 능력입니다. 이메일 발송, 이미지 리사이징, CSV 파일 처리 등 시간이 오래 걸리는 작업이라면 무엇이든 Sidekiq을 통해 화면 뒤에서 조용히 처리할 수 있습니다.

Sidekiq의 아키텍처는 멀티스레딩과 '워커(worker)'라는 개념에 크게 의존합니다. 다만 Sidekiq 6.3.0부터는 'worker'라는 용어가 혼란을 줄 수 있다는 이유로 Sidekiq::Worker 모듈이 deprecated되고 Sidekiq::Job 사용이 권장됩니다.

"워커가 프로세스를 의미하는 건가요? 스레드인가요? 아니면 잡의 한 종류인가요? 저는 개발자들에게 worker라는 용어 사용을 중단할 것을 권합니다."

또한 번개처럼 빠른 인메모리 데이터베이스인 Redis가 중요한 역할을 담당합니다. Redis는 이러한 백그라운드 잡들을 저장하는 큐(queue) 시스템으로 동작합니다.

참고: Sidekiq은 저장소로 Redis에 의존하지만, 이 글에서는 Redis의 설정과 사용 방법에 대한 세부 내용은 다루지 않습니다.

Rails에서 Sidekiq 설치 및 설정하기

시작하려면 Ruby 2.5 이상과 Redis 서버 4 이상이 필요합니다.

준비가 되었다면 이제 Sidekiq 젬(gem)을 설치할 차례입니다.

먼저 애플리케이션의 Gemfile에 Sidekiq을 추가합니다:


다음으로 프로젝트 디렉터리에서 설치를 진행합니다:


Sidekiq이 설치되었으면 이제 설정을 해야 합니다. Rails 애플리케이션에서는 Sidekiq을 ActiveJob 어댑터로 지정합니다. config/application.rb 파일을 열고 애플리케이션 클래스 정의 안에 다음 줄을 추가하세요:


추가로 Sidekiq 초기화 파일(initializer)을 만들어 Redis 인스턴스를 가리키도록 설정할 수도 있습니다. 초기화 파일은 Rails에서 애플리케이션이 시작될 때 실행되는 특수한 스크립트입니다.

config/initializers 디렉터리에 sidekiq.rb라는 이름의 파일을 생성하고, 그 안에 다양한 Sidekiq 설정을 지정할 수 있습니다. 예를 들면 다음과 같습니다:


이 설정은 Sidekiq이 로컬 Redis 서버에 연결하도록 지시합니다. 물론 운영(production) 환경에서는 로컬 URL 대신 실제 Redis 서버의 주소로 교체해야 합니다(이럴 때 환경 변수를 활용하기에 아주 좋은 자리입니다).

이것으로 끝입니다! Sidekiq이 설치되고 설정되었으니, 이제 Rails 애플리케이션의 백그라운드에서 잡을 생성하고 처리할 준비가 완료되었습니다.

Sidekiq 잡 설정하기

기본적인 Sidekiq 잡을 설정하고 초기화하는 방법은 다음과 같습니다:


실제로 잡을 큐에 넣어 실행하려면 잡 클래스에서 perform_async 메서드를 호출하면 됩니다:


이 코드는 기본(default) 큐에 잡 하나를 추가하며, 해당 잡은 처리 가능한 순간 즉시 실행됩니다. 인자로 전달된 'some_name'42는 실행 시점에 SomeNameForAJobperform 메서드로 전달됩니다.

이후 Sidekiq 클라이언트가 잡을 Redis의 큐에 push하고, Sidekiq 서버가 처리 준비가 되면 그 잡을 큐에서 pull해 옵니다.

첫 번째 Sidekiq 잡 만들기

Sidekiq에서 잡은 잡 클래스로 표현되며, 수행해야 할 작업은 perform 메서드 안에 정의됩니다. 간단한 Sidekiq 잡을 만들어 보겠습니다:


이 코드 조각에서 우리는 HelloNameJob 클래스를 만들었습니다. 이 클래스는 nametimes 두 개의 인자를 받으며, 실행되면 콘솔에 지정된 횟수만큼 인사말을 출력합니다. 물론 매우 단순한 예제입니다. 실제 애플리케이션에서는 perform 메서드 안에 백그라운드에서 실행하고 싶은 어떤 코드든 담을 수 있습니다.

이제 잡을 실행해 보겠습니다. 클래스에서 perform_async 메서드를 호출하고 perform 메서드가 기대하는 인자들을 넘겨주기만 하면 됩니다. 방금 만든 HelloNameJob을 예약하는 방법은 다음과 같습니다:


이렇게 하면 "Hello, Jeff!"를 다섯 번 출력하는 잡이 큐에 등록됩니다.

특정 시점에 잡을 실행해야 한다면 perform_in 또는 perform_at 메서드를 사용할 수 있습니다. 예를 들면 다음과 같습니다:


첫 번째 예제에서 Meredith는 5분 후에 세 번의 인사를 받게 되고, 두 번째 예제에서 Jeff는 이틀을 기다린 후 두 번의 인사를 받게 됩니다.

Sidekiq 고급 활용법

Sidekiq의 기능은 단순히 작업을 백그라운드로 미루는 것에 그치지 않습니다. 잡 재시도(retry)나 우선순위 설정 같은 잡 구성에 도움이 되는 고급 기능들도 제공합니다.

자동 잡 재시도(Automatic Job Retries)

Sidekiq의 가장 강력한 기능 중 하나가 바로 자동 잡 재시도입니다. 기본적으로 잡이 처리되지 않은 예외(unhandled exception)로 실패하면, Sidekiq은 지수 백오프(exponential backoff) 방식으로 해당 잡을 재시도합니다. 클래스에 sidekiq_options를 지정하여 재시도 횟수를 커스터마이즈할 수 있습니다:


이 예제에서는 잡이 실패했을 때 Sidekiq이 포기하기 전까지 열 번을 재시도합니다.

잡 우선순위(Job Prioritization)

잡 우선순위 지정 역시 Sidekiq이 제공하는 고급 기능입니다. 잡을 서로 다른 큐에 할당하고 각 큐의 우선순위를 설정함으로써 잡의 처리 순서를 제어할 수 있습니다. 잡을 정의할 때 큐를 지정하는 방법은 다음과 같습니다:


이 예제에서 ThisJob의 잡들은 critical 큐에 배치됩니다. Sidekiq 서버를 시작할 때 어떤 큐부터 처리할지 순서를 지정할 수 있습니다.

여기까지 소개한 것이 Sidekiq의 고급 기능을 활용해 백그라운드 잡 처리를 세밀하게 조정하는 몇 가지 사례일 뿐입니다. Sidekiq을 활용하면 잡이 효율적이고 안정적으로, 그리고 애플리케이션의 요구에 가장 잘 맞는 방식으로 처리되도록 보장할 수 있는 도구를 손에 쥔 셈입니다.

Sidekiq 모니터링과 스케일링

Sidekiq에는 잡 처리 능력을 모니터링하고 확장하기 위한 표준 기능들이 기본으로 포함되어 있습니다. 웹 기반 대시보드를 통해 잡 큐를 실시간으로 확인할 수 있으며, 성공/실패한 잡의 개수는 물론 현재 실행 중이거나 예약된 잡에 대한 상세 정보도 볼 수 있습니다.

Sidekiq 대시보드를 사용하려면 Rails의 라우트 파일에 마운트하면 됩니다. config/routes.rb에 다음을 추가하세요:


이 줄들을 추가한 뒤에는 서버의 '/sidekiq' 경로로 접속하여 대시보드를 확인할 수 있습니다.

AppSignal로 Sidekiq 모니터링하기

더 포괄적인 모니터링이 필요하다면 Sidekiq은 AppSignal 같은 APM(Application Performance Monitoring) 도구와 잘 통합됩니다. AppSignal의 Sidekiq 대시보드는 실패하거나 재시도 중인 잡, 잡 소요 시간, Redis 메모리 사용량 등 Sidekiq 잡에 대한 상세한 인사이트를 제공합니다.

Ruby on Rails 백그라운드 작업 처리, Sidekiq 완벽 활용 가이드

이런 정보는 애플리케이션을 확장(scaling)하는 과정에서 병목 지점을 파악하는 데 매우 귀중합니다. 나아가 AppSignal의 알림 기능을 활용하면 큐 길이(queue length) 같은 이상 징후도 놓치지 않고, 큐가 비정상적으로 늘어난 시점을 바로 인지할 수 있습니다.

Ruby on Rails 백그라운드 작업 처리, Sidekiq 완벽 활용 가이드

Rails 환경의 Sidekiq에 AppSignal을 통합하는 것은 아주 간단합니다. AppSignal의 Ruby 젬이 별도 설정 없이 Sidekiq 서버 미들웨어에 자동으로 삽입됩니다. ActiveJob에서도 마찬가지로 동작합니다!

심지어 Rails 없이 동작하는 Sidekiq 애플리케이션에도 문서에 안내된 설정 방식을 따라 AppSignal을 적용할 수 있습니다.

Sidekiq 실전 사용 사례

Sidekiq의 가장 흔한 사용 사례 두 가지는 비동기 이메일 발송과 예약된 리포트 생성입니다. 그중 하나를 좀 더 자세히 살펴보겠습니다.

이메일, 특히 대용량 첨부파일이 붙거나 수신자가 많은 이메일은 발송에 상당한 시간이 걸릴 수 있습니다. 이메일 발송을 백그라운드 잡으로 처리하면, 이메일이 발송되는 동안에도 애플리케이션은 사용자 요청에 계속 응답할 수 있습니다.

다음은 Rails 애플리케이션에서 이메일을 발송하는 간단한 Sidekiq 잡 예제입니다:


이 예제에서 ResetPasswordJobUserMailer 클래스를 사용해 사용자에게 비밀번호 재설정 이메일을 보냅니다. 이메일 발송을 큐에 등록하려면 애플리케이션의 다른 곳에서 ResetPasswordJob.perform_async(user_id)를 호출하면 됩니다.

하지만 일반적인 Rails 애플리케이션에서는 이메일 발송을 위해 별도의 Sidekiq 잡을 만들 필요가 없는 경우가 많습니다. Rails는 이메일 발송용 프레임워크인 Action Mailer를 제공하며, 이는 Active Job과 자연스럽게 통합되어 백그라운드 처리를 지원합니다.

Active Job과 Action Mailer를 함께 사용해 비밀번호 재설정 이메일을 보내는 예제는 다음과 같습니다:


이 예제에서는 메일러 객체에 대해 deliver_later를 호출하면 해당 이메일이 자동으로 백그라운드 잡으로 큐에 등록됩니다. 내부적으로 Active Job은 Sidekiq을 통해 이러한 잡들을 관리합니다.

반면 재시도 동작이나 큐 우선순위 같은 세밀한 제어가 필요하거나, Action Mailer만큼 Active Job과 쉽게 통합되지 않는 작업을 다룰 때는 별도의 Sidekiq 잡을 만드는 것이 적절합니다.

이러한 유연성에 더해 Sidekiq의 뛰어난 성능과 사용 편의성은 Rails 애플리케이션에서 다양한 백그라운드 작업을 처리하는 데 든든한 도구가 되어 줍니다.

마무리

이번 글에서는 Sidekiq을 소개하며 기본 개념을 살펴보고, 설치와 설정 과정을 다룬 뒤, 유용한 잡을 직접 만들고 실행해 보았습니다.

또한 Sidekiq의 고급 기능들도 짚어 보았고, 실제 현업에서 활용되는 사례를 살펴보면서 Ruby 애플리케이션의 성능과 확장성 향상에 Sidekiq이 얼마나 중요한 역할을 하는지 논의했습니다.

이 소개 글에서 얻은 지식을 바탕으로, 이제 여러분도 자신의 Rails 앱에서 Sidekiq을 더욱 효과적으로 활용할 준비가 되었습니다.

즐거운 코딩 되세요!

P.S. Ruby Magic 포스트가 발행되는 즉시 읽고 싶으시다면 Ruby Magic 뉴스레터를 구독하고 어떤 글도 놓치지 마세요!