オープンソース資料館
今回のテーマは、Subversionのバックアップとリストアについて。
2019/4/5: Subversionのバックアップの件
前提
Subversion 1.10
(バージョン依存はあまりないはずだが一応)
バックアップの色々
Subversionのバックアップ手段はいろいろ用意されているが、定期的に自動で取得することを前提に考えた際の事を考えて見る。
(1) OSレベルでのバックアップ
(2) hotcopyによる取得
(3) svn-dump-backups.pyによる増分ダンプ
(4) svnsync
(1) OSレベルでのバックアップ
Linuxならrsync, Windowsならrobocopyを使用したスクリプトを作成して差分バックアップを取得する。他のバックアップ手段を執るにしてもこれは「念のため」やっておく。これの欠点は「書き込みモードで開いているファイルは壊れてコピーされるかも知れない」という点で、これを回避するため、誰もアクセスしていない夜間時間帯に自動実行するのが良いだろう。これで取得したバックアップは、そのままリポジトリに上書きすれば使える。
rsyncやrobocopyのよいのは差分で取得できる点。なので、例えば週末にフルバックアップを取得して、平日の夜間は差分で取得する、などとすればよい。また、簡単なのも良い。リポジトリの親ディレクトリを指定して実行すれば、後でリポジトリが増えても自動で取ってくれるから。
なお、もし、リポジトリのバックアップでこの方法を取らなかったとしても、hookスクリプトやconfファイルなどのバックアップはこれで取っておくと良いだろう。
>robocopy コピー元パス コピー先パス /mir /copyall /xo
(2) hotcopyによる取得
svnadmin hotcopyはリポジトリのフルコピーを取得できる。ファイルが開いていても可能なホットバックアップだ。そのままリポジトリに戻せば使える。ただ、スナップショットを取得するにはいいのだが、フルバックアップなので時間も掛かるので週末の夜間に取得のがよいだろう。リカバリの際にhotcopy単独で戻すと言うよりは後述するDumpとの合わせ技になる。
>svnadmin hotcopy リポジトリパス バックアップのパス
(3) svn-dump-backups.pyによる増分ダンプ
svnadmin dumpはリポジトリのダンプをしてくれる。フルでダンプするのはこれでいいのだが、自動実行して増分バックアップをする際には問題がある。svnadmin dumpでは増分を取るにはリビジョンを指定しなければならない。となると、スクリプトの中で最新リビジョン番号を取得して、計算して・・・とやらねばならないことになる。Subversionの標準コマンドではないが、これをやってくれるスクリプトが、svn-dump-backups.pyだ。Pythonで書かれたスクリプトなのでPython(Python2)の実行環境が必要であるが、増分ダンプを取るのに非常に使い勝手が良い。
>python svn-dump-backups.py -i リポジトリのパス バックアップ先のパス
(-i、は増分だけを取得するオプション)
すると、
リポジトリ名.開始リビジョン-終了リビジョン.svndmp
という名前でダンプファイルを作ってくれる。例えば、
samplerepo.000025-000050.svndmp
といった具合に。どのリポジトリのどのリビジョンが含まれるか一目瞭然なので便利。
なお、制作年度が古いのかpython2でないと動かない、という情報があり、弊社で構築する場合もPython2と一緒に入れている。
(4) svnsync
リアルタイムのバックアップが欲しい、という人も多い。Subversionは完全ではないがリアルタイムに近いバックアップを取得する手段を用意している(完全ではないのは、データベースのようなロールバックの仕組みはなく、マスタ側のコミット「後」に取るため、障害時のリカバリはマニュアルだからだ)。これがsvnsyncだ。多くのサイトで実装されている。実装方法は簡単で、(初期設定・初期化の後)post-commitスクリプトに、
svnsync sync --sync-user-name xxxx --sync-password xxxx 転送先URL(http://xxx --non-interactive 転送元URL(file:///....)
と書いておく。すると、マスタ側のコミットが終了するとスレーブ側にその内容を転送するのだ。スレーブ側はマスタと同じ内容のコミットをローカルで行う。なお、svnsyncの失敗をエラーにするには、スクリプト内でエラー処理すし、終了時にゼロではないコードを返すように作る必要がある。
さて、問題はバックアップを使って戻す作業だろう。
ステップ1は、前の#1から#3のバックアップを使ってバッチで取得した時点(日次なら前日)までリポジトリを戻すこと。その際、#3のダンプはリポジトリの中だけしか戻さない。hooks配下は戻してくれないので他のバックアップから持ってくる必要があるので注意。
そして、「どこまで戻ったか」を確認する。これは後で更に最新化する際に使う。
>svnlook youngest リポジトリパス
50 (前の#1~#3で復旧したリポジトリの最新のリビジョンが50、の場合)
そしてステップ2、今度はスレーブ側でダンプを取得する。
>svnadmin dump --incremental -r 51:head リポジトリパス > ダンプファイル名
(50までは要らないので、51から最新までを取得)
これをマスタ側にコピーする。で、
>svnadmin load リポジトリパス < ダンプファイル名
でロードする。もちろんリポジトリの内容の全部を戻すこともできるが、時間が掛かるのでhotcopyなどを使ってある程度近いところまで戻した方が早い。それでも時間がかかる懸念がある場合、1.10で追加された --no-flush-to-diskオプションを使う事も検討。
svnsyncは、動かすのは比較的容易だが、取ったバックアップを使ってどうやって戻すか、は他のバックアップも含めてやや複雑と思われる。
なお、面倒くさいからとスレーブのリポジトリをマスタに丸コピーしても動作しないので注意。クライアントから見ればUUIDというリポジトリの識別子が違うのでエラーになるし、マスタとスレーブではフックスクリプトも異なるはずだから。
お問い合わせください
OSSPlazaでは、Subvesrionサーバの構築やサポートを行っています。サーバの構築や入れ替えを検討中であれば、ぜひお問い合わせください。