使用Rails进行异步处理:使用队列。Sidekiq(+ActiveJob)比Resque更加简单方便

我认为在发送电子邮件,执行繁重的处理或批处理等过程中,使用队列非常常见。在Ruby中,有几个库可以轻松实现这些操作。其中比较有名的有Sidekiq、Resque和Delayed Job等。我曾经使用过Sidekiq和Resque这两个库……最近我发现Sidekiq的配置更简单且易于使用,因此我会总结一下与Sidekiq相关的设置和其他内容。

有关ActiveJob

从Rails4.2版本开始,引入了一个名为ActiveJob的队列操作框架。通过使用它,可以统一写法,无论是使用Sidekiq还是Resque这样的后台队列库,都可以自由地书写。如果正在使用Rails4.2,可以积极采用它,效果很不错。

(2017/08/07:追記)我在实际的一些项目中尝试过使用ActiveJob,但是现在我感觉直接使用Sidekiq比使用ActiveJob更有优势。这是因为ActiveJob进行了抽象化处理,所以无法使用Sidekiq的选项。而且,如果要切换队列库,需要进行相应的更改,所以我觉得或许不使用ActiveJob也可以。

$ ./bin/rails g job guests_cleanup
      invoke  test_unit
      create    test/jobs/hoge_job_test.rb
      create  app/jobs/hoge_job.rb

工作脚本是一种常见的写作方式呢。

class HogeJob < ActiveJob::Base
  queue_as :default

  def perform(*args)
    # Do something later
  end
end

队列的执行几乎完全相同。

> HogeJob.perform_later("hoge")
> HogeJob.set(wait: 1.week).perform_later(record) # 1週間後

由于支持回调功能和ActionMailer异常处理,使得它非常易于使用。

    とても分かりやすい公式ドキュメント http://railsguides.jp/active_job_basics.html

Resque和Sidekiq的大致比较

庶务

    • Redis使う

 

    • ジョブごとにフォークされてメモリ初期化されるからスッキリ

でも大量にジョブを処理するとフォークオーバヘッドが…

リトライ処理ができない
デーモン起動が面倒
ダッシュボードがある(質素)

Sidekiq 可以被重述为:Sidekiq

    • Redis使う

 

    • マルチスレッド(Pumaっぽい)

軽くて大量に処理しまくりたい場合に向いているかも
長時間動かしているとコードによってはプロセスメモリ肥大化するかも

リトライ処理ができる
デーモン起動が簡単
ダッシュボードがある(おしゃれ)

延迟的工作

    使ってないからわからぬが、Redisではなく専用にテーブルを作成して使う

首先,完成Redis的安装等

Resque和Sidekiq都使用Redis来存储队列。

$ sudo yum install -y redis
$ sudo service redis start

安装和配置Sidekiq

在浏览仪表盘上,需要使用Sinatra。

gem 'sidekiq'
gem 'sinatra', require: false
gem 'redis-namespace'
$ bundle install

进行Sidekiq的Redis配置。

Sidekiq.configure_server do |config|
  case Rails.env
    when 'production' then
      config.redis = { url: 'redis://prd.redis-example.com:6379', namespace: 'sidekiq' }
    when 'staging' then
      config.redis = { url: 'redis://stg.redis-example.com:6379', namespace: 'sidekiq' }
    else
      config.redis = { url: 'redis://127.0.0.1:6379', namespace: 'sidekiq' }
  end
end

Sidekiq.configure_client do |config|
  case Rails.env
    when 'production' then
      config.redis = { url: 'redis://prd.redis-example.com:6379', namespace: 'sidekiq' }
    when 'staging' then
      config.redis = { url: 'redis://stg.redis-example.com:6379', namespace: 'sidekiq' }
    else
      config.redis = { url: 'redis://127.0.0.1:6379', namespace: 'sidekiq' }
  end
end

生成Sidekiq的工作脚本。

$ rails g sidekiq:worker Sample
class Sample
  include Sidekiq::Worker

  def perform(data)
    Rails.logger.debug(data)
  end
end

启动工作进程。

$ bundle exec sidekiq

只需通过RailsConsole注册队列,就应该自动执行。

