Sidekiqの最適化と監視の基本:速度向上のトレードオフを理解する
Sidekiqの最適化や監視に関するご質問をいただくことがよくあります。監視は私たちの得意分野ですが、Sidekiqのパフォーマンス最適化はまったく別の話です。実際のところ、最適化は複雑なテーマですが、まずは一見シンプルに見える答えから見ていきましょう。
速度を上げる2つの方法
まず、処理速度を上げる方法は大きく分けて2つあります。1つはジョブを大きくする方法(メモリやIOをより多く消費したり、処理が複雑になったりします)、もう1つは同時実行数(concurrency)の設定やワーカー数を調整する方法(CPUをより多く消費し、IOも増加する可能性があります)です。ここで早速現実が立ちはだかります。速度にはコストが伴うのです。追加のメモリ、IO、CPUに余裕があるなら無料で高速化できますが、どのようなトレードオフが必要になるかを意識することが重要だと考えています。
同時実行数の設定で速度を上げる
Sidekiqは、プロセス内で複数のスレッドを使うことで同時実行を実現しています。これにより、複数のジョブを同時に処理でき、各スレッドが一度に1つのジョブを担当します。デフォルトでは、Sidekiqはプロセスあたり10スレッドを使用します。この設定を変更してスレッド数を増やすことで、同時実行性を高めることができます。
なお、新しい同時実行モデルはアプリケーション側でもサポートされている必要があります。たとえば、データベースへの接続プールが十分なサイズであることや、ホストが増加したIO操作に対応できることが求められます。詳細については、Sidekiqの公式ドキュメントにある同時実行に関する項目を参照してください。
複数のワーカーを実行して速度を上げる
複数のプロセスを起動するだけでなく、複数のワーカーを実行するという方法もあります。こうすることで、CPU負荷の高い処理を並列に実行でき、単一プロセス内でCPUを取り合っていた状況を回避できます。Rubyにおける同時実行とGVL(Global Interpreter Lock)については、以前別の記事で詳しく解説しているので、興味があればぜひご覧ください。
改善されたのか、壊れたのか? 監視すべきポイントとマジックダッシュボード
デフォルトのパラメータを変更すると、アプリケーションのパフォーマンスに影響を与える可能性があります。設定を変更する前に、必ず監視体制を整え、その変更が良い影響をもたらすのか、それともパフォーマンスを悪化させるのかを確認できるようにしておきましょう。
まずは、ホストレベルで問題が起きていないかを確認することから始めます。自分のアプリケーションが、稼働しているハードウェアに対してどれほどリソースを消費しているのかを把握しましょう。メモリとCPUに余裕があるのであれば、同時実行数の設定を引き上げて、少しでも処理を速くできます。
どのAPM(Application Performance Monitoring)ツールを使っていても、ホストのメトリクスを追跡する機能は備わっているはずです。AppSignalを使っている場合、ホスト用のダッシュボードは自動的に作成されます。また、異常検知(Anomaly Detection)機能を使えば、特定のホストのCPU使用率に対してアラートを簡単に設定でき、事態が深刻化する前に通知を受け取ることができます。
次に、Sidekiqレベルで問題が起きていないかを確認しましょう。お使いのAPMツールであれば、バックグラウンドジョブの監視とアラートを手動で設定できるはずです。AppSignalでは、この作業が非常に簡単です。最近のバージョンのgemを実行していれば、特別な設定なしにSidekiqのマジックダッシュボードが自動生成され、これらの情報を追跡してくれます。
この環境では、キューごとのジョブステータスを監視し、失敗率にしきい値を設定して、Slack、PagerDuty、メールなど、普段使っているツールにアラートを飛ばすようにしましょう。
ジョブは「少なく・大きく」が正解?
ここまで、CPUを犠牲にして速度を上げる方法を見てきました。次は、メモリやIO、あるいはコードの複雑さを犠牲にする形での高速化を見てみましょう。「大きなジョブを作ればいい」と考えるかもしれません。大きなジョブは、1回ごとのSidekiqのオーバーヘッドがない分、速くなるという発想です。
しかし、私たちの経験では、Sidekiq自体のオーバーヘッドがパフォーマンスを殺すことはほとんどありません。むしろ、ジョブが実行するデータベースクエリこそがボトルネックになりがちです。複数のジョブをまとめて実行し、クエリの発行回数を減らすことは、パフォーマンス向上のための重要な手段であると実感しています。シンプルに言えば、「1レコードずつの更新を1000回行う」よりも「1000レコードを1回の更新でまとめて処理する」方が効率的だということです。
効果の有無を判断するために監視すべきもの
まず、こちらの場合もキューごとのジョブステータスを監視し、失敗率にアラートのトリガーを設定します。さらに、ジョブが長時間化し、処理内容も増えるため、Sidekiqのメモリ使用量も監視対象に加えましょう。AppSignalの異常検知を使えば、Sidekiqのメモリ使用量全般だけでなく、特にホストのメモリ枯渇に対してもアラートを設定できます。
加えて、キューごとのキューの長さ(滞留数)も監視しましょう。ワーカーの処理能力を超えてジョブが溜まり始めたとき——つまりバックログが発生したときに検知できます。「クリティカル」なジョブキューには、異常検知のトリガーを設定しておくことをおすすめします。
APMには映らないトレードオフ
大きなジョブの最大の難点は、コーディングが難しくなることです。個々のジョブを明示的に冪等(べきとう)にし、その状態を管理しなければなりません。簡単な例を挙げると、1人にメールを送るだけのジョブが失敗した場合、害もほとんどなく再試行できます。しかし、1000人にメールを送るジョブが失敗した場合、失敗前にすでに送信済みだった240人に再度メールを送りたくはないでしょう。それを防ぐ仕組みを実装すると、コードは確実に複雑になります。
現実の本当の複雑さ
もう一度、現実の確認をしましょう。多くの場合、バックグラウンド処理が遅い原因は、Sidekiq内で動いているものにはありません。問い合わせているデータベースが、稼働ホストのメモリ不足によって遅くなっているのかもしれません。この記事の題材となる面白い例を探していたとき、私たち自身もまさにそのようなケースに遭遇しました。処理時間が急上昇していた原因は、外部APIのレスポンスタイムが長かったことだったのです。これはSidekiq側ではどうにも解決できません。
問題が一箇所で観測されても、その原因がまったく別の場所にあることは珍しくありません。だからこそAppSignalでは、エラー、パフォーマンス、ホストメトリクスをすべて一元管理できるプロダクトを作っています。これらのメトリクスを組み合わせて見ることで、問題の根本原因を突き止めやすくなります。
簡単な答えなんてない、ということですね
この記事では、Sidekiqの監視と最適化の基礎から始めましたが、すぐに「速度にはCPUとIOのコストがかかる」「あるいはメモリか、コードの複雑さという代償が必要になる」という現実に行き当たりました。アーキテクチャにおけるパフォーマンスの複雑さの一部には触れましたが、正直なところ、本当に難しい部分の99%はこの記事では扱いきれていません。
シンプルな答えへの期待を裏切ってしまったかもしれませんが、皆さんのSidekiq環境の最適化と監視について、何か有益なヒントや考えのきっかけになれば幸いです!
-
iPhoneのRAM・CPU・バッテリー使用状況を確認・監視する方法
iPhoneを長く使っていると、動作が以前より遅くなった、新しいアプリやデータの保存スペースが足りない、バッテリーが数時間しか持たないといった悩みに直面することがあります。そんなときは、主要な3つのコンポーネント(RAM・CPU・バッテリー)の使用状況をチェックしてみましょう。iPhoneのRAM、CPU、バッテリーの使用状況を確認することで、バッテリーが単純に劣化しているのか、それとも機種自体の買い替えが必要なのかを判断できます。また、デバイスを適切にメンテナンスしてパフォーマンスを維持する方法を知ることにも役立ちます。高額な修理や買い替えにかかる費用を節約しながら、自分の用途に合ったパフォ
-
Androidの手動クリーニングは危険?スマホ最適化アプリで安全にストレージを整理する方法
スマホのストレージを手動でクリーンアップしようと考えているなら、あらかじめリスクについて理解しておきましょう。使用期間が長くなるにつれてAndroid端末のストレージは徐々に一杯になっていくため、定期的なクリーニングは欠かせません。しかし、不要なファイルを自分で削除する場合には、いくつか注意すべき点があるのです。 「クリーナーアプリは必要ない、自分で管理すれば十分だ」と考える人も少なくありません。ところが、手動でのクリーニングを続けていると、作業の過程で重要なシステムファイルを誤って削除してしまう可能性が高くなります。そうなると、Android端末の機能や日常的に使っているアプリに深刻な支障を