大量の未読ユーザー通知による大規模キューで発生するSidekiqの非常に遅い問題

Sidekiq で問題が発生しています。

Sidekiq Web UI で監視している間は、ジョブが驚くほど高速に処理されます。しかし、時折、処理が追いつかなくなり、極端に遅くなってしまうことがあります。通常の速度の 1〜5% 程度まで落ち込み、サーバーリソースの使用率が正常/低いにもかかわらず、Redis をフラッシュしない限り回復しません。

キューがある一定のサイズに達すると、システムが停止して劇的に遅くなるように見えます。これによりキューがさらに膨らんでしまいます。これは私の推測に過ぎませんが、もしかすると何らかの別の理由で処理が遅くなり、その結果キューが肥大化しているのかもしれません。

この GIF が私の状況を表しています。

サーバーリソースは十分にあります。CPU 使用率は現在 10% 未満と非常に低いです。メモリや SSD も十分にあります。サーバーは 16 コア(32 スレッド)を搭載しています。8〜14 個の unicorn_sidekiq を実行しようとしましたが、20 個にすると 5xx エラーが多数発生しました。

Sidekiq Web UI の「busy」タブに表示されている遅延ジョブを高速化することができました。

(/etc/sysctl.conf ファイルに ‘vm.overcommit_memory = 1’ を追加して再起動)また、unicon_sidekiq の数を 12 から 8 に減らしました。

それでもまだ遅いままです。昨日の Redis ログに以下が表示されていました(それ以外の警告は、overcommit_memory が 1 に設定されていないことに関するもので、上記で修正済みです):

# WARNING: /proc/sys/net/core/somaxconn is set to the lower value of 128

^ 上記の警告を解決した方はいますか?

ともかく、原因や解決策についてご存知の方がいれば、ぜひ教えてください。感謝します。

フラッシュするのではなく、この問題が二度と発生しないように根本的に解決したいと考えています。

Sidekiq ダッシュボードで確認している画面のスクリーンショットです:

また、「busy」タブのジョブに関するスクリーンショットもいくつかあります:

さらに、Sidekiq Web UI から低優先度キューを削除するのは安全かどうかご存知の方はいらっしゃいますか?

更新:優先度の低いキューに問題なく削除できましたが、ジョブの処理速度は変わらずです。

ジョブの実行時間に係る指標はありますか?PostAlert ジョブには大きな競合があるように見えますが、他のジョブは迅速に完了しています。

サイドキックの Web UI で観測した限りでは、おっしゃる通りです。他のジョブは迅速に完了しているようですが、例外として以下が挙げられます:

Jobs::PostAlert - 0〜3 分(大部分は 0〜1 分の範囲内)。
Jobs::ProcessPost - 0〜21 秒。

SMTP サーバーの動作が遅いですか?

Amazon SES を送信に使用しており、VERP 受信用のメール受信設定も完了しています。

SES に表示されている送信制限は 25 通/秒です。これは遅すぎるでしょうか?おそらく制限の引き上げを依頼できると思います。

おっしゃる通り、この問題が顕在化したのは、通常よりも多くのダイジェストメールが送信された日でした(過去の設定不備により、多くのダイジェストメールが 1 日にまとめて送信されることになったためです)。

何人のユーザーにメールを送信していますか?メールの送信量はどうなっていますか?

何人のユーザーにメールが送信されるか確信が持てません。管理ダッシュボードの過去30日間のアクティブユーザー数は60.8kですが、これが指標になるかもしれません。SESからの送信統計(24時間あたりの制限10万件以上)は以下の通りです:

更新:SES の秒間送信レート制限が 25 から 50 に引き上げられました。これにより、1 時間に最大 18 万件のメールを送信できるようになりました(ただし、1 日あたりの送信上限は 10 万件強です)。ただし、Sidekiq のジョブ処理速度は向上したようではありません。

数年前、ユーザーが1万件の未読通知を持っていることで、通知クエリが遅くなり、その結果、PostAlertジョブも遅くなるという問題が発生しました。

再発防止策を講じましたが、あなたの環境では異なるパフォーマンス特性が現れる可能性があります。

通知数の確認を怠るカテゴリ監視設定をしているユーザーはいませんか?

