使用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'
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"