rsyncしても一部ファイルが同期されない

こんにちは。鎌田です。
今回は高速にファイルを同期する"rsync"というコマンドを使用した際に、一部ファイルが同期されないという問題が発生したため、その解決策をご紹介いたします。
rsyncはファイルを同期する前に転送元と転送先のファイルをチェックし、差分があるものだけを同期します。デフォルトの挙動では、ファイルサイズとタイムスタンプをチェックして、転送対象のファイルを判断しているのですが、それだとファイルが同期されない可能性があります。

原因

rsyncでは転送元ファイルと転送先ファイルのタイムスタンプに秒単位に違いがなくファイルサイズが同じだと同期されません。そのため、rsyncを使用して更新の激しいファイルをコピーする場合、ミリ秒・ナノ秒単位の違いで書き込まれたファイルは正しく同期されない可能性があります。

解決策

-c オプションをつけチェックサムによる差分確認をすれば、ミリ秒・ナノ秒単位の違いで書き込まれたファイルを同期させることができます。

以下でタイムスタンプに焦点を当てて、rsyncの挙動を調査してみました。

環境

  • OS :Oracle Linux Server release 7.2
  • rsync バージョン: 3.0.9

また rsyncのバージョン3.1.0でも同様の問題で、ファイルが同期されません。
(3.1.0では、同期するとタイムスタンプをナノ秒精度でコピーするため、下記の例外のようなことは起きません。)

執筆時点で開発が進行しているrsyncでは、オプションに --modify-window=-1 をつけることで、ナノ秒精度でファイルの更新確認が行われるようになります。こちら
※ただし、使用しているファイルシステムがナノ秒精度のタイムスタンプをサポートしていることが必要になります。

どのような場合に同期 される/されない のか?

調査のためにファイルサイズが同じファイルを2つ用意しました。

  • 同期元ファイル:a/foobar
  • 同期先ファイル:b/foobar

rsyncの挙動を見やすくするために -av オプションをつけております。

□同期元ファイルと同期先ファイルのタイムスタンプが同じ場合

同期されません

a/foobarb/foobarはタイムスタンプが同じため同期されません。

比較のために、ファイルサイズが違う場合のrsyncの結果を載せます。

同期されます
a/foobarb/foobarのファイルサイズが違うと、このように同期されます。

さらに比較のために、ファイルサイズは同じだが、中身が違う場合の結果を載せます。

同期されません
このように、ファイルサイズが同じでタイムスタンプも同じだと中身が違う場合でも同期されません。
 

□同期元ファイルのタイムスタンプを999,999,999ナノ秒(ほぼ1秒)進めた場合

同期されません

a/foobarのタイムスタンプを999,999,999ナノ秒(ほぼ1秒)進めてみたのですが、ミリ秒・ナノ秒単位での更新では同期されないようです。

□同期元ファイルのタイムスタンプを1秒進めた場合

同期されます

a/foobarのタイムスタンプをさらに1ナノ秒(差分が1秒ちょうど)進めると同期されました。

□同期元ファイルのタイムスタンプを1,999,999,999ナノ秒(ほぼ2秒)進めた場合

同期されます

a/foobarの転送元ファイルのタイムスタンプを1,999,999,999ナノ秒(ほぼ2秒)進めると同期されます。

a/foobar 11:30:46.999999999
b/foobar 11:30:46.000000000

しかしタイムスタンプは一致せず、秒精度で切り詰められていることが確認できました。

□同期元ファイルと同期先ファイルのタイムスタンプを1ナノ秒ずらした場合

同期されます

a/foobar 11:30:46.000000000
b/foobar 11:30:45.999999999

1ナノ秒差でも同期されました。どのくらいタイムスタンプに差があるか、ではなく上記のように秒単位に違いがあると、ファイルが同期されることが確認できました。

(例外)タイムスタンプが秒精度に切り詰められない場合がある

以下のような場合にrsyncをすると、b/foobarのタイムスタンプが 11:30:48.00000000 に更新されるはずです。

しかし、rsyncを実行したタイミングのシステム時刻によってタイムスタンプが秒精度に切り詰められない現象が発生します。

rsyncをするとb/foobarのタイムスタンプが

b/foobar 11:30:48.00000000 ではなく、
b/foobar 11:30:48.00200004 

となり期待とは違うタイムスタンプに更新されました。

おそらくパフォーマンスを意識しての実装です。
rsyncはファイル受信側に転送ファイルを書き込んだ後、タイムスタンプの更新を行います。このとき、受信側で転送時に書き込んだ時のタイムスタンプと送信側のファイルのタイムスタンプを比較します。比較の結果、タイムスタンプが秒精度で一致していた場合、タイムスタンプの更新処理を省略します。

つまりrsyncが受信ファイルを書き込んだ時の、タイムスタンプのままになる場合があります。そのため同期されたファイルのタイムスタンプが、必ず秒精度で切り詰められるわけではありません。

おわりに

便利なコマンドも理解して使わないとデータの損失や書き換えミスにつながることを学びました。特にLinux OSではファイルの操作や書き換えをする際は、コマンドの挙動を理解してから使用します。
また機会があれば、別のコマンドについてもご紹介させていただきます。

Comments are closed, but you can leave a trackback: Trackback URL.