Drive Network で収容サーバ (お客様の機器) の機器を変更する様な場合、大量のデータ移行が必要ですが、rsync による差分同期でデータ移行に必要な時間を圧縮することが出来ます。
しかしながら、それでも 2 時間を超える様なケースもざらです。メンテナンスによる停止時間を 2 時間等とは恥ずかしくて通知出来ません。
何とか 30 分程度で収まる方法がないかと考えた時、並列同期する方法を思い付きました。
- rsync による差分同期は、機器や帯域への負荷はほとんど見られない。
- rsync を多重起動することで、同期対象のディレクトリを分散。1 つの rsync のプロセスが受け持つ対象数 ($limit) を減らす。
- 1 プロセス当たり、10 – 30 分程度で収まる並列同期数を割り出す。
方針が決まれば、後はスクリプトを書いて検証するのみです。公開鍵の設定と root 権限による rsync のみの許可については省きます。
#!/usr/bin/perl -w # # rsync.pl # #// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #// use Module #// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= use strict; #// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #// Controller #// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #// ---------------------------------------------------------- #// Option Parse #// ---------------------------------------------------------- my $dir = '/home/tools/hs'; unless ($ARGV[0]) { print "usage: $dir/rsync.pl [hsXX]\n"; exit; } my $host = $ARGV[0]; my $rsync = $dir . '/rsync.sh'; my $limit = 20; `rm $dir/rsync.list.*`; my $base = $dir . '/rsync.list.'; my @list = `ls /home/ | grep cs1`; my $list = {}; my $num0 = 0; my $num = 1; #// ---------------------------------------------------------- #// Start #// ---------------------------------------------------------- foreach (@list) { chomp; $num0 += 1; $list->{$num} .= "+ $_/***\n"; if ($num0 == $limit) { $num0 = 0; $num += 1; } } foreach (%$list) { next unless ($list->{$_}); my $file = $base . $_; open WRITE, "+>$file"; print WRITE $list->{$_}; close WRITE; } foreach (1 .. $num) { `$rsync $host $_ > /dev/null &`; }
上記 rsync.pl は主に以下の手順で処理します。
- 引数に `hostname -s` をセットし、
- /home/cs* の対象数を $limit で分割し、
- rsync.list.? に rsync の –include-from で解釈出来るフォーマットで出力し、
- rsync.sh をバックグラウンドで起動。
次は rsync.sh です。
#!/bin/sh # # rsync.sh # ftime=/home/tools/hs/rsync.time.$2 flog=/home/tools/hs/rsync.log.$2 finc=/home/tools/hs/rsync.list.$2 hs_cs=`hostname` hs_bg=$1'.example.jp' [ -z $1 ] && exit 0 touch $ftime touch $flog chmod 640 $ftime $flog echo -n "0: " > $ftime echo `date "+%Y/%m/%d %H:%M:%S"` >> $ftime /usr/local/bin/rsync -avz --delete --ignore-errors -e "ssh -i /root/.ssh/rsync" --include-from="$finc" --exclude "*" /home/ root@$hs_bg:/fs/$hs_cs/ > $flog echo -n "1: " >> $ftime echo `date "+%Y/%m/%d %H:%M:%S"` >> $ftime time=`cat $ftime` log=`tail -n 2 $flog` echo -e "$time\n\n$log" | mail -s "rsync done $1 $finc ($hs_cs)" report@example.jp
rsync のログの最終 2 行は、正常に終了した場合は
sent 893142527 bytes received 1523569 bytes 216233.50 bytes/sec
total size is 188692618183 speedup is 210.91
上記の様になります。この状態が確認出来れば正常終了と判断して良いので、メールで通知する前提で作成しました。
対象ディレクトリが 200 弱で 600GB 程度の同期に、1 プロセスであれば 2 時間必要でしたが、$limit = 20 まで落として 10 プロセスで並列させたところ、30 分以内で収まる様になりました。
ディレクトリ配下によってはサイズやファイル数に差異があるので、必ずしも機械的な分散が功を奏するとは限りませんが、わずかな気転と時間で上々な結果です。
常用する場合はさらにレポートを整形したり、特定ディレクトリのみ同期させるオプションを追加・対象外とする等拡張は必要でしょうが、今回は良しとしています。