バックアップ中のディスク使用量の急増により、Discourse がクラッシュしました :(

今朝午前5時35分頃、私のフォーラムのディスク使用量が突然急増し、クラッシュして完全にオフラインになりました。Digital Oceanのイメージをリサイズして復旧させる必要がありました。大変でした。

過去24時間のディスク使用量はこちらです:

質問:いったい何が起こったのかを突き止めるために、どのようなログや事後分析を確認すればよいでしょうか?! Discourseのコントロールパネルのログを確認しましたが、手がかりは見当たりません…ログはサイトがクラッシュした時点で終了し、オンラインに戻った直後に再開しているだけです。

「いいね!」 1

まず、どのディレクトリが問題を引き起こしているか特定することから始めましょう。私の標準的なアプローチは、/var/discourse に移動してから du -h -d 1 を実行することです。最も容量の大きいディレクトリに移動し、犯人を特定できるまでこの手順を繰り返します。特定できたら、それが何が起きているのかの手がかりになるかもしれません。

「いいね!」 3

自動バックアップはどうでしょうか?

「いいね!」 3

はい、バックアップはこの種の障害の一般的な原因です。7 日間のウィンドウにおけるディスク使用量はどのようになっていますか?

また、ローカルアップロードもこれらのバックアップに含まれるため、18:00 頃にアップロードが大幅に増加していた場合、バックアップアーカイブのサイズも増大します。

「いいね!」 5

うーん。私は S3 からローカルサーバーへファイルを移行 しているのですが、その処理はオンザフライで実行され、一度に数百枚(1 枚あたり約 300KB)の画像しか処理できません。つまり、1 バッチあたり約 0.1 GB になります。過去 1 週間でスクリプトを約 20 回実行したので、20 バッチで合計約 2 GB のディスク容量を使用しました。十分な空き容量があったはずです。

スクリプトはオンザフライでファイルを移動しているように見えます(S3 からダウンロードして、即座に Digital Ocean にアップロードしているように見えますが)、画像の移動に関連して 5:30 に発動したキューイングされたジョブによる遅延が何らかの原因になっている可能性はありますか?

(また:これらのバッチ処理は 21 時まで手動で実行していたため、サーバーがダウンした 5:30 までの間は、21 時から 5:30 まで通常の操作のみを行っていたはずです。)

以下は 7 日間のディスク使用量です。インポートされた画像により使用量は順調に増加していましたが、5:30 に 100% に達したことがお分かりいただけると思います:

「Logs」タブに表示されているログファイル以外に、5:35 に何が起きたかの手がかりとなるログファイルはありますか?

「いいね!」 1

ふむ。私のバックアップは S3 に 2 日ごとに設定されているはずなのに、9 日以降何も実行されていないのはなぜでしょうか?

Discourse の「バックアップ」ビュー

Amazon S3 のビュー

余談ですが、上記を確認した後、Discourse のボタンをクリックしてバックアップをトリガーしました。28 分ほどかかりましたが、正常に実行されたようです。現在、Discourse と Amazon S3 の両方のバックアップビューにその .tar.gz ファイルが表示されています。では、なぜ自動バックアップがトリガーされないのでしょうか?!うわあああ。

不思議です…どれも特に大きくありませんね:

root@x-app:/var/www/discourse# du -h -d 1

3.5M	./lib
104K	./bin
8.0K	./.tx
148M    ./public
8.0K	./.bundle
14M     ./plugins
4.3M	./db
4.0K	./log
532M	./tmp
8.9M	./spec
17M     ./config
556M	./vendor
8.0K	./images
329M	./.git
2.0M	./script
80K	    ./docs
2.5M	./test
16K	    ./.github
17M	    ./app
1.6G	.

さらに、Docker コンテナ内で全体のディスク容量を見ても、以前ほど大きくはありません。以前は 80 GB の DigitalOcean ドロップレットを使用しており、そこが 100% に達しました。そのため、160 GB にサイズを変更して倍増させました。理論的には、その場合、これらのうちどれかが 50% になるはずです、ね?

root@x-app:/var/www/discourse# df -h

Filesystem      Size  Used Avail Use% Mounted on
overlay         155G   58G   98G  38% /
tmpfs            64M     0   64M   0% /dev
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
shm             512M  2.6M  510M   1% /dev/shm
/dev/vda1       155G   58G   98G  38% /shared
tmpfs           3.9G     0  3.9G   0% /proc/acpi
tmpfs           3.9G     0  3.9G   0% /proc/scsi
tmpfs           3.9G     0  3.9G   0% /sys/firmware

以前は毎晩、ディスク使用率がほぼ 100% に達していましたね。今回の件が最後の押しとなったようです。以前のバックアップは、S3 に送信するためのローカルバックアップファイル作成中にディスク容量不足が発生して失敗したのだと思いますが、単に失敗しただけでフォーラム自体は壊れていませんでした。最終的に、ディスク容量不足が PostgreSQL(あるいは Redis など、実際にはそれほど重要ではありません)を不機嫌にさせ、それがフォーラムをダウンさせるタイミングとちょうど重なったことで、ようやく気づかれました

「いいね!」 7

ああ、あの小さなスパイクは、Discourse がバックアップを作成しようとしているんですね!それで少し見えてきました。

では、ここが私の過去 7 日間のチャートです。

おそらく状況は以下のようだったのでしょう:

  1. 先週の数回、Discourse がバックアップを作成しようとしました。このプロセスは一時的に大量のディスク容量を消費しますが、毎回容量不足で失敗し、バックアップは正常に完了しませんでした。

  2. そして昨夜、再度バックアップを試みた際、もう少し進んだところで、残念ながらサイトがクラッシュしてしまいました。

これは理にかなっています。最後の正常なバックアップが 7 月 9 日だったからです。その後、設定通り 2 日待って 7 月 11 日に再試行しましたが失敗しました。その後 24 時間待って 12 日、13 日、そして 14 日に致命的な再試行を行いました。

もしこれが事実なら、以下の改善を望みます:

  1. バックアップ失敗時に Discourse からより良い通知が届くこと

  2. バックアップ開始時に空き容量が x%(10% 程度?)未満の場合、Discourse が自動的にバックアップを「失敗」させ(通知を作成し)、容量が逼迫している場合は開始しないようにすること。

余談ですが、これが本当に事実なら、7 月 11 日の最初の失敗したバックアップを見ると、空き容量は約 40%(つまり約 32GB!!!)あったはずです。しかし、それでもバックアップの完了には不十分でした。これは正しいでしょうか?!なぜ Discourse はバックアップ作成時に、これほど過剰な一時的な作業領域を必要とするのでしょうか?

「いいね!」 2

昨夜、必ずしも「さらに進んだ」わけではありません。単に「競争に負けた」だけです。容量が不足した際に何が起こるかは、最初に問題の影響を受けるコンポーネントによって異なります。

バックアップの作成に失敗した場合、メッセージの送信を試みるかもしれませんが、ディスク容量が不足している場合は成功しない可能性があります。:scream:

固定された割合だけではあまり参考になりません。データベースがアップロードに比べて非常に小さい場合もあれば、その逆の場合もあります。また、サムネイルやアップロードファイルが含められるかどうかという変数もあります。サイトの設定に合わせて調整できるよう、利用可能な空き容量の要件を構成可能にすることも考えられます。

「不釣り合い」と判断する方法がどうなのかはわかりませんが、私には不釣り合いには思えません。

「いいね!」 2

なるほどですね。ご指摘の通り、関与する変数は多数あります。

ああ、「正しい」方法は、バックアップに必要な容量などを計算することなのでしょうが……。とにかく超シンプルに保つなら、そうですね、単に一定の割合で済ませるしかありません。考えてみると、「サイトが完全にクラッシュしてオフラインになる」か「完璧ではないが即効性のある問題解決策を提示する」かの二択なら、私は後者を選びます。ありがとう。:wink:

ところで感謝の言葉ですが、移行作業やこの件に関するご助言に心から感謝しています。:+1:t2:

「いいね!」 1

バックアップに必要な容量を見積もるのは、コンピュータサイエンスにおける難問の一つです……進行状況バーの遠い親戚のようなものです。:wink:

まじめな話、その一部はデータベースのダンプであり、事前にそれをどのように見積もるかはわかりません。もし画像の数が多くて容量が問題になるなら、それらをバックアップアーカイブに含めるのは、おそらく一般的な慣行の範囲外でしょう。

通常、システム管理においては、空き容量の監視やバックアップの健全性は、アプリケーション側の負担というより、管理上の負担とされてきました。CDCK にDiscourseのホスティングを依頼する際、人々が支払っているのはこの部分の一部です。

容量不足に陥る方法は他にもたくさんあります。あなたが直面した問題に焦点を当てていることは理解できますが、この問題はより一般的であり、通常は管理上のオーバーヘッドとして対処されるべきだと考えます。

「いいね!」 4

この祝祭に水を差すようですが、投稿を読む限り、Discourse のバックアップ処理が問題の原因であるという確実な証拠はありません。

なぜ、この問題が毎日のバックアップ処理によって引き起こされていることを 100% 確認しないのでしょうか?ホストには、毎日実行される複数の crontab ファイルが設定されている可能性があります。

@pnoeric さんは、コンテナの外にある /var/discourse ファイルシステムで du コマンドを実行しましたか?

あなたのメモには、@pnoeric さんが以下のように記述しています。

root@x-app:/var/www/discourse# du -h -d 1

しかし、これではバックアップやアップロードを含む Discourse の共有ディレクトリを見逃してしまっています!さらに、ホスト上のすべての Docker ファイル(およびイメージ)も見逃しています(イメージが時間とともに削除されなければ、これらは膨大なサイズになる可能性があります)。

このチェックを行うべき場所は、コンテナの外(コンテナ内ではありません)です。

例えば(コンテナの外で):

cd /var/discourse 
/var/discourse# du -sh *
4.0K	bin
4.0K	cids
56K	containers
12K	discourse-doctor
24K	discourse-setup
164K	image
24K	launcher
4.0K	LICENSE
12K	README.md
24K	samples
8.0K	scripts
62G	shared
148K	templates

ご覧の通り、このホストでは shared ディレクトリが 62GB です。

また、ファイルシステムの /var からも(コンテナの外で):

cd /var
# du -sh *
511M	cache
20K	composetest
62G	discourse
1.6G	docker
8.0K	legacy
52G	lib
4.0K	local
0	lock
4.0K	locks
5.7G	log
24K	logs
64K	mail
4.0K	opt
4.0K	registry
4.0K	shared
1.9M	spool
48K	tmp
25G	 linux_app
2.2G	www

祝祭に水を差すつもりはありませんが、Discourse に多くの「修正」を提案する前に、Discourse のバックアップ cron が実際の問題であることを 100% 確認することが非常に重要です。

現在の Discourse バックアップ処理では全く問題が発生しておらず、さらに、ホスト上のファイルシステムの管理は Discourse の本来のタスクではありません。

こちら:

du

Filesystem     1K-blocks      Used Available Use% Mounted on
udev            32892500         0  32892500   0% /dev
tmpfs            6584232      2136   6582096   1% /run
/dev/md2       470927632 215969956 230966124  49% /
tmpfs           32921160         0  32921160   0% /dev/shm
tmpfs               5120         0      5120   0% /run/lock
tmpfs           32921160         0  32921160   0% /sys/fs/cgroup
/dev/md0          482922     75082    382906  17% /boot
/dev/sda1         244988      4636    240353   2% /boot/efi
tmpfs            6584232         0   6584232   0% /run/user/1000
overlay        470927632 215969956 230966124  49% /var/lib/docker/overlay2/0f8be368b0154285423630ad50148ee2d5fdcb357c46125eafa7374ca34ef29a/merged
shm               524288      1620    522668   1% /var/lib/docker/containers/ca7b55fc5a0c123f7b2b1234ea210aa8286a34167cba9344b7929547bd323c9b/mounts/shm
overlay        470927632 215969956 230966124  49% /var/lib/docker/overlay2/7cd7e8b5b35b496eaed68753cc995e9303499a24721062055e2f06beb07e26c8/merged
shm                65536         0     65536   0% /var/lib/docker/containers/3cc0c90c3e3a5db6692e7b5d21727fbb1c13c8e07e48e4f6d954214fc03694a9/mounts/shm
overlay        470927632 215969956 230966124  49% /var/lib/docker/overlay2/31533fdf68033eed96dab4f9df89025ea3dab172ed48b6ce6431840a8df1c8ea/merged
shm               524288         0    524288   0% /var/lib/docker/containers/631fbabedda9a430dd8204ec66fb45c7514d948025124171b960ea424e28d5d4/mounts/shm
overlay        470927632 215969956 230966124  49% /var/lib/docker/overlay2/7a3ba2223ee93bc868b52b3707799d0fd7b4ca6dcc0df29f20c2c98a53903ff1/merged
shm                65536         0     65536   0% /var/lib/docker/containers/7a145366268c8ac5543a4555dc1bfc63c1e85a654e4c793e96fc2cc2e8514388/mounts/shm
overlay        470927632 215969956 230966124  49% /var/lib/docker/overlay2/add4bdd7bd88df7a0e05dff21896d3ef796f7cf2ff9759e0bb04b1953f16cd95/merged
shm                65536         0     65536   0% /var/lib/docker/containers/123743e122089b94660a6bdd2a9e55055ad91b6f75cce4ac760f36066bcf14d0/mounts/shm
overlay        470927632 215969956 230966124  49% /var/lib/docker/overlay2/b376ff32eaac0c58463e8b99b6db9ec0da3405c3f7a9f00b5430f10e07d372b0/merged
shm               524288         0    524288   0% /var/lib/docker/containers/63c52bc571b5f0d2544417da10efc37d3957e7a38f44bc8325145e795ee29559/mounts/shm

Docker ファイルを見てみましょう:

# cd /var/lib
# du -sh docker
30G	docker

私たちの Docker イメージは定期的に削除・整理されています。

@bartv さんが正しく提案されたように、まずはここから始めるのが良いでしょう:

どのディレクトリが容量を圧迫しているかを特定することから始めるべきです。私の標準的なアプローチは、/var/discourse に移動し、du -h -d 1 を実行することです。最も大きいディレクトリに入り、その中で同様の操作を繰り返し、疑わしい箇所を見つけます。それがわかれば、何が起きているかのヒントが得られるかもしれません。

これは良い出発点ですが、ホストファイルシステムには Docker やコアファイルなど、ファイルシステムを埋め尽くす可能性のある他の場所も多数あります。

1 日に一度、使用率のスパイクを示すグラフだけでは、Discourse のバックアップ cron プロセスが根本原因であると断言するには不十分です。可能性はありますが、現時点での証拠に基づけば、そうとは限りません。

「いいね!」 6

素晴らしいですね。あなたが挙げたことをすべて試してみます。ありがとうございます。

「いいね!」 1

はい、明らかにバックアップですね。

いいえ、十分な証拠があります。例外が 1 つあるものの、スパイクは 2 日ごとに発生しており、バックアップ頻度も 2 日に設定されています。また、Meta での過去の経験からも、まさにこの故障モードが確認されています。

はい、これは今後進めるための堅実な計画です。VPS でディスク容量の制限に達し始めた人への最初の推奨事項は、S3 メカニズム を用いたマシン外へのアップロード保存です。

「いいね!」 8

@pnoeric さんは画像を S3 から離れようとしているのに、S3 内に保存されたバックアップにすべての画像の複数のコピーを保持することは、S3 から離れるという目的を達成しません。@pnoeric さん、これは私を混乱させています。S3 から離れたいのに、S3 にすべての画像を複数のバックアップコピーで保存しているためにファイルの一部しか移動しないのであれば、その目的は何なのでしょうか?

いずれにせよ、私は代替案がどのようなものかを示そうとしていました。バックアップは困難です。特に、バックアップから復元したい場合などはそうです。

私は十分なサーバー容量があり、急激な成長やトラフィックが「S3」を利用する理由にならないため、デジタルオーシャンのスペース(私の場合は)から「S3」を離れましたが、私は特殊なケースです。そのため、S3 からの移行時のデータ破損を解消する私の PR に対するレビューの言葉が一つも得られなかったのかもしれません。:stuck_out_tongue: そのため、私のバックアップ体制は非常に特殊であると考えています。

「いいね!」 4

私の状況は、画像が大量にあるため、ユーザーがそれらの画像を表示する際に転送帯域幅が大量に消費されることです。そのため、画像が Amazon S3 に保存されていた頃、帯域幅の請求額が本当に致命傷となりました。特に、すべての画像を DO ドロップレットに保存すれば、すでに支払っている帯域幅/ストレージ料金に含まれることに気づいた時です(将来的には、再び S3 に移行することが合理的になるかもしれませんが、あるいは DO ドロップレットをさらに増設する方が合理的になるかもしれません)。

そのため、最初は S3 から始めましたが、その後誤りに気づきました。それが現在の状況であり、あなたの優れたコードを使って、S3 から DO へすべての画像を移行しています。

画像を含む完全なバックアップを S3 に保持することは全く別の話です。S3 の「コールドストレージ」に保存されており、問題が発生しない限りアクセスされません。したがって、帯域幅の請求額も問題になりません。

また、バックアップとディスク使用状況についてさらに考えを深めました。ここには何か見落としがあると感じています。単に警告メッセージやより良いドキュメントが必要なのかもしれません。私の Discourse インスタンスはディスク容量の 60% しか使用していませんでしたが、オフサイトバックアップは失敗していました。必要なディスク容量の見積もりや、容量不足時の警告、あるいは何らかの対策があれば、現在のように容量不足になった際に何日もバックアップが行われず、その結果としてハードクラッシュが発生し、フォーラムが完全にオフラインになってしまう状況よりもはるかに良いはずです。:-\

@riking 氏も「バックアップはこの種の故障の一般的な原因だ」と述べています。つまり、Discourse インスタンスは、潜在的な問題の警告なしにバックアップが失敗する原因で定期的にクラッシュしているのでしょうか?)

