개요
최소 GB 단위부터 시작하여 TB 단위에 이르는 대용량 파일 데이터를 이관하기 위해
rsync를 활용한 쉘 스크립트를 작성해보고자 한다.
Rsync
- 특정 디렉토리와 파일을 지정하여 원격으로 복사 및 동기화
- 변경분만 체크하여 동기화 수행하므로 SCP와 비교하여 비교적 속도가 빠름.
- 디렉터리 파일의 권한 및 속성 그대로 가져올 수 있음
Rsync는 네트워크를 통해 로컬 서버와 원격 서버간 데이터를 동기화하는 프로그램이다.
일반적으로 파일 이관, 동기화, 백업을 하기 위한 용도로 많이 사용된다.
사용 방법
# 로컬 서버의 파일을 원격 서버로 동기화하는 경우
rsync -avzh [로컬 디렉토리 경로] [계정]@[원격 서버 IP]:[원격 디렉토리 경로]
# 원격 서버의 파일을 로컬 서버로 동기화하는 경우
rsync -avzh [계정]@[원격 서버 IP]:[원격 디렉토리 경로] [로컬 디렉토리 경로]
사용 예시
# 원격서버로 파일 내보내기
rsync -avzh /my-data user@192.168.219.113:/mnt/data
# 로컬서버로 파일 가져오기
rsync -avzh user@192.168.219.113:/mnt/data /my-data
적용 예시
IDC를 임대하여 서비스를 운영 중인 중소급 규모의 회사에서
대규모 데이터를 클라우드 환경으로 이관하는 케이스가 있다고 가정해 보자.
이때, 대규모 데이터를 얼마나 안전하고 신속하게 이관할 수 있느냐가 주요 관건일 것이다.
이 상황에서 데이터의 안정성을 위해서는 IPSecVPN을 도입하는 방안을 고려해 볼 만하고,
신속성을 위해서는 Data Telepoter 장비를 대여하는 방안도 고려해 볼 만할 것이다.
그러나, 되도록이면 비용이 발생하지 않는 방향으로
그리고 별도의 솔루션 도입 없이 데이터를 이관할 수 있는 방안이 필요하다고 한다면
Rsync
를 사용하는 것이 가장 최선의 방법일 것 같다.
이번 실습에서는 Rsync를 활용한 데이터 이관 처리 스크립트를 작성해 볼 것이다.
물론 스크립트 작성 없이 서버마다 접속하여 Rsync
명령을 수행하는 것도 방법이긴 하나,
서버가 1,2대만 있는 것은 아니기에 일일이 서버에 접속하여 작업한다면 굉장히 번거로운 작업이 된다.
따라서 쉘 스크립트를 작성하여 데이터를 이관하는 작업을 수행할거다.
스크립트의 가장 중요 포인트는 Rsync 프로세스 병렬 실행 및 처리 부분이다.
예를 들어, 8코어 서버에서 단일 프로세스를 실행할 때 하나의 CPU를 사용한다고 하면,
8개의 프로세스를 실행하여 시스템 자원을 모두 할당함으로써 데이터 전송을 위한 처리 성능을 높인다.
단, 이때 서버에서 애플리케이션이나 기타 중요 서비스가 동작 중이라면
데이터 이관 과정에서 서비스에 문제가 생길 수 있으므로 주의해야 한다.
스크립트 작성
단일 디렉터리, n개 이상의 디렉터리를 각각 분리하여 별도의 스크립트를 작성해 볼 거다.
대상 디렉토리가 1개 인 경우
로컬 서버의 특정 디렉토리 하나를 지정하여 원격 서버로 이관하기 위한 병렬 처리 스크립트
#!/usr/bin/bash
# rsync 병렬 프로세스 수 설정
parallel_processes=8
# xargs에 전달할 인자 수 설정
args_per_process=1
# 원격 서버 IP 주소
remote_ip="192.168.219.113"
# 로컬 디렉토리 경로 (동기화할 소스 디렉토리)
source_directory="/mnt/data/"
# 원격 서버에서 동기화 대상 디렉토리 경로
target_directory="/data/"
# 디버그 정보를 저장할 임시 디렉토리 생성
temp_directory="/tmp/backupDir"
if [[ ! -d "$temp_directory" ]]; then
mkdir -p "$temp_directory"
fi
# 로컬 서버의 파일/디렉토리 목록 생성
function generate_file_list() {
rsync -avzP --dry-run "$source_directory" | sort -n
}
generate_file_list > "$temp_directory/meta.txt"
# 병렬로 rsync 프로세스 실행
function run_in_parallel() {
ls "$source_directory" | xargs -I {} -P "$parallel_processes" -n "$args_per_process" rsync -avz --progress "$source_directory"{} "$remote_ip:$target_directory"
}
run_in_parallel
변수 설명
parallel_processes=8
: 병렬로 실행할 rsync 프로세스의 수를 8으로 설정하였다.args_per_process=1
: xargs 명령어에 전달할 인자의 수를 1로 설정하였다.remote
: 원격 서버의 IP 주소이다.sourDir
: 로컬 디렉토리의 경로이다. 이 경로의 파일들을 원격 서버로 동기화한다.tarDir
: 원격 서버에서 동기화할 대상 디렉토리의 경로이다.tmpDir
: 디버그 정보를 저장할 임시 디렉토리의 경로이다.
함수 설명
function generate_file_list() {
rsync -avzP --dry-run "$srcDir" | sort -n
}
generate_file_list > "$tmpDir/meta.txt"
generate_file_list()
: rsync를 이용하여 로컬 디렉토리의 파일 및 디렉토리 목록을 가져온다.- rsync 옵션:
-a
: 아카이브 모드로, 파일 권한, 시간 등의 정보를 유지-v
: 자세한 출력.-z
: 전송 중 데이터를 압축.-P
: 진행 상황을 표시.--dry-run
: 실제로 동기화하지 않고 어떤 파일들이 동기화될지 미리 확인.
sort -n
: rsync 출력 결과를 숫자 순서로 정렬.- 정렬된 파일 목록을
$tmpDir/meta.txt
파일에 저장.
- rsync 옵션:
function run_in_parallel() {
ls "$srcDir" | xargs -I {} -P "$p" -n "$n" rsync -avz --progress "$srcDir"{} "$remote:$tarDir"
}
run_in_parallel
run_in_parallel()
:ls
를 사용하여 소스 디렉토리($srcDir
)의 파일과 디렉토리 목록을 가져옴.xargs
명령어는ls
로 얻은 파일 목록을 입력으로 받아 병렬로rsync
를 실행함.-I {}
:xargs
에서 파일 이름을 대체하는 플레이스홀더로{}
를 사용-P "$p"
: 병렬로 실행할 프로세스 수를"$p"
로 설정. 즉, 최대 6개의rsync
프로세스가 동시에 실행됨.-n "$n"
:xargs
가 한 번에 전달하는 인자의 수를"$n"
으로 설정
- 각 파일을
"$remote"
서버의"$tarDir"
에 동기화 함.
대상 디렉터리가 n 개 이상인 경우
로컬 서버에서 경로가 서로 다른 디렉토리 여러 개를 지정하여 원격 서버로 이관하기 위한 병렬 처리 스크립트이다.
디렉토리의 리스트를 list.txt
파일에 저장하여 스크립트의 input 값으로 넣어주는 부분이 1번 스크립트와 다른 부분이다.
추가로 스크립트 실행 및 종료 시간, 로그 파일 생성, 기타 옵션 등을 보완하여 작성하였기에 이 스크립트가 최종본이라고 보면 될 것 같다.
#!/usr/bin/bash
# 디버그 정보를 저장할 임시 디렉토리 생성
tmpDir="/tmp/backupDir"
if [[ ! -d "$tmpDir" ]]; then
mkdir -p "$tmpDir"
fi
# 시작시간 기록
startDate="$(date '+%Y-%m-%d %H:%M:%S')"
startDateFormat="$(date '+%Y-%m-%d_%H%M%S')"
# 로그 기록
touch "$tmpDir/$startDateFormat"
exec 3>> "$startDateFormat"
echo "Start ... [$startDate]" >&3
# rsync 병렬 프로세스 수 설정
parallel_processes=8
# xargs에 전달할 인자 수 설정
args_per_process=1
# 원격 호스트 IP 주소
remote="192.168.219.113"
# 로컬 디렉토리 목록 읽기
IFS_BACK="$IFS"
IFS=$'\n'
currentPath="$(pwd)"
list="$(cat $currentPath/list.txt)"
list=($list) # array 형태로 정의
# 로컬 서버의 파일/디렉토리 목록 생성
for sourDir in "${list[@]}"; do
rsync -avzP --dry-run "$sourDir" | sort -n >> "$tmpDir/meta.txt"
done
# 병렬로 rsync 프로세스 실행
function run_in_parallel() {
for sourDir in "${list[@]}"; do
ls "$sourDir" | xargs -I {} -P "$parallel_processes" -n "$args_per_process" rsync -avz -e "ssh -p 22" --progress --bwlimit=1000000 "$sourDir"{} "$remote:$sourDir"
done
}
run_in_parallel
# 종료시간 기록
endDate="$(date '+%Y-%m-%d %H:%M:%S')"
endDateFormat="$(date '+%Y-%m-%d_%H%M%S')"
echo "End ... [$endDate]" >&3
list.txt
파일의 내용은 아래와 같이 작성된다.
/mnt/data/
/mnt/logs/
/mnt/drivers/
변수 설명
IFS_back
: 기존의 IFS 값을 백업해주자. IFS는 쉘의 내부 필드 구분자를 지정하는 역할을 한다.IFS=$'\n'
: IFS를 줄바꿈 문자(\n)로 설정하여, 파일 내에서 줄 단위로 읽도록 바꿨다.currentPath=$(pwd)
: 현재 디렉토리 경로를 가져온다.list=$(cat $currentPath/list.txt)
: 현재 디렉토리에 있는list.txt
파일의 내용을 읽어온다.list=($list)
: 파일의 각 줄을 배열 list에 저장하도록 한다. 여기서()
은 쉘 스크립트에서 배열로 정의할 때 사용된다.
함수 설명
function run_in_parallel() {
for sourDir in "${list[@]}"; do
ls "$sourDir" | xargs -I {} -P "$parallel_processes" -n "$args_per_process" rsync -avz -e "ssh -p 22" --progress --bwlimit=1000000 "$sourDir"{} "$remote:$sourDir"
done
}
run_in_parallel()
: 각 sourDir 디렉토리에 대해 병렬로rsync
를 실행한다.ls $sourDir
: 해당 디렉토리의 파일 목록을 가져온다.xargs
명령어는ls
의 결과를 입력으로 받아 병렬로rsync
를 실행한다.-I {}
:xargs
에서 파일 이름을 대체할 플레이스홀더로{}
를 사용하도록 변경해줬다.-P $parallel_processes
: 병렬로 실행할rsync
프로세스 수를$parallel_processes
로 설정한다. 즉, 최대 8개의rsync
프로세스가 동시에 실행된다.-n $args_per_process
:xargs
가 한 번에 전달하는 인자의 수를$args_per_process
으로 설정한다.
rsync -avz -e "ssh -p 22" --progress --bwlimit=1000000
: 파일을 원격 서버로 전송한다.-e "ssh -p 22"
: rsync에 사용할 SSH 옵션을 지정. 여기서는 포트 22를 사용했음 (사용하는 SSH 포트 번호에 맞게 변경하도록 하자.)
--bwlimit=1000000
: 전송 속도를 초당 1,000,000KB로 제한
$sourDir{}
: 원본 파일 경로를 지정.$remote:$sourDir
: 원격 서버의 동기화 대상 경로를 지정