HOME / コンピュータTips / UNIXツール / WebDAVサーバとwebdav-syncでrsyncするには!

Date: 2014/10/06 |  このエントリーをはてなブックマークに追加  |  Tags: rsync, webdav, webdav-sync

ファイル同期の定番、rsync

UNIX使いには毎度おなじみのrsync

rsyncはとても便利なツールで、2つのディレクトリをPermissionまであわせてコピーしたり、タイムスタンプでの比較、ファイルの増分での比較など、2つのディレクトリの同期コピーでは最強といえます。

さらにSSHと一緒に利用すると利便性はUp。SSHのログインさえできるサーバなら、2つのコンピュータのディレクトリを完全に同期させることができるのです。

それゆえ、UNIX使いにとって、最後の最後に頼れるバックアップツールはrsyncという、不動の地位を持っているのです。

WebDAVサーバに対してrsyncする

一番簡単な方法は、WebDAVボリュームをUNIXにマウントしてそこにrsyncする方法なのですが、この方法には大きな問題があります。

rsyncは、fstat(ファイルのステータス情報を調べるsyscall)を使って調査し、その上でファイルのコピーを決めるツールなのですが、このとき、大量のチェックを行います。

これをネットワーク的に離れたサーバのボリュームをマウントしたファイルシステムに対して行うと、たとえばMac OSXのWebDAVクライアントでは、1ファイル転送する度に平均20弱のHTTPコマンドを発効することになり、いつまで経っても終わらない、残念な状態になります。

確かに、rsyncはssh越しでもリモート側でもrsyncが立ち上がり、rsyncがローカルファイルシステムとして、fstatを発効するのです。

リモート専用のツールWebDAV-syncを使う

webdav-sync.png

そこでリモート同期には、やっぱりリモート同期に最適化した仕組みが欲しくなります。

実はWebDAVの場合、プロトコルにPROPFINDというコマンドがあり、このコマンドをつかうとディレクトリ単位でファイルの諸情報を教えてくれたり、ETagsを使ったファイルのシグネチャまで含めて調査できます。

これを使えば、理論上、ファイルの調査含めて、1ファイルあたりのファイル転送時のコマンド発行数が1〜2回となり、ネットワーク的に離れたリモートデータ転送に有利です。

ここではWebDAV-syncというjavaで作られた「コマンドラインツール」を使います。

マニュアルがあるので、すぐに使いこなせるとは思いますが、ここでは、1G無料、1Tでも年1万程度で使えるWebDAVサービスのTeraクラウドでの、利用方法を書いてみます。

下記はちなみにMac OSXの例ですが、SolarisでもLinuxでもJavaが動く環境であれば、何でも使えるはずです。

まずはローカルの~/Documents(書類フォルダ)を、TeraクラウドのDocumentsにコピーする方法です。バックアップ用ですね。

/path-to-inst/webdav_sync.jarは、適当なところにインストールして呼び出してくださいという意味です。ホスト名は、Teraクラウドのアカウント画面から調べてください。

java -jar /path-to-inst/webdav_sync.jar -up \
-u https://ユーザID:パスワード@ホスト名.teracloud.jp/dav/Documents/ \
-d ~/Documents/

起動時直後に、リモート側とローカル側のディレクトリ情報の照合を行うので、そこそこの時間がかかります。私のDocumentsは3分ぐらいかかりましたが、ローカルはSSDだったのでファイル量や、ディスク状況によって大分違うでしょう。

これをcronで回せば、ガンガンコピーしてもらえます。

ただコマンドラインにパスワードが乗るのはいささか気分が良くないので、ファイルにする方法もあります。これとて、ファイルは自分用のPermissionにしておかないと、同じように気分が悪いのですが(笑)まずは、このようなファイルを、ユーザディレクトリの直下に、webdav_sync.confという名前で適当に作っておき、(下記の日本語の文字は適当に貴方の環境に合わせて書き換えること)

<?xml version="1.0"?>
<config>
  <sync>
    <directory>/Users/あなたのユーザ名/Documents/</directory>
    <url>https://あなたのID:あなたのパスワード@ホスト名.teracloud.jp/dav/Documents/</url>
    <direction>up</direction>
    <acl xmlns="DAV:">
      <ace>
        <principal>
          <authenticated/>
        </principal>
        <grant>
          <privilege>
            <read/>
          </privilege>
        </grant>
      </ace>
    </acl>
    <exclude>^\.DS_Store$</exclude>
    <exclude>^\.DocumentRevisions-V100</exclude>
    <exclude>^\.TemporaryItems$</exclude>
    <exclude>^core$</exclude>
    <exclude>^.*\~$</exclude>
    <exclude>^\#</exclude>
    <exclude>^\.\#</exclude>
    <exclude>^\#.*\#$</exclude>
    <exclude>^\.Trashes$</exclude>
    <exclude>^\.csync</exclude>
    <hidden-folder-name>.Hidden</hidden-folder-name>
  </sync>