$ rails c
> Sample.perform_async('hoge')

在中国,除了常见的Sample.perform_async(‘hoge’)任务队列外,还有许多其他选择。

Sample.perform_in(3.hours, 'hoge', 1) # 3時間後に実行する
Sample.perform_at(3.hours.from_now, 'hoge', 1) # こちらも3時間後に実行する

Sidekiq 的仪表盘

用一个相对时尚的仪表板,很容易阅读。图表的绘制令人高兴。

require 'sidekiq/web'
mount Sidekiq::Web => '/sidekiq'
スクリーンショット 2015-05-12 9.12.33.png

Sidekiq的部署

使用Sidekiq作为守护进程,通过Capistrano进行部署非常简单。只需添加名为capistrano-sidekiq的Gem。

group :development, :test do
  gem 'capistrano-sidekiq', github: 'seuros/capistrano-sidekiq' # 追加
end
set :rails_env, "production"
set :unicorn_rack_env, "production"
set :pty, false # これをセットしないと、デプロイ時にSidekiqがデーモン起動しない…

role :app, %w{vagrant@192.168.33.40}
role :web, %w{vagrant@192.168.33.40}
role :db,  %w{vagrant@192.168.33.40}

server '192.168.33.40', user: 'vagrant', roles: %w{web app}

set :ssh_options, {
  keys: %w(/home/vagrant/.ssh/id_rsa),
  forward_agent: false,
  auth_methods: %w(publickey)
}
require 'capistrano/sidekiq' # 追加
$ bundle exec cap production deploy

部署已完成。

如果要将Web服务器和批处理服务器分开的话。

如果想要将Sidekiq的守护进程与批处理服务器分离开来,可以设置:sidekiq_role。这样,192.168.33.40将成为Rails的Web服务器,而192.168.33.41将成为仅运行Sidekiq的批处理服务器。Sidekiq本身可以并行运行多个实例,所以如果队列很大或者任务很重,我认为最好通过扩展batch角色来进行横向扩展。

# 追加
set :sidekiq_role, :batch
role :batch,  %w{vagrant@192.168.33.41}
server '192.168.33.41', user: 'vagrant', roles: %w{batch}

启动/停止/重新启动Sidekiq

如果不想部署,但想操作Sidekiq进程,有一些选项可用,比如启动、停止、重启等选项。方便。

$ bundle exec cap production sidekiq:start

在monit上进行Sidekiq进程管理和监控。

无论是使用Sidekiq还是Resque,它们都是被守护进程化的进程,我们无法确定它们什么时候会终止,因此我们希望能够定期重新启动进程作为粗略的内存泄漏对策。因此,我们需要进行进程管理和监控。我个人比较喜欢monit的简洁性,所以我会安装并配置monit。

$ sudo yum install -y monit
$ sudo chkconfig monit on
set httpd port 2812 and
  allow localhost
$ sudo service monit start
require 'capistrano/sidekiq/monit' # 追加

然后,一旦部署完成,系统会自动生成并自动传输monit的配置文件。默认情况下,它会尝试将配置文件放置在/etc/monit/conf.d/hoge_production.conf,所以请确保将适当的权限设置给部署用户。

$ sudo monit status

通过这个,您可以查看进程的状态。

Resque的安装和配置

暫時保留Resque的安裝和設定代碼。

gem 'resque', :require => 'resque/server'
$ bundle install
case Rails.env
  when 'production' then
    Resque.redis = 'prd.redis-example.com'
  when 'staging' then
    Resque.redis = 'stg-example.com'
  else
    Resque.redis = '127.0.0.1'
end
Resque.redis.namespace = "resque:prj-name:#{Rails.env}"
class Sample
  @queue = :default

  def self.perform(data)
    Rails.logger.debug(data)
  end
end
require 'resque/tasks'
$ QUEUE=* ./bin/rake environment resque:work
$ rails c
> Resque.enqueue(Sample, "hoge")

Resque仪表板

mount Resque::Server, :at => "/resque"
スクリーンショット 2015-05-12 8.47.30.png
广告
将在 10 秒后关闭
bannerAds