selmertsxの素振り日記

ひたすら日々の素振り内容を書き続けるだけの日記

Sidekiqのjobの信頼性向上方法と Sidekiq Proの検討について

自分のための覚書

TL;DR

  • sidekiq proでは、server processが死んでも jobの復活がサポートされる
  • sidekiq proにおいて、redis が死んでも、1000件程度のジョブならclientが保持し続けて、redisが復活したタイミングでenqueue してくれる
  • ↑の状況において、client processが死ねば、蓄積された1000件のジョブは全て消える
  • sidekiq enterpriseでは、unique な jobになるように諸々やってくれるが、完全に保証してくれるものでは無いので、そこんところを考えたjob設計にすること。

Pricing

  • Pro
    • $9,500 / yr
  • Enterprise
    • 250 thread $19,500 / yr
    • 500 thread $23,400 / yr

Jobが失われないようにする仕組みについて

sidekiqにおいてjobが失われるケースは下記の3点

  • redisに接続できないケース
  • client processが死んだケース
  • server processが死んだケース

この中でSidekiq Proが対策をしているのは redisに接続できないserver processが死んだ の2つのケース。

redisに接続できない場合

基本的に、下記の資料に書いてある内容。 https://github.com/mperham/sidekiq/wiki/Pro-Reliability-Client

通常版だと、redisが死んでいたらjobがpush出来ない。しかしPro版だとpushできなかったjobをclientのプロセスが保持しており、特定のjobがpushできるようになったタイミングで残っているjobも一緒にpushしてしまう。なお、client が保持できるjobの数は最新の1000件のみ。1000件を越えた場合は、永遠に失われてしまうので、そこは気をつけること。

server processが死んだ場合

  • sidekiq basicは、Redis queueからのjobのフェッチにBRPOPを使っている
  • sidekiqがjobを実行している最中にクラッシュしたら、そのjobは永遠に失われてしまう
  • jobが失われない様に保証するための唯一の方法は、jobが完了するまでredisから削除しないこと
  • sidekiq proはRedisのPROPLPUSH コマンドを利用してそれを実現している
  • BROPLPUSH を使う場合は下記のように記述する必要がある
Sidekiq::Client.reliable_push! unless Rails.env.test?

Sidekiq.configure_server do |config|
  config.super_fetch!
  config.reliable_scheduler!
end

なお、super_fetchをする際は、redisデータベースの全走査を行うので、cache dataとjob dataで保持するredisを分けるのが望ましい。

JobのUnique制約について

大前提として jobは (class, 引数, queue)を組み合わせてuniqueであることが求められる。同じ引数のjobを異なるqueueに入れることができる。そのため、同一引数のjobで違う結果を期待してはいけない。基本的に unique な制約は時間に掛けることになる。

class MyWorker
  include Sidekiq::Worker
  sidekiq_options unique_for: 10.minutes

  def perform(...)
  end
end

上記のような設定をした場合、jobが成功するか、jobが失敗して10分が経過するまで同一引数のjobを実行することは出来ない。