sql >> データベース >  >> RDS >> PostgreSQL

PITRの実行中に、PostgreSQLで一時停止/再開することは可能ですか?

    はい、本当に可能であり、PostgreSQLによってスマートに処理されます。これをデモするには、まずPostgreSQLのポイントインタイムリカバリの標準的な手法を採用する必要があります。さまざまな本/記事/ブログは、並外れた著者によって非常にうまくデモされたため、その方法の詳細には触れていませんが、主題に直接向かいます。つまり、同じテクニックで回復しながら一時停止する方法です。間違いなく、私はPITRから数式を「PITR =(LFBの後に生成された最後のファイルシステムバックアップ(LFB)+WALアーカイブ+現在の$PGDATA / pg_xlogsの未アーカイブWAL)」と表現しました。理解を深めるために、考えをより明確にするという事実に照らして、これをグラフに入れました:(申し訳ありませんが、このブログは少し長いですが、コンセプトの詳細を説明しているときに無意識のうちに起こったのです)

    PITRの手順。これは、すぐに説明するわずかな変更を加えたものです。

    手順1.最新のファイルシステムレベルのバックアップ(FSB)を、リカバリの実行が計画されている任意の場所に復元します。
    ステップ2.FSBがtarの場合は、tarを解除し、アーカイブを残してpg_xlogディレクトリをクリーンアップします。バックアップでこのディレクトリが除外されている場合は、FSBに空のpg_xlogディレクトリを作成します。
    ステップ3.アーカイブされていないWALをクラッシュしたクラスター$PGDATA/pg_xlogから$FSB/ pg_xlogにコピーします(ステップ2)
    ステップ4.FSBディレクトリからpostmaster.pidを削除します。
    ステップ5.FSBディレクトリにrecovery.confファイルを作成します。
    ステップ6.クラスター(FSB)を開始します。

    必要な回復を一時停止するときに、質問をする必要がありますか?たぶん、複数のベースの復元やロールフォワードリカバリを防ぐためですが、特定のテーブルのデータまたは関心をチェックインまたはロールバックして、どこまでリカバリされたかを確認してください:)。リカバリで一時停止するということは、リカバリ中に接続できることを忘れないでください。これを概説するために、私は事故まで特定のテーブル行の改善のチャートで状況を再現しました。

    上の図から、ファイルシステムレベルのバックアップ($ PGDATA)を取得した場合のDEMOテーブルの行数は10,00,000であり、クラッシュする前の行数は40,00,000でした。私のローカルVMでは、日付ではなくTIMEの基礎に基づいて状況を作成しました。

    前提条件:
    1。 10,00,000行のDEMOテーブルの場合のファイルシステムレベルのバックアップ。
    2。その時点から、クラッシュする前にWALアーカイブが実行され、DEMOテーブルの行数は40,00,000行になります。
    3。 WALアーカイブの場所:/opt/PostgreSQL/9.3/archives。
    4。データディレクトリ:/opt/PostgreSQL/9.3/data(PGDATA)
    5。バックアップの場所:/opt/PostgreSQL/9.3/backups

    一時停止リカバリを使用するには、メインクラスタ($ PGDATA)の「wal_level」を「hot_standby」に設定し、リカバリクラスタ(ファイルシステムレベルのバックアップ)の「hot_standby」を「ON」に設定する必要があることに注意してください。メインクラスターにこれらの変更を加え、クラスターを再起動して有効にし、バックアップを開始しました。気にしないのであれば、それは単なるデモであることに注意してください。そのため、私のWALアーカイブは数が少ないため、巨大な数ではない可能性があります。バックアップ時からクラッシュまでに生成されたWALアーカイブもここにリストしました。

    -bash-4.1$ psql -c "select count(*), now() from demo;"
    count | now
    ---------+-------------------------------
    1000000 | 2014-04-04 15:06:04.036928-07
    (1 row)

    -bash-4.1$ pg_basebackup -D /opt/PostgreSQL/9.3/backup/data_pitr -- I have my $PGDATA, $PGUSER, $PGPORT set, so its a straight command in my case
    NOTICE: pg_stop_backup complete, all required WAL segments have been archived

    WALアーカイブと$PGDATA/ pg_xlog

    の現在の状態
    -bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
    -rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001C
    -rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001D
    -rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
    -rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E

    -bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/data/pg_xlog | tail -4
    -rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
    -rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
    -rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
    drwx------ 2 postgres postgres 4.0K Apr 4 16:13 archive_status

    これで、バックアップコピーができました。時間を記録して、3つの部分にいくつかのレコードを挿入できるので、リカバリを一時停止し、FSBの時点から生成されたWALを追加で確認できます。

    -bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
    INSERT 0 1000000
    -bash-4.1$ psql -c "select count(*),now() from demo;"
    count | now
    ---------+-------------------------------
    2000000 | 2014-04-04 16:06:34.941615-07
    (1 row)
    -bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
    INSERT 0 1000000
    -bash-4.1$ psql -c "select count(*),now() from demo;"
    count | now
    ---------+-------------------------------
    3000000 | 2014-04-04 16:10:31.136725-07
    (1 row)
    -bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
    INSERT 0 1000000
    -bash-4.1$ psql -c "select count(*),now() from demo;"
    count | now
    ---------+-------------------------------
    4000000 | 2014-04-04 16:13:00.136725-07
    (1 row)

    INSERT中に生成されたWALの数を確認してください。

    -bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
    -rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
    -rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
    -rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
    -rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000020
    -rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000021
    -rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000022
    -rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000023
    -rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000024
    -rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000025
    -rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000026
    -rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000027
    -rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000028
    -rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000029
    -rw------- 1 postgres postgres 16M Apr 4 16:10 00000001000000000000002A
    -rw------- 1 postgres postgres 16M Apr 4 16:13 00000001000000000000002B

    この時点で事故が発生し、FSB + WALアーカイブ+アーカイブされていないWAL(存在する場合)を使用してリカバリを実行する必要があると想定します。リカバリ中に、3回一時停止して、読み取り専用モードでデータベースに接続することにより、DEMOテーブルの20,00,000、30,00,000、および40,00,000行の各リカバリを確認したいと思います。リカバリを再開するたびに、recovery.conf/recovery_target_timeの新しいタイムラインに移動してリカバリクラスタを再起動する必要があります。また、$ FSB / postgresql.confで、hot_standby=onを設定する必要があります。これが私のrecovery.confファイルです:

    -bash-4.1$ more recovery.conf
    pause_at_recovery_target = true
    #recovery_target_time = '2014-04-04 16:06:34' # For 2 lakh records
    #recovery_target_time = '2014-04-04 16:10:31' # For 3 lakh records
    #recovery_target_time = '2014-04-04 16:13:00' # For 4 lakh records
    restore_command = 'cp /opt/PostgreSQL/9.3/archives/%f %p'

    20,00,000レコードのリカバリを開始しましょう:

    -bash-4.1$ /opt/PostgreSQL/9.3/bin/pg_ctl -D /opt/PostgreSQL/9.3/data_pitr/ start
    server starting

    Now in logs:

    -bash-4.1$ more postgresql-2014-04-04_162524.log
    2014-04-04 16:25:24 PDT-24187---[] LOG: starting point-in-time recovery to 2014-02-06 18:48:56-08
    2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001E" from archive
    2014-04-04 16:25:24 PDT-24187---[] LOG: redo starts at 0/1E0000C8
    2014-04-04 16:25:24 PDT-24187---[] LOG: consistent recovery state reached at 0/1E000190
    2014-04-04 16:25:24 PDT-24185---[] LOG: database system is ready to accept read only connections
    2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001F" from archive
    2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "000000010000000000000020" from archive
    2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000021" from archive
    2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000022" from archive
    2014-04-04 16:25:25 PDT-24187---[] LOG: recovery stopping before commit of transaction 1833, time 2014-04-04 16:06:23.893487-07
    2014-04-04 16:25:25 PDT-24187---[] LOG: recovery has paused
    2014-04-04 16:25:25 PDT-24187---[] HINT: Execute pg_xlog_replay_resume() to continue

    かっこいい、ログで一時停止し、再開を求めるスマートヒントを確認してください。ここで、回復に問題がなければ、「select pg_xlog_replay_resume();」(チェックアウトできます)を呼び出して再開できます。今は再開しませんが、サーバーに接続して回復された行数を確認してください。

    -bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
    count | pg_is_in_recovery
    ---------+-------------------
    2000000 | t
    (1 row)

    よかった、それはポイントに達し、私が要求したところに一時停止しました。 30,00,000行を回復するために、さらに一歩進んでみましょう。次に、recovery.conf / restorey_target_timeで次のタイムラインを設定し、クラスターを再起動します。

    2014-04-04 16:28:40 PDT-24409---[] LOG:  restored log file "00000001000000000000002A" from archive
    2014-04-04 16:28:40 PDT-24409---[] LOG: recovery stopping before commit of transaction 1836, time 2014-04-04 16:10:40.141175-07
    2014-04-04 16:28:40 PDT-24409---[] LOG: recovery has paused
    2014-04-04 16:28:40 PDT-24409---[] HINT: Execute pg_xlog_replay_resume() to continue.

    -bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
    count | pg_is_in_recovery
    ---------+-------------------
    3000000 | t
    (1 row)

    いいですね…、最後に40,00,000行で一時停止してみましょう。

    2014-04-04 20:09:07 PDT-4723---[] LOG:  restored log file "00000001000000000000002B" from archive
    cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001000000000000002C': No such file or directory
    2014-04-04 20:09:07 PDT-4723---[] LOG: redo done at 0/2B0059A0
    2014-04-04 20:09:07 PDT-4723---[] LOG: last completed transaction was at log time 2014-04-04 16:11:12.264512-07
    2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000001000000000000002B" from archive
    2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000002.history" from archive
    2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000003.history" from archive
    2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000004.history" from archive
    cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000005.history': No such file or directory
    2014-04-04 20:09:07 PDT-4723---[] LOG: selected new timeline ID: 5
    cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001.history': No such file or directory
    2014-04-04 20:09:07 PDT-4723---[] LOG: archive recovery complete
    2014-04-04 20:09:08 PDT-4721---[] LOG: database system is ready to accept connections
    2014-04-04 20:09:08 PDT-4764---[] LOG: autovacuum launcher started

    -bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
    count | pg_is_in_recovery
    ---------+-------------------
    4000000 | f
    (1 row)

    おっと、何が起こったのか、なぜそれが一時停止しなかったのか、そして何が不平を言っているのか? Recovery_target_timeの時点でWALアーカイブが存在しない場合は、最後のポイントに到達してデータベースを読み取り/書き込み用に開いているため、一時停止して予期しないことに注意してください。ログでは、あまりストレッチを行わずに、ファイル「00000001000000000000002C」を探していましたが、その時点でクラスターがクラッシュしたため、使用できませんでした。一部の人はこの動作を認めないかもしれませんが、その事実であり、WALアーカイブが存在しない場合は、リカバリを一時停止する理由はありません。 WALアーカイブがなくなった後でも一時停止する必要がある場合は、standby_mode =’on’(HOT_STANDBY)を使用します。この方法では、リカバリは終了しませんが、WALアーカイブを待ちます。

    お役に立てば幸いです。


    1. MariaDBでのMINUTE()のしくみ

    2. Oracleで複数の行をコンマ区切りのリストに結合するにはどうすればよいですか?

    3. JavaFXUIおよびJDBCアプリケーションの操作

    4. .nextvalJDBC挿入の問題