rsyncを高速化するために、分散して実行することにした。
全部を1つのスクリプトとしてもいいのだが、デバグがしやすいように分割して作業を行えるようにしている。
また、下記の記述はLinuxの/usrをコピーすることを想定している。環境に応じて書き換えること。
まず、/usr/xxx以下にあるファイルまでをコピーするために以下を実行する。
# rsync --archive -v --exclude="*/*/" /usr/ /mnt/vol/voltest
このexcludeオプションをつけている場合、「/usr/xxx/yyy」のファイルとシンボリックリンクはコピーされる。しかし「/usr/xxx/zzz/」のディレクトリはコピーされない。
次に、「/usr/xxx/zzz/」のディレクトリ一覧を取得する。
# find /usr -mindepth 2 -maxdepth 2 -type d -print
このディレクトリ一覧を下記のperlスクリプトに食わせる。(下記スクリプトは” find /usr -mindepth 2 -maxdepth 2 -type d -print > list.txt”で取得したlist.txtを使う想定)
#!/usr/bin/perl
use threads;
use Thread::Queue;
my $LOGDIR="/root/test";
my $MAXSESSION=5;
my $sourcepathbase="/usr";
my $destpathbase="/mnt/vol/voltest";
my $stream = Thread::Queue->new;
open(FILE,"list.txt");
while(my $tmp=<FILE>){
$stream->enqueue("$tmp");
}
close(FILE);
sub SyncExecute{
while(my $str = $stream->dequeue){
# 改行削除
$str =~ s/\n//ig;
$str =~ s/\r//ig;
# ログ出力用ファイル名
my $filename=$str;
$filename =~ s/\//-/ig;
$filename =~ s/\.//ig;
$filename =~ s/-$//ig;
$filename =~ s/#//ig;
$filename =~ s/^-//ig;
$filename =~ s/ //ig;
my $logfile="$LOGDIR/test-$filename.log";
# rsync元と先の処理
my $tmp,$st,$ed;
my $sourcepath,$destpath;
$tmp=substr($str,0,1);
if($tmp eq "/"){
$sourcepath=$sourcepathbase.$str."/";
$destpath=$destpathbase.$str;
}else{
$sourcepath=$sourcepathbase."/".$str."/";
$destpath=$destpathbase."/".$str;
}
`date >> $logfile`;
print "rsync -v --archive $sourcepath $destpath >> $logfile 2>&1 \n";
`rsync -v --archive $sourcepath $destpath >> $logfile 2>&1 `;
`date >> $logfile`;
#`sleep 5`;
}
}
my @kids;
foreach(1..$MAXSESSION){
my $kid = threads->new(\&SyncExecute,$stream);
push(@kids,$kid);
$stream->enqueue(undef);
}
print "wait\n";
foreach(@kids){
my ($return) =$_ -> join;
}
このスクリプトは、rsyncの同時実行数5で、並列にrsyncを実行していくものになっている。
実行したサーバの負荷状況に応じて「my $MAXSESSION=5;」で設定している 同時実行数 を調整する。あまり大きくしすぎるとサーバからの応答が遅くなりすぎるのでほどほどに・・・
2020/03/10追記
上記で実行するrsyncコマンドはハードリンクの処理を行わないものとなっている。
このため、ハードリンクされているファイルがある場合、コピー先のファイルが1つではなく複数別個のものとしてコピーされる。
ハードリンクをそのままコピーしたい場合は「–hard-links」オプションを追加する必要があるのだが、ハードリンク処理の効力範囲は同一プロセス内で処理すること、という条件があるため、今回のような分割処理して高速化する、という場合には不適切となっている。
このため、ハードリンクファイルがある場合は、初回同期は分割処理で行い、2回目はディレクトリ全体を–hard-linksオプションをつけて1プロセスで処理してハードリンク処理を行わせる、という手法をとる必要がある。
なお、ハードリンク処理が完了したあと、分割処理の対象となった場合、すでにファイルが存在しているので再コピーされる、ということは発生しない。