復旧支援 - システムが真夜中にハングアップしました

Okay this was bound to happen, things were just too good for too long. Years of running on cruise control, the system would automatically update itself and I would update Discourse every few weeks. At midnight last night, Amazon showed the system was unresponsive, discourse was down and the CPU was pegged at 100% until it ran out of AWS CPU resources. Couldn’t login to the system, the one time after several reboots I was able to login momentarily, I saw this in htoptaking up a lot of CPU

snap lxd activate

If anyone has seen this can can throw some light as to why this may happened by itself, it would be much appreciated for future reference.

Coming the pressing issue at hand, I proceeded to rebuild a new server on AWS using Ubuntu 20LTS, Discourse setup was exceedingly easy. I had a copy of the app.yml file which I used to recreate the discourse forum. The old server was using S3 for the backups AND for the content (images etc).

After creating the server, I downloaded the latest discourse backup file from S3, manually uploaded it to the discourse server and hit the Restore buttons. After a few minutes I get this error.

[2022-06-09 09:01:56] ALTER TABLE
[2022-06-09 09:01:56] ALTER TABLE
[2022-06-09 09:01:56] Migrating the database...
[2022-06-09 09:02:11] == 20220308201942 CreateUploadReferences: migrating ===========================
-- create_table(:upload_references, {})
   -> 0.0486s
-- add_index(:upload_references, [:upload_id, :target_type, :target_id], {:unique=>true, :name=>"index_upload_references_on_upload_and_target"})
   -> 0.0030s
== 20220308201942 CreateUploadReferences: migrated (0.0580s) ==================

== 20220309132719 CopyPostUploadsToUploadReferences: migrating ================
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT post_uploads.upload_id, 'Post', post_uploads.post_id, uploads.created_at, uploads.updated_at\nFROM post_uploads\nJOIN uploads ON uploads.id = post_uploads.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0595s
== 20220309132719 CopyPostUploadsToUploadReferences: migrated (0.0602s) =======

== 20220309132720 CopyPostUploadsToUploadReferencesForSync: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT upload_id, 'Post', post_id, NOW(), NOW()\nFROM post_uploads\nON CONFLICT DO NOTHING\n")
   -> 0.0076s
== 20220309132720 CopyPostUploadsToUploadReferencesForSync: migrated (0.0080s) 