データベース内で、ユーザーあたりの最大未読通知数を確認できますか?

そこで、優先度の低いキューを再度クリアし、数日間放置しました(前回の更新以降の変更はありません)。即座に速度が向上したわけではありませんでしたし、キューイングされたジョブが急速に積み上がっていましたが、時間を置くことで自己修復されたようです。現在、ジョブの処理は非常に高速に進んでいます。:slight_smile: 20 秒のポーリング間隔で運用しており、過去数分間は 1 秒あたり 55〜140 件のジョブを処理しています。1 日あたりの状況も健全で、キューの蓄積は見られません。

@Falco @supermathie @Stephen の皆様に多大なるご支援をいただき、誠にありがとうございます。大変感謝しております!

ご質問いただいた件については、確認方法が確信が持てません。もしまだ参考になるようであれば、確認(多少のガイダンスが必要ですが)を行い、情報を提供することも喜んで行います。関連する可能性のある点として、長らく「ユーザーあたりの 1 日最大メール数」の設定を 3 に設定していました。

早合点したかもしれません。Sidekiq のジョブは現在、約 1〜3 件/秒で実行されており、キューには 881 万件が溜まっています。

:philosoraptor:

最後にアップデートしたのはいつですか?数日前に PostAlert ジョブにパフォーマンスの改善を追加しました:

非常に大規模なサイトの一部では、「最初の投稿をウォッチする」ユーザーが多いカテゴリでパフォーマンスの問題が発生していました。このコミットにより、当社のホスティング環境では問題が解決しました。そのため、貴サイトにも効果がある可能性があります。

素晴らしい!今すぐ更新します。前回の更新は約10日前です(テスト合格)。改善があるか監視し、その後報告します。ありがとう!

更新:残念ながら、更新直後は速度の即時改善は見られませんでした。時間が経つにつれて改善するか確認します。

更新:まだ低速で、キューが蓄積しています。‘top’ で多くの postmaster プロセスが確認できます。CPU 使用率は全体で約 85%(32 コア)で、その大部分が postmaster によるものです。これは興味深い点です。なぜなら、今日早些方は CPU 使用率は 20〜35% でした(その時点でも sidekiq はまだ低速で動作していました)。関連記事: Primary Postgres database process (postmaster) eating all CPU - #5 by pfaffman

これらの Redis の警告が関係している可能性がありますか?これらはアプリの再ビルド中に表示されます。

# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

# WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

Docker インストールでこれらのエラーを解決した方はいますか?

すでに /etc/sysctl.conf に vm.overcommit_memory = 1 を追加して、メモリ過剰割り当ての警告を解決しました。

Transparent Huge Pages (THP) の警告は、root で echo never > /sys/kernel/mm/transparent_hugepage/enabled を実行することで解消しました。永続化のために rc.local に追加する予定はありますが、まだテスト段階です。Discourse を再構築しましたが、パフォーマンスはほぼ同じです。わずかに改善したかもしれません。

ただし、この警告の解決方法については確信が持てません:
# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

このガイドのようにシステム値を高く設定しても、Docker は値 128 を使い続けるという話をいくつか見かけます:Performance tips for Redis Cache Server – Tech and Me

低優先度キューに特定の UNICORN_SIDEKIQS を割り当てるのが良いアイデアかもしれないと考えています。

デフォルトの優先度タスク(例えば PostAlert)は比較的遅く処理されており、これらの低速なデフォルト優先度タスクが蓄積されると、はるかに高速に完了可能なタスクを含む低優先度キューが膨れ上がってしまいます。実際、低優先度キューのタスクはほとんど完了していないように見えます。この膨れ上がりが、すべてのタスクのキュー処理全体を遅くしているのではないかと疑っています。これが、1 秒あたりのジョブ数の大きな変動の原因かもしれないと思います。

app.yml ファイル(または他の方法)で、UNICORN_SIDEKIQS を特定の優先度タスクに割り当てられるかどうかご存知の方はいらっしゃいますか?

データベースがボトルネックになっている状態で Sidekiq を追加しても、状況はさらに悪化するだけです。

前述の通り、PostgreSQL のパフォーマンス低下の問題をデバッグする必要があります。