Heroku Postgres データベースのバージョンのアップグレード
この記事の英語版に更新があります。ご覧の翻訳には含まれていない変更点があるかもしれません。
Last updated 14 January 2021
Table of Contents
この記事では、Heroku Postgres データベースのメジャー PostgreSQL バージョンをアップグレードする方法について説明します。Heroku でサポートされている最新のメジャー PostgreSQL バージョンは 12 です。
データベースのマイナーバージョンをアップグレードする場合や、Postgres プランまたは基礎となるインフラストラクチャのみを変更する場合は、「Changing the Plan or Infrastructure of a Heroku Postgres Database」(Heroku Postgres データベースのプランまたはインフラストラクチャの変更) を参照してください。
メジャー PostgreSQL バージョンのアップグレードは、Heroku CLI 経由でのみ実行できます。これは、慎重に実行する必要のある重大な操作です。
Heroku では、アップグレードのための 2 つの方法がサポートされています。どちらの方法でも、アップグレード中のデータ損失を防ぐために、ある程度のアプリケーションのダウンタイムが必要です。
アップグレード方法 | 説明 |
---|---|
pg:upgrade | Hobby 層プランを除くすべての Heroku Postgres プランで動作します。 次の場合を除き、この方法をお勧めします。
約 10 分のダウンタイムが必要ですが、これは変動する場合があります。 |
pg:copy |
すべての Heroku Postgres プラン (Hobby 層プランを含む) で動作しますが、サイズが 10 GB 未満のデータベースでのみ動作します。
GB あたり約 3 分のダウンタイムが必要ですが、これは大きく変動する場合があります。 |
データのチェックサム
Postgres 9.3 では、データ破損の早期検出のためにデータのチェックサムが導入されました。最初に 9.3 より前のバージョンの PostgreSQL で Heroku Postgres データベースをプロビジョニングした場合は、チェックサムが有効になっていない可能性があります。
データベースでチェックサムが有効になっているかどうかは、heroku pg:psql
で次のクエリを実行することによって確認できます。
=> SELECT setting = 'on' AS enabled FROM pg_settings WHERE name = 'data_checksums';
enabled
---------
t
(1 row)
データベースで現在チェックサムが有効になっておらず、pg:copy のアップグレードに必要となるダウンタイムがアプリで許容可能な場合は、アップグレードの一部としてチェックサムが確実に有効になるように pg:copy
のアップグレード方法を使用します。
データベースの肥大化
データベースに多数の “肥大化” (使用されなくなった行によって占有される余分な領域) があり、pg:copy のアップグレードに必要となるダウンタイムがアプリで許容可能な場合は、すべてのテーブルとインデックスを最初から再作成するために pg:copy
のアップグレード方法を使用します。それを行うことにより、データベースからすべての肥大化が削除され、ディスク領域が節約されます。
ダウンタイムが主な考慮事項である場合は、代わりに pg:upgrade
を使用します。
pg:upgrade でのアップグレード
pg:upgrade
コマンドは、PostgreSQL の pg_upgrade ユーティリティを使用して PostgreSQL バージョンをその場でアップグレードします。このコマンドは、フォロワーデータベースのアップグレードにのみ使用できます。このデータベースは同じプランのままになりますが、現在のリーダーのフォローは停止します。
PostgreSQL バージョンおよびプランの両方をアップグレードする必要がある場合は、別のプランで新しいフォロワーをプロビジョニングし、切り替えプロセスの一部として pg:upgrade
を実行できます。
pg:upgrade
コマンドは、適度な量の関係とスキーマが含まれているデータベースを対象にしています。 データベースに数千のスキーマが含まれている場合は、postgres@heroku.com に問い合わせてください。
データベースをバージョン 9.6、10、11、12 にアップグレードできます。pg:upgrade
で使用するバージョンは、--version
フラグ (--version 11
など) で指定できます。--version
フラグが設定されていない場合は、デフォルトで 12 にアップグレードされます。
pg:upgrade
を実行するには、約10 分間のアプリのダウンタイムが必要になります。この方法は、Hobby 層プランを除くすべての Heroku Postgres プランでサポートされています。
1. フォロワーデータベースをプロビジョニングする
開始するには、データベースの新しいフォロワーを作成し、そのフォロワーがリーダーデータベースに追いつくまで待ちます。次の例では、standard-2
プランが使用されていますが、ニーズに最適なプランをプロビジョニングする必要があります。
$ heroku addons:create heroku-postgresql:standard-2 --follow HEROKU_POSTGRESQL_LAVENDER_URL --app sushi
Adding heroku-postgresql:standard-2 to sushi... done, v71 ($200/mo)
Attached as HEROKU_POSTGRESQL_WHITE
Follower will become available for read-only queries when up-to-date
Use `heroku pg:wait` to track status
$ heroku pg:wait
Waiting for database HEROKU_POSTGRESQL_WHITE_URL... available
フォロワーは一般に、プライマリデータベースまで 200 コミット以内のときに “追いついた” と見なされます。フォロワーが遅れているコミット数は、pg:info
コマンドを使用して確認できます (フォロワーデータベースの Behind By
行を参照)。
$ heroku pg:info --app sushi
=== HEROKU_POSTGRESQL_LAVENDER
Plan: Standard 0
Status: available
...
=== HEROKU_POSTGRESQL_WHITE
Plan: Standard 2
Status: available
...
Following: HEROKU_POSTGRESQL_LAVENDER (DATABASE_URL)
Behind By: 125 commits
2. データベースの書き込みを防止するためにメンテナンスモードにする
アップグレードプロセス中に、新しいデータは新しいデータベースに転送されないため、現在のプライマリデータベースに新しいデータが書き込まれないようにすることが重要です。これを行うには、アプリをメンテナンスモードにします。スケジューラージョブが実行されている場合は、これを無効にしてください。
メンテナンスモードでは、dyno が自動的にはスケールダウンされません。どの接続もデータベースにデータを書き込んでいないようにするために、Web dyno や Web 以外の dyno をスケールダウンする必要があります (heroku ps:scale worker=0
など)。
アップグレードプロセスのこの時点で、アプリケーションは起動できなくなります。
$ heroku maintenance:on
Enabling maintenance mode for sushi... done
3. フォロワーデータベースをアップグレードする
メンテナンスモードになり、プライマリデータベースに追加データが書き込まれていない状態になったので、フォロワーデータベースをアップグレードできます。
フォロワーデータベースがプライマリに完全に追いつくまで待ちます (0 commits
遅れていることで示される)。
$ heroku pg:info
=== HEROKU_POSTGRESQL_LAVENDER_URL
Plan: Standard 0
Status: available
...
=== HEROKU_POSTGRESQL_WHITE_URL
Plan: Standard 2
Status: available
...
Following: HEROKU_POSTGRESQL_LAVENDER_URL (DATABASE_URL)
Behind By: 0 commits
フォロワーが追いつくまで待たないと、次のエラーメッセージが表示されることがあります。
▸ database must not be too far behind leader, please wait until your follower catches up with its leader.
フォロワーが追いついたら、pg:upgrade
コマンドを使用して、フォロワーの PostgreSQL バージョンをその場で更新します。アップグレードにより、フォロワーはプライマリデータベースのフォロー解除も行います。この手順は通常、完了するまでに約 5 分かかります。
$ heroku pg:upgrade HEROKU_POSTGRESQL_WHITE --app sushi
pg:wait
を使用して、アップグレードの進捗状況を監視できます。
$ heroku pg:wait --app sushi
pg:upgrade
プロセスの一部として、Heroku Postgres はデータベースに対して ANALYZE
を実行します。これにより、データベースの統計が再計算され、バージョンアップグレードの後も Postgres クエリプランナーに確実に最新情報が保持されるようになります。
5.0 より前のバージョンの Rails には、Postgres 10 以上との既知の互換性の問題があります。Rails のバージョンをアップグレードし、Rails の問題で推奨されるモンキーパッチを使用するか、または pg:upgrade
を実行して 9.6 にしてください。
4. 新しいデータベースをプロモートする
新しくアップグレードされたデータベースをプロモートして、アプリケーションによって使用されるプライマリデータベース (DATABASE_URL
) として設定します。
$ heroku pg:promote HEROKU_POSTGRESQL_WHITE
Promoting HEROKU_POSTGRESQL_WHITE_URL to DATABASE_URL... done
これで、フォロワーデータベースがプライマリデータベースになりました (ただし、アプリケーションはまだ新しいリクエストを受信していない)。
元のプライマリデータベースが複数のアプリにアタッチされていた場合は、heroku addons:attach
を使用して新しいデータベースをこれらのアプリにアタッチする必要があります。
プロモーションの後、元のプライマリデータベースのフォロワーは、新しいプライマリのフォローを自動的に開始するようにはなりません。
必要に応じて、新しいプライマリデータベースの新しいフォロワーを作成してください。
$ heroku addons:create heroku-postgresql:standard-0 --follow DATABASE_URL -a sushi
古いフォロワーが必要なくなったら、必ずプロビジョニング解除してください。
5. メンテナンスモードを終了する
通常のアプリケーション操作を再開するには、Web 以外のすべての dyno をその元のレベルにスケーリングします (heroku ps:scale worker=1
など)。
最後に、メンテナンスモードをオフにします。
$ heroku maintenance:off
アプリケーションが、更新されたデータベースインスタンスへのリクエストを受信するようになりました。これは、heroku pg:info
を実行することによって確認できます。DATABASE_URL
で示されるデータベースはプライマリデータベースと見なされます。
Heroku Postgres データベースが Heroku アプリケーションに接続されていない場合は、HEROKU_POSTGRESQL_WHITE_URL
を取得し、それをプライマリデータベースとして使用するようにアプリケーションを更新する必要があります。
pg:copy でのアップグレード
pg:copy
のアップグレード方法では、PostgreSQL のネイティブなバックアップと復元ユーティリティを使用します。データベースバックアップをディスクに書き込む代わりに、バックアップデータを新しくプロビジョニングされたデータベースの復元プロセスに直接ストリーミングします。
pg:copy
の方法では、現在のデータベースの GB あたり約 3 分のアプリのダウンタイムが必要ですが、これはスキーマやデータベースプランによって大きく異なる場合があります。必要なダウンタイムは、ドライランを実行することによって見積もることができます (新しいデータベース上で、そのときはプロモートせずにアップグレードプロセスを実行する)。
pg:copy
の方法では、サポートされているすべての Heroku Postgres プランおよびバージョン間でのアップグレードがサポートされます。これは、Hobby 層プランをサポートする唯一のアップグレード方法です。pg:copy
では、デフォルトの資格情報と、それでアクセスできるデータのみがコピーされます。その他の資格情報と、それでしかアクセスできないデータはコピーされません。
1. 新しいデータベースをプロビジョニングする
目的のプランの新しい Heroku Postgres データベースをプロビジョニングします (次の例では、standard-0
プランが使用されていますが、ニーズに最適なプランをプロビジョニングする必要がある)。
$ heroku addons:create heroku-postgresql:standard-0
Adding heroku-postgresql:standard-0 on sushi... done, v122 ($50/mo)
The database should be available in 3-5 minutes
データベースを、サポートされている最新バージョン以外のバージョンの PostgreSQL にアップグレードする場合は、--version
フラグ (--version 9.6
など) で使用するバージョンを指定してください。
Standard、Premium、Private、Shield 層は、プロビジョニングするまでに数分かかります。pg:wait
コマンドを使用すると、プロビジョニングがいつ完了したかの通知を受け取ることができます。
$ heroku pg:wait
Waiting for database HEROKU_POSTGRESQL_PINK_URL... available
2. データベースの書き込みを防止するためにメンテナンスモードにする
アップグレードプロセス中に、新しいデータは新しいデータベースに転送されないため、現在のプライマリデータベースに新しいデータが書き込まれないようにすることが重要です。これを行うには、アプリをメンテナンスモードにします。スケジューラージョブが実行されている場合は、これを無効にしてください。
メンテナンスモードでは、dyno が自動的にはスケールダウンされません。どの接続もデータベースにデータを書き込んでいないようにするために、Web dyno や Web 以外の dyno をスケールダウンする必要があります (heroku ps:scale worker=0
など)。
アップグレードプロセスのこの時点で、アプリケーションは起動できなくなります。
$ heroku maintenance:on
Enabling maintenance mode for sushi... done
3. データを新しいデータベースに転送する
データを現在のデータベースから新しくプロビジョニングされたデータベースにコピーするには、新しいデータベースの HEROKU_POSTGRESQL_COLOR
名を指定して pg:copy
コマンドを使用します。
この例では、DATABASE_URL
が転送するデータのソースであり、HEROKU_POSTGRESQL_PINK
がターゲットデータベースです。
$ heroku pg:copy DATABASE_URL HEROKU_POSTGRESQL_PINK --app sushi
! WARNING: Destructive Action
! Transfering data from DATABASE_URL to HEROKU_POSTGRESQL_PINK
! This command will affect the app: sushi
! To proceed, type "sushi" or re-run this command with --confirm sushi
> sushi
4. 新しいデータベースをプロモートする
この時点で、新しいデータベースは元のデータベースからデータが入力されていますが、まだアプリケーションのアクティブなデータベースになっていません。新しいアップグレードされたデータベースをアプリケーションのプライマリデータベースにするには、次のようにプロモートします。
$ heroku pg:promote HEROKU_POSTGRESQL_PINK
Promoting HEROKU_POSTGRESQL_PINK_URL to DATABASE_URL... done
これで、アップグレードされたデータベースがプライマリデータベースになりました (ただし、アプリケーションはまだ新しいリクエストを受信していない)。
元のプライマリデータベースが複数のアプリにアタッチされていた場合は、heroku addons:attach
を使用して新しいデータベースをこれらのアプリにアタッチする必要があります。
プロモーションの後、元のプライマリデータベースのフォロワーは、新しいプライマリのフォローを自動的に開始するようにはなりません。
必要に応じて、新しいプライマリデータベースの新しいフォロワーを作成してください。
$ heroku addons:create heroku-postgresql:standard-0 --follow DATABASE_URL -a sushi
古いフォロワーが必要なくなったら、必ずプロビジョニング解除してください。
5. メンテナンスモードを終了する
通常のアプリケーション操作を再開するには、Web 以外のすべての dyno をその元のレベルにスケーリングします (heroku ps:scale worker=1
など)。
最後に、メンテナンスモードをオフにします。
$ heroku maintenance:off
アプリケーションが、新しいデータベースインスタンスへのリクエストを受信するようになりました。これは、heroku pg:info
を実行することによって確認できます。DATABASE_URL
で示されるデータベースはプライマリデータベースと見なされます。
Heroku Postgres データベースが Heroku アプリケーションに接続されていない場合は、HEROKU_POSTGRESQL_WHITE_URL
を取得し、それをプライマリデータベースとして使用するようにアプリケーションを更新する必要があります。
古いプライマリデータベースのプロビジョニング解除
データベースをアップグレードした後、古いプライマリデータベースを必ずプロビジョニング解除してください。
$ heroku addons:destroy HEROKU_POSTGRESQL_LAVENDER
古いプライマリデータベースに関連付けられていたデータクリップを新しいデータベースに再割り当てする必要があります。すべての回復可能なデータクリップを解決するには、「Dataclip recovery」(データクリップのリカバリ) の手順に従ってください。