개요
최소 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대만 있는 것은 아니기에 일일이 서버에 접속하여 작업한다면 굉장히 번거로운 작업이 될 것이다.
따라서 쉘 스크립트를 작성하여 데이터를 이관하는 작업을 수행해볼 것이다.
위 상황에서 스크립트를 작성함으로써 얻는 장점은 다음과 같다.
- 반복적이고 일관된 작업을 자동화하여 생산성을 높임.
- 로그 파일을 남김으로써 수행 결과를 체계적으로 확인할 수 있음.
- 변수 설정을 통해 소스 디렉토리, 타겟 디렉토리, IP 주소 등을 지정하였고, 이를 얼마든지 재사용할 수 있었음.
- 명령어가 순차적으로 실행되므로, 디버깅이 용이하며 가독성이 높았음.
- 프로세스를 병렬로 실행시켜 부하를 분담하고 처리 속도를 향상시킬 수 있었음.
- 스크립트를 백그라운드(
&
)로 실행함으로써 세션을 끊어도 문제가 발생하지 않았으며, 주기적인 모니터링이 가능했음.
스크립트의 가장 중요 포인트는 Rsync 프로세스 병렬 실행 및 처리 부분이다.
예를 들어, 8코어 서버에서 단일 프로세스를 실행할 때 하나의 CPU를 사용한다고 하면,
8개의 프로세스를 실행하여 시스템 자원을 모두 할당함으로써 데이터 전송을 위한 처리 성능을 높였다.
단, 이 때 서버에 애플리케이션이 동작 중이라면 서비스에 문제가 생길 수 있으므로 작업 기간을 협의하여야 한다.
병렬 처리 스크립트
1. 대상 디렉토리 1개
로컬 서버의 특정 디렉토리 하나를 지정하여 원격 서버로 이관하기 위한 병렬 처리 스크립트
#!/usr/bin/bash
# rsync 프로세스 수 설정
p=6
# xargs에 전달할 인자의 수 설정
a=1
# 로컬 호스트 IP 주소
local="127.0.0.1"
# 원격 호스트 IP 주소
remote="192.168.219.113"
# 로컬 디렉토리 경로 (이 경로의 파일들을 원격 서버로 동기화)
srcDir="/mnt/data/"
# 원격 서버에서 동기화할 대상 디렉토리의 경로
tarDir="/data/"
# 디버그 정보를 저장할 임시 디렉토리 생성
tmpDir="/tmp/backupDir"
if [[ ! -d "$tmpDir" ]]; then
mkdir -p "$tmpDir"
fi
# 로컬 서버의 파일/디렉토리 목록 생성
function getList() {
rsync -avzP --dry-run "$srcDir" | sort -n
}
getList > "$tmpDir/meta.txt"
# 병렬로 rsync 프로세스 실행
function parallel() {
ls "$srcDir" | xargs -I {} -P "$p" -n "$n" rsync -avz --progress "$srcDir"{} "$remote:$tarDir"
}
parallel
변수 설명
p=6
: 병렬로 실행할 rsync 프로세스의 수를 6으로 설정합니다.n=1
: xargs 명령어에 전달할 인자의 수를 1로 설정합니다.local
: 로컬 호스트의 IP 주소입니다. 스크립트에서는 사용되지 않습니다.remote
: 원격 서버의 IP 주소입니다.sourDir
: 로컬 디렉토리의 경로입니다. 이 경로의 파일들을 원격 서버로 동기화합니다.tarDir
: 원격 서버에서 동기화할 대상 디렉토리의 경로입니다.tmpDir
: 디버그 정보를 저장할 임시 디렉토리의 경로입니다.
함수 설명
function getList() {
rsync -avzP --dry-run "$srcDir" | sort -n
}
getList > "$tmpDir/meta.txt"
getList()
: rsync를 이용하여 로컬 디렉토리의 파일 및 디렉토리 목록을 가져옵니다.- rsync 옵션:
-a
: 아카이브 모드로, 파일 권한, 시간 등의 정보를 유지합니다.-v
: 자세한 출력을 합니다.-z
: 전송 중 데이터를 압축합니다.-P
: 진행 상황을 표시합니다.--dry-run
: 실제로 동기화하지 않고 어떤 파일들이 동기화될지 미리 확인합니다.
sort -n
: rsync 출력 결과를 숫자 순서로 정렬합니다.- 정렬된 파일 목록을
$tmpDir/meta.txt
파일에 저장합니다.
- rsync 옵션:
function parallel() {
ls "$srcDir" | xargs -I {} -P "$p" -n "$n" rsync -avz --progress "$srcDir"{} "$remote:$tarDir"
}
parallel
parallel()
:ls
를 사용하여 소스 디렉토리($srcDir
)의 파일과 디렉토리 목록을 가져옴.xargs
명령어는ls
로 얻은 파일 목록을 입력으로 받아 병렬로rsync
를 실행함.-I {}
:xargs
에서 파일 이름을 대체하는 플레이스홀더로{}
를 사용-P "$p"
: 병렬로 실행할 프로세스 수를"$p"
로 설정. 즉, 최대 6개의rsync
프로세스가 동시에 실행됨.-n "$n"
:xargs
가 한 번에 전달하는 인자의 수를"$n"
으로 설정
- 각 파일을
"$remote"
서버의"$tarDir"
에 동기화 함.
2. 대상 디렉토리 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 프로세스 수 설정
p=6
# xargs에 전달할 인자의 수 설정
a=1
# 로컬 호스트 IP 주소
local="127.0.0.1"
# 원격 호스트 IP 주소
remote="192.168.219.113"
# 로컬 디렉토리 목록 읽기
IFS_BACK="$IFS"
IFS=$'\n'
currentPath="$(pwd)"
list="$(cat $currentPath/list.txt)"
list=($list) # array 형태로 정의
# 배열의 첫 세개 요소를 출력하여 제대로 읽어졌는지 확인
echo "${list[0]}"
echo "${list[1]}"
echo "${list[2]}"
# 로컬 서버의 파일/디렉토리 목록 생성
for sourDir in "${list[@]}"; do
rsync -avzP --dry-run "$sourDir" | sort -n >> "$tmpDir/meta.txt"
done
# 병렬로 rsync 프로세스 실행
function parallel() {
for sourDir in "${list[@]}"; do
ls "$sourDir" | xargs -I {} -P "$p" -n "$n" rsync -avz -e "ssh -p 22" --progress --bwlimit=1000000 "$sourDir"{} "$remote:$sourDir"
done
}
# 종료시간 기록
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 parallel() {
for sourDir in "${list[@]}"; do
ls "$sourDir" | xargs -I {} -P "$p" -n "$n" rsync -avz -e "ssh -p 22" --progress --bwlimit=1000000 "$sourDir"{} "$remote:$sourDir"
done
}
parallel()
: 각 sourDir 디렉토리에 대해 병렬로 rsync를 실행합니다.ls $sourDir
: 해당 디렉토리의 파일 목록을 가져옵니다.- xargs 명령어는 ls의 결과를 입력으로 받아 병렬로 rsync를 실행합니다.
-I {}
: xargs에서 파일 이름을 대체할 플레이스홀더로 {}를 사용합니다.-P $p
: 병렬로 실행할 rsync 프로세스 수를 $p로 설정합니다. 즉, 최대 6개의 rsync 프로세스가 동시에 실행됩니다.-n $n
: xargs가 한 번에 전달하는 인자의 수를 $n으로 설정합니다.
rsync -avz -e "ssh -p 22" --progress --bwlimit=1000000
: 파일을 원격 서버로 전송합니다.-e "ssh -p 22"
: rsync에 사용할 SSH 옵션을 지정합니다. 여기서는 포트 22를 사용합니다.
--bwlimit=1000000
: 전송 속도를 초당 1,000,000KB로 제한합니다.
$sourDir{}
: 원본 파일 경로를 지정합니다.$remote:$sourDir
: 원격 서버의 동기화 대상 경로를 지정합니다.