お世話になっております。
MisskeyHQ 情報システム管理部です。
この度は、11月下旬~1月5日まで続いたMisskey.ioの連合の処理に関する不具合について、詳細をご報告いたします。
まず、この度の連合(ActivityPub)の障害について深くお詫び申し上げます。
長期にわたる不具合により、ユーザーの皆様と連合先のFediverseの皆様に大変ご迷惑をおかけしました。
現在把握されている範囲では、Misskeyでタスクのスケジューリング・並列処理に使用されている「BullMQ」の状態変更の処理の構造的な欠陥に起因する問題だと認識しております。
Misskeyの仕組み上、ユーザーの皆様の行った投稿・リアクションなどはユーザー様のフォロワー様のご利用のサーバーに配送されるよう、その対象のサーバーごとに一つ一つのジョブとしてジョブキューに登録されることになります。Misskeyではそのジョブキューシステムとして「BullMQ」を採用しており、そのデータの保存先としてRedisを採用していますが、Misskey.ioではパフォーマンスの関係上、オリジナルのRedisではなくKeyDBやDragonflyDBというRedisの代替サーバーシステムで運用しております。
この度の不具合は、内部的には大きく二つの症状が発生しておりました。
- ジョブデータの保存先であるKeyDB・DragonflyDBが応答無しになる問題
- BullMQにて、ジョブの「処理中」リストが一定以上膨れ上がるとジョブの処理の状態を更新できなくなる問題
最近の問題は主に『ジョブの「処理中」リストが一定以上に増加すると、ジョブの処理状態が更新できなくなる』というもので、これが連合への配送の大幅な遅延を引き起こしていました。
この期間中に連合への配送が遅延していた約5000万件のアクティビティについては、問題の原因が特定された後、現行のシステムとは別で配送専用のサーバーを稼働し、毎秒2000件のペースで送信を行い、1月7日の15時時点で全ての送信を完了しました。
今回の不具合に関する、時系列順での対応履歴です。
- 問題:クラウドプロバイダのネットワーク障害により、プロキシを介してKeyDBに接続した際に不定期にKeyDBのサーバーが応答無しになる問題を確認。
その後、ネットワーク障害が解消されたにも関わらず、プロキシを介さず直接KeyDBに接続しても問題が継続しました。
- 対応:コネクションの再利用に関する変更を実施しましたが、改善は見られませんでした。
- 対応:応答無しとなる状況を定期的に検出し、サーバーを再起動するスクリプトを実装しました。
- 対応:試しに11月28日に実施した変更をRevertしてみましたが、状況は特に改善されませんでした。
- 対応:ジョブキューの保存先をキューごとに指定できるようMisskeyを改修しました。
これにより、inbox、deliver、その他のキューを別々のサーバーで運用することになりました。
その他のキューを担当するKeyDBサーバーでは応答無しの問題がほぼ解消され、Misskeyの内部処理に支障をきたすことはなくなりました。
しかし、inboxとdeliverを担当するサーバーは依然として不定期に応答無しの状態に陥り、このたびも検出スクリプトが再起動を行う必要がありました。
- 対応:ジョブキューのデータ流失を最小限に抑えるため、以前は1つだったジョブキューのデータサーバーを3つに増設しました。
この増設により、KeyDBのメインサーバー、メモリ上でデータを保持するサーバー、そしてディスクにデータを書き込むサーバーという構造を採用しました。
これにより、メインサーバーが再起動された際にも、ディスクやメモリ上のサーバーから最新のデータを取得できるようになりました。
- 問題:Misskeyのログから、ジョブキューの処理中、同一ジョブが複数回処理されないようにする「ジョブのLock処理」が正常に機能していないことが判明しました。
この結果、処理を完了したジョブが完了状態に遷移せず、Active 状態のままになる問題が発生していることが確認されました
- 問題:新年の「あけおめ」のタイミングでジョブキューのデータが急激に増加しました。
その結果、三重構成のシステムではデータ同期の遅延が発生し、KeyDBが書き込み不可の状態に陥ることが確認されました。
- 対応:KeyDBのメインサーバーとメモリ上のデータを保持するサーバー間の相互同期設定を変更し、データが一方向にのみ流れるようにしました。
これにより、書き込み不可の状態を防ぐことができました。
- 対応:BullMQの「ジョブのLock処理」に要する時間が長かったため、デフォルトの「ジョブのLock時間」を延長してみましたが、問題の改善には至りませんでした。
- 対応:inboxとdeliverキューの保存先のサーバーをKeyDBからDragonflyDBに変更しました。
しかし、この変更にもかかわらず、同様の問題が引き続き発生しました。
- 対応:BullMQを最新バージョンにアップデートし、MisskeyでBullMQやRedisサーバーに関するより詳細な設定が可能になるような改修を行いました。
さまざまな設定を試みましたが、問題の改善には至りませんでした。
- BullMQの使用を中止し、RabbitMQやKafkaなど、他のメッセージキューソリューションの導入を検討し始めました。これらの代替ソリューションの実装作業にも着手しました。
- 原因の特定:KOBA789(https://misskey.io/@koba789)さんも調査に参加いただき、BullMQのジョブキュー処理後に「active」ジョブリストから完了したジョブを削除する操作に多大な時間がかかることが問題の原因であることが明らかになりました。
この実装の欠陥により、「active」リストが一定以上に膨れ上がると、ジョブの処理状態を更新することができなくなっていました。
- 対策:「active」リストの肥大化を防ぐため、BullMQのConcurrencyの値を1 Podあたり256~512件からさらに絞り込み、オートスケーラーの設定も見直しました。
また、管理を容易にするため、Redisサーバーと同様にQueueのPodもCommon, Inbox, Deliverに分けました。
- 対応:連合への配送が遅延していた約5000万件のアクティビティに対し、新たに稼働した配送専用のサーバーを使用して、毎秒2000件のペースで送信を開始しました。
- 対策:万一「active」リストが肥大化する事態に備えて、その状況が長く続かないよう、一定周期でリストを監視する仕組みを導入しました。
- 解消:1月7日の15時時点で、連合への配送が遅延していたアクティビティの配送がすべて完了したことを確認しました。
この度の障害を受け、Misskey.ioのシステムの安定性と耐障害性を向上させるため、以下の対策を講じます。
1. システム監視の強化:これまで以上にシステムの監視体制を強化し、問題が発生した際の早期発見・対応を可能にします。
具体的には、リアルタイムのシステムモニタリングの充実と、自動化された警告システムの導入を計画しています。
2. より柔軟に対応できるキューシステムへの移行:BullMQとRedisベースの現行システムの代わりに、新たなメッセージキューシステムを導入する計画です。
最後に、ご不便をおかけした皆様に心よりお詫び申し上げます。
今後ともMisskey.ioをよろしくお願い申し上げます。
以上、報告となります。不明点やご質問がございましたら、お気軽に下記の連絡先までお問い合わせください。
メールアドレス: support@misskey.io
サポートページ: https://support.misskey.io/
皆様のご意見やご質問を心よりお待ちしております。