[ホーム] -> [Aache + PHP + PostgreSQL 実験室] |
日々データベースを運用し、安全面を考えると、データベースのバックアップは当然必要となってきます。バックアップの方法には複数通りあります。
data
ディレクトリごとバックアップをとる
pg_dump
コマンドを使う
一番目の方法は、非常に手っ取り早いものです。PostgreSQL のデータファイルは、普通のファイルですので、OS に付いているバックアップツールを使ってバックアップをしてしまう方法です。tar
コマンドや、cp
コマンドや、その他のツールを使って PostgreSQL の data
ディレクトリをバックアップしまいます。ただし、バックアップ中にデータが変更されるとまずいので、必ずデータベースを停止した状態でバックアップします。したがって、この方法は、バックアップ時にデータベースが停止してもかまわないような環境で利用できます。
二番目の方法は、PostgreSQL に付いてきている pg_dump
、pg_dumpall
コマンドを使う方法です。これらのコマンドは、実際には copy
という SQL 文を実行しているので、データベースが起動していなければなりませんが、PostgreSQL に接続できる環境であれば、たとえリモートのマシンからでもバックアップをとることが可能です。もちろん、ただの SQL 文を実行してデータを取得するので、PostgreSQL のセキュリティの影響を受けます。そのため、バックアップを取るデータベース(テーブル)に対して、読み取り(select
)の権限が無いといけません。データベースをバックアップする場合は、そのデータベースの作成者、pg_dumpall
を使う場合は、PostgreSQL のスーパーユーザで実行するのが無難だと思います。
> pg_dump -Fc -b データベース名 > db_archive.dump
これで、db_archive.dump
にデータが出力されます。このファイルはバイナリですが、圧縮されているので、大きなデータベースをバックアップするときには効率的です。また、このデータから復元させるには、次のように行います。
> createdb -T template0 データベース名 > pg_restore -d データベース名 db_archive.dump
これで、データベースが復元されます。-T template0
は必ず指定してください(理由を知りたい場合は、マニュアルを参照してください)。また pg_dumpall
は、全てのデータベースのバックアップを行います。したがって、データベース名を指定する必要はありません。これらのコマンドは、データベースのバージョンアップを行うときにも使用できます。PostgreSQL の場合、バージョンアップを行うと、データベースファイルの互換性がなくなる場合があります。その場合は、これらのコマンドを使ってデータを移行する必要があります。
場合によっては、テーブル単位でバックアップとを取り、テーブル単位でデータを復元したい場合もあるかと思います。テストしてるときとかは、重宝します。それには次のようにします。
バックアップ > pg_dump -t テーブル データベース名 > dump.out 復元 > psql データベース名 < dump.out
-b
オプションを指定してませんが、これを指定してない場合はラージオブジェクト(非常に大きいデータを格納するための特別なデータ型と思ってください)がバックアップされません。ただし、バックアップした dump.out
は、普通のテキストファイルで、中には SQL 文が書かれるようになります。復元する前に中身を加工することも可能です。
pg_dump
は、データの整合性が保証されています。これは、pg_dump
を開始した後、他のユーザによりデータが変更されても、その変更はバックアップには反映されないということです。例えば、バックアップ対象のデータベースには、テーブルA とテーブルB と テーブルC があったとします。pg_dump
を実行してしばらくし、テーブルAのバックアップが終わり、現在テーブルBをバックアップしているとします。この瞬間に、誰かがテーブルAとテーブルCにデータを追加したとします。
TIME ------ 1 -------> -------------2-------------> --------3------> | | BACKUP | BACKUP | BACKUP | | | | | | +---------+ | | +---------+ | | +---------+ | | TABLE A | | | | TABLE A | | | | TABLE A | v | | | | | | <-+ | | | | | | | | | *** | | | | | *** | +---------+ | | +---------+ | | | +---------+ | TABLE B | | | | TABLE B | | | | | TABLE B | | | | v | | +- ADD | | | | | | | | | | | | | | +---------+ | +---------+ | | | +---------+ | TABLE C | | | TABLE C | | | | | TABLE C | | | | | | <-+ | v | | | | | | *** | | | *** | +---------+ | +---------+ | +---------+
その後 pg_dump
が進み、テーブルBが完了してテーブルCも完了しました。バックアップの最中に、テーブルAとテーブルCに追加がありましたが、テーブルAはバックアップ済みなので追加されたデータは入っていないのはもちろんのこと、テーブルCのバックアップにも追加されたデータは入っていません。
これは非常に重要な点です。システムを作っていくと、ある二つのテーブルには、必ずペアでデータが登録しないといけない場合などがあります。もしこの整合性が保証されていないと、プログラムから見るとテーブルAとテーブルCにデータを入れたにもかかわらず、バックアップからデータベースを復元してみたらテーブルCにのみデータが入っていることになります。PostgreSQL では、このような困ったことは起きません。PostgreSQL えらい!
でも、pg_dump
、pg_dumpall
コマンドですが、昔は一部の情報(トリガーとか当時実装されたばっかりのもの)がバックアップできないとかいう問題があったりしました。今は大丈夫かとは思いますが、使用前には十分テストをお勧めします。
データベースを作成された後、実際のデータは、環境変数 PGDATA
で定義した場所に格納されます。普通に作ると、すべてのデータベースがそのディレクトリの下に作成されますが、データベース毎に違うディレクトリも指定できます。
データベース毎に違うディレクトリを置くことは、安全上大きなメリットがあります。まず知っての通り、UNIX は、ディレクトリ対してディスクパーテションをマウントできます。そのため、データベース毎に違うディレクトリを指定すると、データベース毎に違うパーテションにデータを配置することが出来ます。これにより、あるデータベースのデータ量が多くなり、他のデータベースを圧迫してしまうことが無くなります。また、物理的に違うディスクをマウントしておくことにより、IO の速度低下を押さえることが出来ます。
どのディレクトリにデータを置くか考えたら、その一つ上のディレクトリを作成します。このディレクトリ以下は、PostgreSQL のスーパーユーザ(PostgreSQL サーバを実行するユーザ)でないといけないため、これらの作業は、PosrgreSQL のスーパーユーザで行ってください。
つぎに、このディレクトリを環境変数に設定します。この環境変数の名前は何でもいいのですが、マニュアルによると、「PGDATA
」で始まる文字を推奨しています。
> su - pgsql > mkdir -p /home/www/db sh, bash 等 > PGDATA_WWWDB=/home/www/db/data > export PGDATA csh, tcsh 等 > setenv PGDATA_WWWDB /home/www/db/data
この場合、/home/www/db/data
の下にデータが格納しようとしています。次に、initlocation
というコマンドを使って、このディレクトリを初期化?します。
> initlocation PGDATA_WWWDB
引数には、先ほどの環境変数の名前を指定します。頭にダラー「$
」を付けてはいけません。そうしたら、サーバを再起動します。ちなみに、この環境変数は、サーバが起動するときに必ず設定しておく必要があります。
環境によって違うとは思いますが、rpm をインストールしている方なら、PostgreSQL のスーパーユーザのホームディレクトリに、.profile
というファイルを作り、このファイルに先ほどの環境変数の設定を書いておくと、/etc/rc.d/init.d/postgresql restart
としたときにきちんと設定されると思います。
> vi ~/.profile 次の2行を追加 PGDATA_WWWDB=/home/www/db/data export PGDATA > su - # /etc/rc.d/init.d/postgresql restart
そしたら、データベースを作成しますが、そのときにデータの作成先を指定します。
> createdb -D PGDATA_WWWDB wwwdb
-D
オプションの後ろには、やっぱり環境変数の名前を指定します。これにより、先ほど指定した /home/www/db/data
の下に、データベースが作成されます。この後は、特にこのディレクトリを意識することなく通常通り作業をすることが出来ます。
今まで説明した方法で、新しいデータベースは作成できるのですが、既存のデータベースのディレクトリを変更したい場合は、PostgreSQL サーバを停止した後、ファイルを移動し、元の場所へシンボリックリンクファイルを作成するのでも全然問題ありません。
> pg_ctl stop > mkdir -p /db/wwwdb/data/base > cd /usr/local/pgsql/data/base > cp -a 16555 /db/wwwdb/data/base/ > rm -rf 16555 > ln -s /db/wwwdb/data/base 16555 > pg_ctl start
実はさっきのディレクトリを指定してデータベースを作る方法も、実際にはシンボリックリンクファイルでリンクが張られています。また、同じように、WAL ログ(data
ディレクトリにある pg_xlog
というディレクトリ)も移動することが出来ます。
前に、grant, revoke
文のところでチラッとふれましたが、PostgreSQL には、ユーザグループの機能があります。普通 grant, revoke
文はユーザを対象に設定しますが、グループにユーザを登録しておいて、そのグループに対して権限を付加することが出来ます。ユーザ数が多くなったときに便利です。
使い方はと言うと、まずグループを作成します。
=> create group webusers; CREATE GROUP
これで、webusers
グループが作成されました。次に、このグループにユーザを追加します。
=> alter group webusers add user dareka; ALTER GROUP => alter group webusers add user rin, siz; ALTER GROUP
webusers
グループに、dareka, rin, siz
の3人が追加されました。ユーザを削除したりグループを削除したりするには、次のようにします。
=> alter group webusers drop user rin; ALTER GROUP => drop group webusers; DROP GROUP
この様にして作ったグループを、活用するには、次のようにします。
=> grant select on meibo to group webusers; GRANT
気を付けるべき点は、to ユーザ
としていたところを、to group グループ
とする点です。