== 20220330160747 CopySiteSettingsUploadsToUploadReferences: migrating ========
-- execute("WITH site_settings_uploads AS (\n  SELECT id, unnest(string_to_array(value, '|'))::integer upload_id\n  FROM site_settings\n  WHERE data_type = 17\n  UNION\n  SELECT id, value::integer\n  FROM site_settings\n  WHERE data_type = 18 AND value != ''\n)\nINSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT site_settings_uploads.upload_id, 'SiteSetting', site_settings_uploads.id, uploads.created_at, uploads.updated_at\nFROM site_settings_uploads\nJOIN uploads ON uploads.id = site_settings_uploads.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0034s
== 20220330160747 CopySiteSettingsUploadsToUploadReferences: migrated (0.0038s) 

== 20220330160751 CopyBadgesUploadsToUploadReferences: migrating ==============
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT badges.image_upload_id, 'Badge', badges.id, uploads.created_at, uploads.updated_at\nFROM badges\nJOIN uploads ON uploads.id = badges.image_upload_id\nWHERE badges.image_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0006s
== 20220330160751 CopyBadgesUploadsToUploadReferences: migrated (0.0010s) =====

== 20220330160754 CopyGroupsUploadsToUploadReferences: migrating ==============
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT groups.flair_upload_id, 'Group', groups.id, uploads.created_at, uploads.updated_at\nFROM groups\nJOIN uploads ON uploads.id = groups.flair_upload_id\nWHERE groups.flair_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0050s
== 20220330160754 CopyGroupsUploadsToUploadReferences: migrated (0.0055s) =====

== 20220330160757 CopyUserExportsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_exports.upload_id, 'UserExport', user_exports.id, uploads.created_at, uploads.updated_at\nFROM user_exports\nJOIN uploads ON uploads.id = user_exports.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0013s
== 20220330160757 CopyUserExportsUploadsToUploadReferences: migrated (0.0041s) 

== 20220330164740 CopyThemeFieldsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT theme_fields.upload_id, 'ThemeField', theme_fields.id, uploads.created_at, uploads.updated_at\nFROM theme_fields\nJOIN uploads ON uploads.id = theme_fields.upload_id\nWHERE type_id = 2\nON CONFLICT DO NOTHING\n")
   -> 0.0006s
== 20220330164740 CopyThemeFieldsUploadsToUploadReferences: migrated (0.0010s) 

== 20220404195635 CopyCategoriesUploadsToUploadReferences: migrating ==========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT categories.uploaded_logo_id, 'Category', categories.id, uploads.created_at, uploads.updated_at\nFROM categories\nJOIN uploads ON uploads.id = categories.uploaded_logo_id\nWHERE categories.uploaded_logo_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0095s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT categories.uploaded_background_id, 'Category', categories.id, uploads.created_at, uploads.updated_at\nFROM categories\nJOIN uploads ON uploads.id = categories.uploaded_background_id\nWHERE categories.uploaded_background_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0004s
== 20220404195635 CopyCategoriesUploadsToUploadReferences: migrated (0.0103s) =

== 20220404201949 CopyCustomEmojisUploadsToUploadReferences: migrating ========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT custom_emojis.upload_id, 'CustomEmoji', custom_emojis.id, uploads.created_at, uploads.updated_at\nFROM custom_emojis\nJOIN uploads ON uploads.id = custom_emojis.upload_id\nWHERE custom_emojis.upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0032s
== 20220404201949 CopyCustomEmojisUploadsToUploadReferences: migrated (0.0036s) 

== 20220404203356 CopyUserProfilesUploadsToUploadReferences: migrating ========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_profiles.profile_background_upload_id, 'UserProfile', user_profiles.user_id, uploads.created_at, uploads.updated_at\nFROM user_profiles\nJOIN uploads ON uploads.id = user_profiles.profile_background_upload_id\nWHERE user_profiles.profile_background_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0017s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_profiles.card_background_upload_id, 'UserProfile', user_profiles.user_id, uploads.created_at, uploads.updated_at\nFROM user_profiles\nJOIN uploads ON uploads.id = user_profiles.card_background_upload_id\nWHERE user_profiles.card_background_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0011s
== 20220404203356 CopyUserProfilesUploadsToUploadReferences: migrated (0.0033s) 

== 20220404204439 CopyUserAvatarsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_avatars.custom_upload_id, 'UserAvatar', user_avatars.id, uploads.created_at, uploads.updated_at\nFROM user_avatars\nJOIN uploads ON uploads.id = user_avatars.custom_upload_id\nWHERE user_avatars.custom_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0200s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_avatars.gravatar_upload_id, 'UserAvatar', user_avatars.id, uploads.created_at, uploads.updated_at\nFROM user_avatars\nJOIN uploads ON uploads.id = user_avatars.gravatar_upload_id\nWHERE user_avatars.gravatar_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0069s
== 20220404204439 CopyUserAvatarsUploadsToUploadReferences: migrated (0.0276s) 

== 20220404212716 CopyThemeSettingsUploadsToUploadReferences: migrating =======
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT theme_settings.value::int, 'ThemeSetting', theme_settings.id, uploads.created_at, uploads.updated_at\nFROM theme_settings\nJOIN uploads ON uploads.id = theme_settings.value::int\nWHERE data_type = 6 AND theme_settings.value IS NOT NULL AND theme_settings.value != ''\nON CONFLICT DO NOTHING\n")
   -> 0.0025s
== 20220404212716 CopyThemeSettingsUploadsToUploadReferences: migrated (0.0030s) 

== 20220526203356 CopyUserUploadsToUploadReferences: migrating ================
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT users.uploaded_avatar_id, 'User', users.id, uploads.created_at, uploads.updated_at\nFROM users\nJOIN uploads ON uploads.id = users.uploaded_avatar_id\nWHERE users.uploaded_avatar_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0227s
== 20220526203356 CopyUserUploadsToUploadReferences: migrated (0.0234s) =======


[2022-06-09 09:02:11] Reconnecting to the database...
[2022-06-09 09:02:12] Reloading site settings...
[2022-06-09 09:02:12] Disabling outgoing emails for non-staff users...
[2022-06-09 09:02:14] Disabling readonly mode...
[2022-06-09 09:02:14] Clearing category cache...
[2022-06-09 09:02:14] Reloading translations...
[2022-06-09 09:02:14] Remapping uploads...
[2022-06-09 09:02:14] Restoring uploads, this may take a while...
[2022-06-09 09:03:05] EXCEPTION: 509 of 1823 uploads are not migrated to S3. S3 migration failed for db 'default'.
[2022-06-09 09:03:05] /var/www/discourse/lib/file_store/to_s3_migration.rb:132:in `raise_or_log'
/var/www/discourse/lib/file_store/to_s3_migration.rb:79:in `migration_successful?'
/var/www/discourse/lib/file_store/to_s3_migration.rb:373:in `migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:66:in `migrate'
/var/www/discourse/lib/file_store/s3_store.rb:328:in `copy_from'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:62:in `restore_uploads'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:44:in `restore'
/var/www/discourse/lib/backup_restore/restorer.rb:61:in `run'
/var/www/discourse/script/spawn_backup_restore.rb:23:in `restore'
/var/www/discourse/script/spawn_backup_restore.rb:36:in `block in <main>'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `fork'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `<main>'

Can anyone advise on what’s the problem and how I can restore the server from the Amazon S3 server backups?

こんにちは。
app.yml から新しいサーバーを再作成した後、https://your.domain/admin/backups セクションでバックアップにアクセスできましたか?

いいえ、app.yml から再作成した後、何も入っていないクリーンな新しいセットアップが提供されただけでした。S3 から最後のバックアップをダウンロードし、ローカルの Discourse に手動でアップロードして、復元を実行しました。

復元を開始すると、すべての設定(S3、設定ページからのすべての認証情報を含む)が戻り、すべてのカテゴリが表示され、投稿が表示され、すべてが表示されます。その後、数分後にログアウトメッセージが表示され、すべてのカテゴリとトピックが消え、ログにそのエラーが表示されます(ロールバックするようです)。

:thinking: S3の設定はapp.yml(こちらで説明されているように Configure an S3 compatible object storage provider for uploads )にはなく、Set up file and image uploads to S3 のように設定されているということですか?

「いいね!」 1

いいえ、アプリのymlには表示されません。

すべてのS3設定は、管理者 → 設定ページで定義されており、サーバーが昨夜ダウンして復元する必要があるまで、1年間正常に動作していました。

はい、S3のバックアップとアップロードを設定するために使用したのはこれです。

アプリの app.yml を設定で編集してから、管理セクションにバックアップが表示され、そこから復元できるはずです。手動でのインポートやアップロードなしで、それらはバックアップに含まれているはずですが、なぜ失敗しているのかはわかりません。

「いいね!」 1

バックアップにS3とローカルアップロードが混在していることが原因である可能性があります。これは私の専門分野ではないのですが、このトピックで、失敗を回避するための議論と回避策があります。ただし、これははるかに少ないエラー数に対するものでしたので、それを考慮に入れる必要があるかもしれません。

「いいね!」 2

残念ながら、私のサイトはクラッシュしてしまいました。そのため、S3へのアップロードとバックアップしか残っていません。残りのローカルファイルをS3に移行する方法はないと仮定しています。

そこで、現在の選択肢についてお伺いします。S3のバックアップから復元し、ローカルファイルを無視する方法はありますか?S3へのアップロードを無視する方法を見つけましたが、その場合、ほとんどすべての投稿でリンク/画像が壊れています(S3へのアップロードをセットアップしてから何年も経っているため、90%以上がS3にあると思われます)。

同じ問題で苦労している方のためにアップデート情報をお伝えします(基本的に、バックアップからの復元ができず、システムアップグレードの不具合でサーバーがクラッシュしました)。

問題の根本原因は、ローカルアップロードとS3アップロードの両方があるため、復元ツールがローカルとS3の復元を同時に処理する方法がわからずバグが発生しているようです(Discourseはバックアップ/復元を見直す時期かもしれません)。

@RGJさんからのヒントに感謝します。彼は、復元中にDiscourseにS3アップロードを無視させることを提案しました。

  1. app.ymlDISCOURSE_ENABLE_S3_UPLOADS=false という行を追加します。
  2. Discourseを再構築します ./launcher rebuild app
  3. 復元を試みます(GUIのバックアップページから、またはCLIを使用)。
  4. 復元後、app.ymlからその行を削除し、もう一度再構築します。

これは機能しましたが、注意点として、フォーラムはひどく壊れていました。カテゴリ、設定、投稿は復元されましたが、すべての画像、リンク、埋め込みドキュメントなどは壊れてエラーになりました。

最後の手段:
古いサーバーを救出し、/var/discourseディレクトリを(tar/gzで)抽出し、新しいサーバーにコピーして./launcher rebuild appを実行しました。これによりフォーラムの運用は完全に復元されましたが、根本的な問題は残っています。ローカルとS3のアップロードが混在しているため、バックアップは機能しません。

この問題を根本的に解決するための最善の方法について、ぜひアドバイスをいただきたいです。すべてのアップロードをローカルからS3へ、またはS3からローカルへ移動する方が良い/簡単でしょうか?また、その方法は?バックアップの目的はこのような状況を助けることですが、今回は役に立たなかったので、きちんと修正する必要があります。

「いいね!」 1

Object Storage for Uploads (S3 & Clones) の使用 に記載されているように設定すると、

 rake uploads:migrate_to_s3

を実行できるようになります。s3 の使用を停止したい場合は、rails コンソールに入り、

  SiteSetting.include_s3_uploads_in_backups=true

を設定します。その後、バックアップを取得し、app.yml で s3 が設定されていないことを確認して、バックアップを復元します。これにより、バックアップがローカルに復元されるはずです。

ただし、どちらの場合も、app.yml ファイルの ENV 変数にキーとバックアップバケットを設定し、新しいサイトに復元できることを確認することを推奨します。

「いいね!」 2

少し混乱しているようです。

理想的なのは、すべてのアップロードをローカルで行い、バックアップ(zip)をS3に保存することだと思います。これにより、サーバーに何かあった場合にバックアップがS3で利用可能になりますが、バックアップ自体は依存関係のない自己完結型なので、新しいサーバーに簡単に復元できるはずです。

もし私の理解が正しければ、これらの指示に従うべきです。

S3の使用を停止したい場合は、railsコンソールに入り、以下のように設定します。

  SiteSetting.include_s3_uploads_in_backups=true
その後バックアップを取り、app.ymlにS3が設定されていないことを確認し、バックアップを復元します。これにより、バックアップがローカルに復元されると思います。

そして

  1. 管理 -\u003e 設定 -\u003e ファイル で S3へのアップロードを有効にする オプションを無効にする
  2. 管理 -\u003e 設定 -\u003e バックアップ ページでS3へのバックアップを有効にする

これで正しいですか?

ここが混乱した点です。なぜapp.ymlファイルにS3の設定を入れたいのですか?

これにより、バックアップを復元する前にコマンドラインからバックアップにアクセスできます。そうしないと、管理者アカウントを設定してから S3 を設定し、その後復元する必要があります。同様に、データベースに設定した設定は、データベースを復元すると上書きされます。

ベストプラクティスは、app.yml ファイルの ENV 変数のみを使用して S3 を設定することだと思います。数百人が表示されなくなったことに驚くことを除けば、それらを非表示設定にすることが理にかなっているでしょう。

「いいね!」 1

そうしないと、復元が困難になるためです。

「いいね!」 2

コマンドラインからS3のバックアップを復元するにはどうすればよいですか? こちらの指示によると:Restore a backup from the command line
バックアップファイルを /var/discourse/shared/standalone/backups/default フォルダにドロップし、その後CLIから復元を開始できると記載されています。これは以前、あなたの提案で行ったこと(残念ながらリンク切れの原因となった)ですが、それは機能します。

CLIから直接S3を復元するにはどうすればよいですか?

cd /var/discourse
./launcher enter app
discourse restore

利用可能なバックアップが表示されるので、復元したいものをコピー/ペーストしてください。

「いいね!」 2

ありがとうございます。S3バックアップを読み込み、オプションとして一覧表示するということですね。

Jayさん、アセットをローカルに移動するというご提案について、フォローアップです。

非表示設定 include_s3_uploads_in_backups を true に設定し、S3をオフにしてからバックアップと復元を行うことで、S3の使用を停止できると思います。

S3バックアップを app.yml で設定すると、コマンドラインで復元する際に app.yml ファイルのみで可能になります(DiscourseをクローンしてDockerをインストールした後)。

最初のステップとして、S3バケットをバックアップする必要がありますか、それともこれはバケットに安全な操作ですか?

まあ、少なくとも昨夜サーバーがクラッシュした理由(そして完全な再構築後にも再びクラッシュした理由です:frowning:、詳細は次のトピックを参照してください: https://meta.discourse.org/t/ubuntu-20-04-kernel-update-with-docker-causing-a-crash/229526)がわかりました。

「いいね!」 2

バックアップから起動するには、以下の手順を実行する必要がありました。

  1. 設定 → ファイルS3アップロードを有効にする を無効にする
  2. 設定 → バックアップバックアップ場所S3
  3. 設定 → バックアップアップロード付きバックアップ を有効にする

その後、バックアップを取得し、正常に復元することができました。しかし、一つ問題が発生しました。すべての添付ファイル(ファイル)が無効なリンクになりました。画像はすべて正常ですが、添付ファイルのリンク(例:https://domain.com/uploads/short-url/phu1HOLvkE8LWpkKYfnMPSWsvHh.zip)は現在エラーが発生します。

おっと!そのページは存在しないか、プライベートです。

これらの短縮URLリンクを修正する方法はありますか?

それらのトピックのいずれかでHTML再構築(別名リベイク)を試して、それが修正されるかどうかを確認してみてください。

ありがとうございます。特定のトピックをベイクするコマンドの発行方法に関するガイドはどこかにありますか?