こんにちは、エンジニアの森田です。 MedPeerでは、バックグラウンドで非同期に処理を実行させる方法としてSidekiqを使っておりましたが、今回Sidekiq Enterprise(Proを含む)を導入しました。
https://sidekiq.org/products/enterprise.html
今回はSidekiq Enterpriseを導入するにあたって解決したかった課題と実際の導入方法、導入後の活用事例をを紹介できればと思います!
Sidekiq Enterpriseとは?
Sidekiq Enterpriseとは、その名の通りエンタープライズ向けの機能拡張が行われた有料版のSidekiqです。(Sidekiq Enterpriseとは別にSidekiq Proもありますが、Sidekiq Enterpriseを導入するとSidekiq Proの機能も使用出来るようになります。)
ProとEnterpriseそれぞれで主に下記のような拡張がされています。
Sidekiq Pro
- RELIABILITY
- BATCHES
Sidekiq Enterprise
- RATE LIMITING
- PERIODIC JOBS
- ENCRYPTION
詳しい機能の紹介は公式のWikiが充実しているので、興味の有る方はそちらをご確認いただくのが良いかとおもいます。
Home · mperham/sidekiq Wiki · GitHub
Sidekiq Enterprise導入に至った背景
MedPeerではバックグラウンドで実行するバッチ処理にSidekiqを使用しています。サービスの成長に伴い日々Jobは増えていて、100を超えるJob(2020/03/19現在)が実行されています。
+----------------------+--------+--------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+--------+--------+---------+---------+-----+-------+ | Jobs | 4482 | 3607 | 106 | 500 | 4 | 5 | +----------------------+--------+--------+---------+---------+-----+-------+
Jobの中には、利用者へのインセンティブ進呈に関わる等、影響が大きいものもありJobにおける処理の信頼性の担保が今まで以上に求められるようになってきました。
またデプロイによるJobへの影響も当時の問題として発生しておりました。 実行完了までに長時間かかるようなJobがあり、デプロイ時のSidekiqのプロセス再起動により実行が中断されるとJobの処理が中断され再実行しても正常に完了できず、毎日運用担当の方からメール配信のスケジュールを共有いただき、エンジニア側でデプロイタイミングがかぶらないように注意するような運用をしていました。。。
このような背景から解決方法を探していたところ弊社技術顧問である前島さんからSidekiq Enterpriseを導入してみてはどうかと提案いただき、導入を検討することとなりました。
結果として上記のような問題は、Sidekiq Enterpriseの導入により解決することが出来ました🎉
Sidekiq Enterpriseの導入方法
ではSidekiq Enterpriseの具体的な導入方法について書いていきます✍
Sidekiq Enterprise申し込み
導入にあたってまずは、Sidekiq Enterpriseの下記のページから申し込みを行います。
https://billing.contribsys.com/sent/new.cgi
金額は100スレッドで月額$179(2020/03/19現在)です。スレッド数が増えていく毎に金額があがっていきます💸
You can use Sidekiq Enterprise with any number of apps and processes and machines as long as their total worker thread count in production is <= the licensed amount. Development and staging environments are free and unlimited. https://github.com/mperham/sidekiq/wiki/Commercial-FAQ
この金額に影響を与えるスレッド数は本番環境で実行されているスレッド数となっているようでstagingやdevelopmentといった本番以外の環境は自由に使うことができます。
申し込みを行うとSidekiq Enterpriseのinstall時の認証に必要なキー情報がメールにて送付されます 📩
Sidekiq Enterpriseのインストール
Sidekiq Enterpriseをアプリケーションに導入する場合は下記のようにGemfileに追記します。
source "https://enterprise.contribsys.com/" do gem 'sidekiq-ent' gem 'sidekiq-pro' end
そして下記のようにbundle config
または環境変数に申込時に受け取った認証用のキー情報を設定します。
export BUNDLE_ENTERPRISE__CONTRIBSYS__COM=foo:bar # or bundle config --local enterprise.contribsys.com foo:bar
上記のGemfileと認証用のキー情報の設定が完了したらbundle installを実行することでSidekiq Enterpriseを導入することができます 🎉
※導入したい機能によっては、initializer/sidekiq.rb
等で起動時に有効化する必要があるものもございますので、Wikiを読んで導入方法を確認することをおすすめします。
ActiveJobからSidekiq::Wokerへ書き換え
Sidekiq Enterpriseの全ての機能を利用するためにはActiveJob
ではなくSidekiq::Woker
を使用する必要があります。そのため弊社ではSidekiq Enterpriseの機能を利用したいJobまたは新規のJobについては、ActiveJob
ではなくSidekiq::Worker
をincludeする形式で実装するようにしています。
# before class MyJob < ApplicationJob queue_as :default def perform(*_args) # something logic end end # after class MyJob include Sidekiq::Worker sidekiq_options queue: :default def perform(*_args) # something logic end end
ActiveJob
を継承したJobをSidekiq::Worker
をincludeする形式に修正するにあたって、引数でActiveRecordのオブジェクトを受けるような形式になっている場合には注意が必要です。
The arguments you pass to perform_async must be composed of simple JSON datatypes: string, integer, float, boolean, null(nil), array and hash. https://github.com/mperham/sidekiq/wiki/Best-Practices#1-make-your-job-parameters-small-and-simple
ActiveJobは良しなに引数のオブジェクトをシリアライズしてくれますが、SidekiqではWikiに記載の通り引数の値をto_sしてRedisにエンキューする都合上、Sidekiq::Worker
をincludeしたときのperform_later
に当たるpeform_async
の引数には単純な値しか渡すことは出来ません。そのため、下記のようにuserではなくuser_idとして取得してUserのオブジェクトを取得するような形で修正が必要となります。
# before class MyJob < ApplicationJob queue_as :default def perform(user:) # something logic end end # after class MyJob include Sidekiq::Worker sidekiq_options queue: :default def perform(user_id:) user = User.find(user_id) # something logic end end
これでSidekiq Enterpriseの機能を使う準備が整いました🎉
Sidekiq Enterpriseの活用事例
最後に弊社におけるSidekiq Enterpriseの活用事例としてReliability
を使ったJob実行の信頼性の向上を紹介いたします。
Reliability
を使ったJob実行の信頼性の向上
Jobにおける処理の信頼性の担保が課題としてあげられていたので、Sidekiq Proの機能であるReliability
を使って信頼性の向上を図っています。
Reliabilityとは、Sidekiq Proの機能である信頼性向上のための機能です。クライアント側(エンキューする側)とサーバー側(デキューして実行する側)に機能が追加されています。
https://github.com/mperham/sidekiq/wiki/Reliability
弊社でも下記の2つを活用しています。
Redisへのenqueueに失敗した場合にメモリ上にenqueueしておいて、接続可能となったタイミングでenqueueできる
Reliability Client
Sidekiqのプロセスが停止した場合にもRedisを総なめして孤立したqueueを実行する
super_fetch
ネットワーク障害等によりRedisに一時的に接続出来ないために失われていたJobや、実行中にSidekiqのプロセスが停止し孤立してしまったJobの実行を担保出来るようになり、信頼性を向上させることが出来ました🎉
Ent Rolling Restarts
を使った安全な再起動
デプロイ時のSidekiqのリスタートによる完了までに長時間掛かるJobの中断を防ぐために、Sidekiq Enterpriseの機能であるEnt Rolling Restarts
を使って安全に再起動しています。
通常のSidekiqのリスタートではTSTP+TERM
を使ったリスタートを行うと思います。通常であればこの方式で安全に再起動出来るのですが、長時間完了までに掛かるJobの中断を防ぐことは出来ません。
Sidekiq EnterpriseのEnt Rolling Restarts
を使うことで、長時間掛かるJobの完了を待って安全に再起動を行うことが出来ます。
There is no limit to the time it can continue running. Upon signalling a rolling restart, a new process will be started to pick up new jobs. https://github.com/mperham/sidekiq/wiki/Ent-Rolling-Restarts
具体的にはRolling Restarts
を検知した際に、下記のような形で再起動が行われます。
- 旧プロセスは新規のJobの実行を停止し、既存のJobの実行が終わったら停止する。
- 新プロセスが起動して新規のJobの実行を開始する。
弊社でも導入の背景に記載したとおり、長時間完了までに掛かるJobがデプロイ時に中断される問題がありましたが、Ent Rolling Restarts
の機能のおかげで現在はデプロイ時にJobの実行有無を確認する必要はなくなりました🎉
おわりに
Sidekiq Enterpriseについて弊社の事例をご紹介しました。もしもSidekiq Enterpriseの導入検討の一助になれば幸いです✨
運用担当とのやりとりやJob実行の信頼性の向上のための内製化コード、なども省けて金額以上のメリットを感じています!
またSidekiq Enterpriseの導入をすすめる中でSidekiqのWikiを読んだのですが、すごく充実した内容になっているので導入に関わらずSidekiqを触っている方は読んで見ると色々と役に立つ内容が多そうでした🙌
それでは👋
メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!
■募集ポジションはこちら
https://medpeer.co.jp/recruit/entry/
■開発環境はこちら
https://medpeer.co.jp/recruit/workplace/development.html