</config>

下記の様に実行します。

java -jar /path-to-inst/webdav_sync.jar -i 300 -c ~/webdav_sync.conf

-i 300は、300秒ごとに自動実行するという意味です。

<sync />ディレクティブの単位で、複数のジョブを設定できるので、これはリモートアップロード、これはダウンロード専用、これは双方向同期など、選ぶことができます。

javaなので、ファイルサーバなどに設定しておくこともできて便利ですよね。

これで、MacやSolarisやLinuxでも、ガンガン、Teraクラウドにバックアップができますね!

ちなみに・・・、Teraクラウドの容量は公式にも色んなところに書かれてるように、ZFSがファイルシステムとして実際に使っている容量での算出ですから、実際にはローカルのデータ占有率と異なります。この辺はこのブログを参照してるかたはわかりそうですが、比べてみるとZFSはディスク容量食いですね。

引数の抜粋

rsyncやcpと違って、ソースとディスティネーションの指定ではなく、ローカル、リモートの設定になります。

コマンドラインXML説明
-d<directory>dir</directory>ローカルのディレクトリ。アップロード元、或いはダウンロード先
-u<url>https://...</url>リモートのURL。ダウンロード元、或いはアップロード先
-down/-up/-bi<direction>down</direction>down:ダウンロード(-u → -d)
up:アップロード(-d → -u)
bi:双方向
※ダウンロード、アップロードの場合は、ファイルが更新されていたらアップデートしたり、なくなっていたら削除したりします。つまり、ソースと同じものにします。biは正直不明。ETagsを使って矛盾が起きないようにするそうですが・・・
-rename<rename/>アップロード先を削除するのではなく、.1,.2というサフィックスをつけて保存します。-biがついているときに向いているのかも
-rename-depth<rename-depth>10<rename-depth>リネームする時のサフィックスを何世代持つのか?
-hidden-folder<hidden-folder-name>.Hidden<hidden-folder-name>ローカルとリモートに、このプログラム用のファイルを保存するようです
-resetなし?最初から同期をやり直す
-iなし?常駐して指定した秒単位でもう一度同期を試みる
-e<exclude>filename pattern 1</exclude>除外ファイル、exclude
-r<recursive/>サーバがPROPFINDのDepth Infinityをサポートしていない場合でも再帰的にファイルを転送しようとします。Teraクラウドの場合はサーバ側がPROPFINDのDepth Infinityをサポートするため不要です。
-no-recursion<no-recursion/>サーバがPROPFINDのDepth Infinityに対応していても再帰しません

既知のバグっぽいもの

この場合、ファイル名に特殊キャラクタがあるときに起きるみたいです。僕は+と、%で発生しました。

be.re.io.IOException
	at be.re.webdav.cmd.Sync$ListenerAdapter.exception(Sync.java:4807)
	at be.re.webdav.cmd.Sync.put(Sync.java:2938)
	at be.re.webdav.cmd.Sync.exchange(Sync.java:949)
... 割愛

こちらの場合は、XMLでのdirectory directiveで、~/Documentsなど、変数展開しないと存在しないディレクトリを設定するとエラーが出ました。

java.lang.NullPointerException
       at be.re.webdav.cmd.Sync.getFiles(Sync.java:1330)
       at be.re.webdav.cmd.Sync.sync(Sync.java:3908)
       at be.re.webdav.cmd.Sync.run(Sync.java:3380)
       at be.re.webdav.cmd.Sync.sync(Sync.java:3990)
       at be.re.webdav.cmd.Sync.main(Sync.java:2343)

ソースコードが公開されているので、回避バグパッチも作ったのですが、いちいちビルドするよりは、回避策をとった方が多分楽だと思います。

オマケ:rsyncにはVPN越しのNFSが良いか、SSHが良いか?

VPNが貼られた環境でNFSマウントができる環境がしばしばあります。

このときNFSでマウントしているため、

  • NFSマウントしたディレクトリを直接rsyncした方が良いのか?
  • ssh経由コピーした方がいいのか?

という命題がたまにあります。

この記事の上の方を一通り読んだ方は、すぐに答えがわかると思います。

比べた方ならわかるのですが、最近のマシンだと暗号化コストが小さいため、RTTがそこそこある環境では、だいたいsshの方が有利です。

RTTがある環境では、NFSのfstatロスがそこそこにある為ですね。