非常に簡潔に言い換えるなら、3 万フィートからの眺めで見ると、ソフトウェアの基本機能である自動バックアップがシステム全体をオフラインにしてしまうのは設計上の欠陥のように思えます。特に、バックアップの準備にディスク容量を使用するだけで、同じディスクに保存するわけではない機能の場合です。

「いいね!」 1

いいえ、彼が言いたかったのは、どのサーバー上のどのソフトウェアでもバックアップを取得すると、ディスクがいっぱいになり、問題を引き起こす可能性があるということです。

「いいね!」 3

確かに、しかしそのためにS3の前面にCDNを配置するのです。画像を直接S3から配信するのは、非常に高額になります:scream:。S3の前面にはCloudFrontやCloudFlareを比較的簡単に設定できます。CloudFlareの無料プランでもこれを実現可能です。

また、ローカルに保存することもあまり良くありません。不要にVPSをスケールアップする必要が出てきます。ローカルSSDの方がはるかに高額になります。

「いいね!」 7

ああ、わかりました。

では、Discourse がバックアップの準備をする際に必要なディスク容量をどうやって把握すればよいのでしょうか?ソフトウェアからは何も教えてもらえません。もし明日突然 500 GB 必要になったりしたら、Digital Ocean のサーバーが再びオフラインになってしまうかもしれませんね🤷🏻‍♂️。少なくとも概算計算ができるようになれば、状況を把握しやすくなるでしょう。

おっと、素晴らしいアイデアですね。そんな手があるなんて思いもしませんでした。つまり、Amazon バケットに CDN を適用し、Discourse にはすべてのアセットに S3 を使うように設定するということでしょうか?(以前のように、ですね。笑)

「いいね!」 3