티스토리 뷰

시리즈/Ruby

사이드킥

빅또리 2021. 11. 12. 16:17

 

참고하기 : sidekiq wiki 

 

 

Sidekiq runs on 3 components

  • The Rails Application
  • Sidekiq worker process(es) => sidekiq 프로세스가 멀티쓰레드으로 돌면서 background에서 큐에 들은 worker/job 수행
  • Redis  => 큐

Sidekiq handles concurrency by using multiple threads in its process. This way, it can process multiple jobs at once, each thread processing one job at a time. By default, Sidekiq uses 10 threads per process. You can configure it to use more threads, thus increasing concurrency.

 

 

 

sidekiq 실행 콘솔화면. pid = 18634 이다.
ps 명령어로 확인하면 sidekiq 프로세스는 pid 18634로 1개 돌고 있다.

 

* 참고로 [ 0 of 5 busy ] 에서

실행시 concurrency를 5로 주었고, 사이드킥 job lifecycle에 따르면 busy는 currently processing인 상태라고 함.

Job Lifecycle

osx ps 명령어의 -M option
ps -M -p 18634

그런데 이 프로세스의 쓰레드를 확인해보니까 왜 15개나 있는거지?

15개는 native thread이고, concurrency로 명시해준 5개는 user level thread 라서 m:n mapping 으로 도는건가....?

 

 

 

 

 

1. 레디스 서버 켜기

redis-server

2. gem 설치

gem 'sidekiq'
gem 'sidekiq-cron'

3. dashboard 보기

# routes.rb 파일에 추가하기
# localhost:3000/sidekiq에서 대시보드 확인한다

require 'sidekiq/web'
mount Sidekiq::Web => "/sidekiq"

4. config file

1) config/initializers/sidekiq.rb => 레디스 연결

redis_params = {
  url: "redis://localhost:6379",
#   namespace: "sidekiq"     # 이렇게 쓰려면 'redis-namespace' gem이 필요하다
}

# Server config
Sidekiq.configure_server do |config|
    config.redis = redis_params
end
  
# Client config
Sidekiq.configure_client do |config|
    config.redis = redis_params
end

client => 레디스로 엔큐하는 주체들.  The client is anything that pushes jobs to Redis, typically your passenger, puma or unicorn process running Rails or Sinatra.

server => 레디스에서 디큐하는 사이드킥 프로세스. The server is the Sidekiq process which pulls jobs from Redis.

 

a Sidekiq server process can push new jobs to Redis thus acting like a client too!

 

* 레일즈와 사이드킥 프로세스가 서로 다른 서버에서 동작하는 것도 가능한데, 그러려면 이 config에서 레일즈와 사이드킥이 같은 레디스 서버와 연결되어 있도록 해줘야 한다.

stack overflow 질문 : sidekiq remote server setup

 

2) config/sidekiq.yml => sidekiq 실행할때의 command line argument 들을 파일로 저장한 것

예를 들면 이렇게 생겼다.

# :pidfile: ./tmp/pids/sidekiq.pid     # rails6 부터 pid file creation 없어짐. 이거 적어도 효과 없음
:concurrency: 5
staging:
  :concurrency: 10
production:
  :concurrency: 10
:queues:
  - default
  - foo
  - bar

default location에 저장하면 sidekiq 실행할 때 알아서 이 파일 읽어들이지만 그게 아니라면 -C flag로 파일 위치를 명시해줘야 한다.

sidekiq -C config/myapp_sidekiq.yml

-c => concurrency ( 쓰레드 개수 인가? )

-q => 큐 [, weight]

 

기타 option flag

sidekiq -q critical,2 -q default
# ...
:queues:
  - [critical, 2]
  - default

이거 두개가 같은 효과! ( critical 큐 (는 weight 2로), default 큐에 들어있는 worker / job 을 수행한다 )

 

yaml 파일에 적어줬든, sidekiq 실행할 때 cli argument로 줬든 명시한 큐에서만 디큐한다.

다른 큐에는 perform_async 등의 명령어로 엔큐해서 쌓여있어도 사이드킥이 거기있는 작업은 수행 안함. 대시보드에서 확인해봐도 그냥 쌓여있음.

 

 

5. worker / job 생성하기

 

Worker/ Job 클래스 안의 perform 메소드 => 백그라운드에서 비동기로 할 작업 정의

( worker / job 클래스).perform_async() 등의 메소드 호출 => 작업 레디스 큐에 엔큐하기

 

2가지 방식 중 택 1 하면 된다

(1) sidekiq worker 생성 => sidekiq gem에서 제공하는 방식

 

할일 정의

rails g sidekiq:worker BlogPost

app/workers 디렉토리에 생성된다.

class BlogPostWorker
  include Sidekiq::Worker

  sidekiq_options queue: :bar

  def perform(subject, title, article)
    Post.create(subject: subject, title: title, article: article)
  end
end

특별히 큐를 명시하지 않으면 default로 들어감

 

enqueue하기

perform_asyncHardWorker.perform_async('bob', 5)

perform_in HardWorker.perform_in(5.minutes, 'bob', 5)

perform_atHardWorker.perform_at(5.minutes.from_now, 'bob', 5)

 

 

(2) Active Job 생성 => rails의 Active Job의 backend queue를 사이드킥으로 연동해서 사용하는 방식

 

config/application.rb 파일에 이렇게 적어준다

# config/application.rb
module YourApp
  class Application < Rails::Application
    # Be sure to have the adapter's gem in your Gemfile
    # and follow the adapter's specific installation
    # and deployment instructions.
    config.active_job.queue_adapter = :sidekiq
  end
end

이렇게 설정파일에서 따로 queuing backend를 지정해주지 않으면 Active Job은 background에서 비동기로 실행되는게 아니라 그냥 바로 실행되어 버린다. (perform_later 하면 그냥 바로..)

Rails by default comes with an "immediate runner" queuing implementation. That means that each job that has been enqueued will run immediately.

 

할일 정의

rails g job blog_post

# 큐 지정
rails g job blog_post --queue foo

app/jobs 디렉토리에 생성된다

class BlogPostJob < ApplicationJob
  queue_as :default

  def perform(subject, title, article)
    Post.create(subject: subject, title: title, article: article)
  end
end

 

enqueue 하기

perform_later

GuestsCleanupJob.perform_later guest
GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(guest)
GuestsCleanupJob.set(wait: 1.week).perform_later(guest)

 

6. sidekiq 실행

레디스에서 dequeue 해서 작업 수행 한다. 멀티쓰레드로.

 

sidekiq을 실행하지 않고 레일즈 코드 내에서나, 레일즈 콘솔에서 perform_async를 하면 큐에 쌓이기만 하고 아직 작업이 수행되진 않는다. sidekiq 프로세스(=일꾼)를 실행해야 비로소 큐가 비고 정의한 작업이 수행된다.

bundle exec sidekiq

# bundle exec 생략하고 그냥 sidekiq 만 적어줘도 됨

이때 위에서 언급한 command line option들을 줄 수 있다.

sidekiq -q foo

 

댓글
공지사항
최근에 올라온 글