👏

pythonを用いたPostgreSQLの物理オンラインバックアップ方法

2024/05/21に公開

はじめに

pythonを用いたPostgreSQLの物理オンラインバックアップ方法について記します。bashを経由してpsqlコマンドを操作して物理オンラインバックアップを行う方法が一般的ですが、細かいコントロールが必要な時はbashでは記述が難しくなるため細かいコントロールを行いたい場合はプログラムを作成してバックアップを取得したほうが簡単になります。今回はプログラムの作成例としてpythonを用いた物理オンラインバックを行う方法について記します。

物理オンラインバックアップとは何か

物理オンラインバックアップというのはPostgreSQLを起動した状態でDBを構成するファイルをすべて取得するバックアップ方法です。PostgreSQLが起動した状態で何もせずにDBを構成するファイルのバックアップを取得してしまうとデータを保存するファイルが書き込み途中の状態でバックアップしてしまうとDBが破損する恐れがあります。バックアップ先のデータの破損を防ぐためにはpg_backup_start関数を実行して非排他的バックアップを実行してからバックアップを行う必要があります。バックアップ完了後にはpg_backup_stop関数を実行して非排他的バックアップを完了させます。PostgreSQLのバックアップ方法は物理オンラインバックアップの他に論理バックアップと物理オフラインバックアップという方法もありますが今回はこの2つのバックアップ方法については説明を省略します。

サンプルコード

検証環境

  • PostgreSQL15
  • python3.8.10

事前準備

サンプルコード実行する前にpythonのPostgreSQLのアダプタライブラリであるpsycong3をインストールします。環境によってはpipコマンドはpip3となっている場合もあるので適時読み替えてください。psycong3はPostgreSQL10~16に対応しています。

pip install psycopg[binary]

サンプルコードの内容

サンプルコードでは非排他的バックアップを開始してPostgreSQLのデータ領域のバックアップを取得しています。backup_database関数の処理を変更することで様々なバックアップ方法に対応することが出来ます。例えばクラウド上で動作しているVM上でバックアップを取得する場合、クラウド側のバックアップサービスの実行要求をbackup_database関数内で行えばVMのバックアップ時にDBのバックアップも取得することが出来ます。PostgreSQLのバージョンが14以前のバージョンでこのスクリプトを実行したい場合はpg_backup_start関数をpg_start_backup関数に変更し pg_backup_stop関数をpg_stop_backup関数に変更して各関数のパラメータを設定しなおせば実行可能になります。

import psycopg
import tarfile

# バックアップ関数のサンプル
# 単純にローカルに存在するデータディレクトリをtarで保存する。
# postgresqlのデータディレクトリは適時変更する。
def backup_database():  
    tarfilename = "backup.tar.gz"
    datadir = "/var/lib/postgresql/data"
    with tarfile.open(tarfilename, "w:gz") as tar:
        tar.add(datadir)

# バックアップ処理、DBの接続情報は適時変更する。
with psycopg.connect("host=localhost user=postgres password=examplepass port=5432") as conn: 
    with conn.cursor() as cur:
        # 非排他バックアップを開始する。
        cur.execute("SELECT pg_backup_start(label => 'backup1', fast => true)") 
        s = cur.fetchall()
        
        # バックアップ処理を実行する。
        backup_database()   

        # 非排他バックアップを終了する。
        cur.execute("SELECT * FROM pg_backup_stop(wait_for_archive => true)") 
        e = cur.fetchall()
        with open("result.txt", "w") as f:
            for row in e:
                f.write(",".join(row))

参考

オンライン物理バックアップの排他モードと非排他モードについて
PostgreSQL 15 で廃止となった排他的バックアップについて
非排他的バックアップを実行するシェルスクリプトの改善
Psycopg 3
PostgreSQL15 26.3. 継続的アーカイブとポイントインタイムリカバリ
PostgreSQL14 26.3. 継続的アーカイブとポイントインタイムリカバリ

株式会社エーピーコミュニケーションズ

Discussion