목요일 오후, DB 서버 디스크가 갑자기 죽었습니다. 마지막 백업을 언제 했는지 기억이 안 납니다. 차장이 "백업은 있죠?"라고 물어봅니다. 파일이 있긴 한데 복구 절차를 한 번도 연습해본 적이 없습니다. 백업은 만들어두는 것이 아니라 복구할 수 있어야 진짜 백업입니다. 이 모듈을 마치면 장애 상황에서 침착하게 데이터를 복구할 수 있습니다.
백업과 복구 전략
"백업을 한 번도 안 쓴 사람"과 "백업이 필요했던 사람"은 있어도 "백업이 필요 없는 사람"은 없습니다. 데이터 유실은 시간 문제입니다. 이 모듈에서는 리눅스 환경에서 실무에서 쓰는 백업 방법과 복구 절차를 다룹니다.
백업은 만드는 것보다 복구하는 것이 더 중요합니다. 복구 안 되는 백업은 백업이 아닙니다.
- 13-2-1 규칙과 전체·증분·차등 백업의 차이를 구분할 수 있다
- 2tar로 아카이브를 만들고 특정 파일을 복구할 수 있다
- 3rsync로 증분 미러 백업과 원격 동기화를 구성할 수 있다
- 4LVM·파일시스템 스냅샷으로 일관성 있는 백업을 만들 수 있다
- 5RPO·RTO 관점에서 복구 절차를 설계하고 복구를 검증할 수 있다
백업 유형 — 전체/증분/차등 차이
확대
| 유형 | 방법 | 백업 속도 | 복구 속도 | 저장 공간 |
|---|---|---|---|---|
| 전체(Full) | 모든 데이터 복사 | 느림 | 빠름 | 많음 |
| 증분(Incremental) | 마지막 백업 이후 변경분만 | 빠름 | 느림(체인) | 적음 |
| 차등(Differential) | 마지막 전체 백업 이후 변경분 | 중간 | 중간 | 중간 |
실무 전략: 주 1회 전체 + 매일 증분 (또는 차등)
tar — 아카이브 백업
# 기본 압축 백업
tar -czf /backup/www-$(date +%Y%m%d).tar.gz /var/www/html
# 옵션 설명
# c: create, z: gzip 압축, f: 파일명 지정
# x: extract, t: list(목록 보기), v: verbose
# 증분 백업 (--newer 활용)
tar -czf /backup/incremental-$(date +%Y%m%d).tar.gz \
--newer /backup/last-full.tar.gz /var/www/html
# 특정 파일 복구
tar -xzf /backup/www-20260414.tar.gz \
-C /restore/ \
var/www/html/config.php # 앞의 / 없음
# 무결성 확인
tar -tzf /backup/www-20260414.tar.gz | head -20
# 체크섬 파일 생성 (백업과 함께 보관)
sha256sum /backup/www-20260414.tar.gz > /backup/www-20260414.tar.gz.sha256
# 검증
sha256sum -c /backup/www-20260414.tar.gz.sha256
- 먼저 tar -tzf로 백업 파일 내부 목록을 확인하고, 그 다음 sha256sum -c로 체크섬 일치를 검증 — 목록이 없거나 OK가 아니면 백업 자체가 손상됨
- 백업 파일 크기 기준: 원본 대비 gzip 압축률 30-70% 감소가 정상. 1% 미만 감소라면 이미 압축된 파일이거나 -z 옵션이 빠진 것
- sha256sum -c 결과 FAILED이고 tar -tzf도 오류가 나면 → 저장 중 손상, FAILED이지만 목록은 정상이면 → 체크섬 파일 자체가 다른 버전으로 생성된 것을 의미
rsync — 증분 미러 백업
# 기본 미러 동기화
rsync -avz --delete /var/www/html/ /backup/www/
# 옵션
# a: archive (권한, 타임스탬프, 심볼릭 링크 유지)
# v: verbose, z: 전송 압축, --delete: 원본 삭제 파일 동기화
# 원격 서버로 백업 (SSH)
rsync -avz --delete /var/www/html/ backup@192.168.1.100:/backup/www/
# --dry-run으로 사전 확인 (필수 습관)
rsync -avz --delete --dry-run /var/www/html/ /backup/www/
# 제외 패턴
rsync -avz --exclude='*.log' --exclude='.git/' \
/var/www/html/ /backup/www/
# crontab에 등록 (매일 새벽 2시)
# 0 2 * * * rsync -az --delete /var/www/html/ /backup/www/ >> /var/log/backup.log 2>&1
rsync의 강점: 변경된 파일만 전송 → 대용량 디렉토리도 빠르게 동기화
- --dry-run 출력에서 먼저 "deleting" 접두사가 붙은 라인을 확인하고, 그 다음 전송 예정 파일 수를 확인 — deleting이 예상보다 많으면 src 경로가 잘못된 것
- 전송 효율 기준: "sent X bytes received Y bytes" 에서 sent/received 비율이 10:1 이상이면 정상 증분 동기화, 1:1에 가까우면 거의 전체를 재전송 중(--delete와 함께 점검)
- cron 로그에 "rsync error"가 있고 exit code가 11이면 → 디스크 용량 부족, 23이면 → 일부 파일 접근 권한 문제를 의미
LVM 스냅샷 — 순간 백업
# LVM 스냅샷 생성 (순간적 일관성 있는 복사본)
lvcreate -L 5G -s -n www-snap /dev/vg0/www
# 스냅샷 마운트 후 백업
mount -o ro /dev/vg0/www-snap /mnt/snap
tar -czf /backup/www-snap-$(date +%Y%m%d).tar.gz /mnt/snap/
# 백업 완료 후 스냅샷 제거
umount /mnt/snap
lvremove -f /dev/vg0/www-snap
스냅샷의 장점: DB처럼 파일이 계속 변경 중일 때도 일관된 시점의 백업 가능
RPO / RTO — 백업 주기와 복구 시간 목표
백업 전략은 결국 두 가지 질문으로 정리됩니다. **"데이터를 어디까지 잃어도 되는가(RPO)"**와 **"얼마 만에 복구해야 하는가(RTO)"**입니다. 이 두 목표가 백업 주기와 복구 절차의 수준을 결정합니다.
확대
- RPO(Recovery Point Objective) — 마지막 백업 시점과 장애 시점 사이의 데이터는 복구할 수 없습니다. 하루 1회 백업이면 최대 24시간치 손실을 감수해야 합니다. RPO를 줄이려면 백업 주기를 짧게 하거나 실시간 복제를 씁니다.
- RTO(Recovery Time Objective) — 장애 발생부터 정상 서비스 복귀까지 허용 시간입니다. 복구 절차가 자동화되어 있지 않거나 복구 리허설을 한 적이 없으면 RTO는 사실상 무한대가 됩니다.
테스트 디렉토리 준비 및 파일 생성
mkdir -p ~/backup-test/src ~/backup-test/dest
echo '중요 데이터 파일 1' > ~/backup-test/src/data1.txt
echo '중요 데이터 파일 2' > ~/backup-test/src/data2.txt
ls ~/backup-test/src/예상 출력
data1.txt data2.txt
tar로 압축 백업 생성 및 체크섬 파일 생성
tar -czf /tmp/backup-$(date +%Y%m%d).tar.gz ~/backup-test/src/
sha256sum /tmp/backup-$(date +%Y%m%d).tar.gz > /tmp/backup-$(date +%Y%m%d).tar.gz.sha256
ls -lh /tmp/backup-*.tar.gz예상 출력
-rw-r--r-- 1 user user 1.2K [날짜] /tmp/backup-20260614.tar.gz
tar 백업 내용 목록 확인 (무결성 점검)
tar -tzf /tmp/backup-$(date +%Y%m%d).tar.gz예상 출력
home/user/backup-test/src/ home/user/backup-test/src/data1.txt home/user/backup-test/src/data2.txt
rsync로 증분 미러 백업 (--dry-run 먼저 확인)
rsync -avz --delete --dry-run ~/backup-test/src/ ~/backup-test/dest/예상 출력
sending incremental file list data1.txt data2.txt sent 156 bytes received 43 bytes
rsync 실제 실행 및 체크섬 검증
rsync -avz --delete ~/backup-test/src/ ~/backup-test/dest/
sha256sum -c /tmp/backup-$(date +%Y%m%d).tar.gz.sha256예상 출력
/tmp/backup-20260614.tar.gz: OK
# MySQL 실행 중에 rsync로 /var/lib/mysql 백업
rsync -az /var/lib/mysql/ /backup/mysql/
# 복구 후: InnoDB 로그 불일치로 MySQL 기동 실패
원인: MySQL이 실행 중에 데이터 파일을 rsync하면 트랜잭션 중간 상태가 캡처됩니다.
올바른 방법:
# 방법 1: mysqldump (논리 백업)
mysqldump -u root -p --all-databases --single-transaction \
> /backup/all-dbs-$(date +%Y%m%d).sql
# 방법 2: MySQL 중지 후 rsync
systemctl stop mysql
rsync -az /var/lib/mysql/ /backup/mysql/
systemctl start mysql
# 방법 3: Percona XtraBackup (Hot Backup — 무중단)
xtrabackup --backup --target-dir=/backup/mysql/
실무 백업 자동화 스크립트
#!/bin/bash
# /usr/local/bin/daily-backup.sh
BACKUP_DIR="/backup/$(date +%Y%m%d)"
LOG="/var/log/backup.log"
mkdir -p "$BACKUP_DIR"
echo "[$(date)] 백업 시작" >> "$LOG"
# 웹 파일
rsync -az --delete /var/www/html/ "$BACKUP_DIR/www/" && \
echo "[$(date)] WWW 완료" >> "$LOG" || \
echo "[$(date)] WWW 실패" >> "$LOG"
# DB 덤프
mysqldump -u root -p"$MYSQL_PASS" --all-databases \
--single-transaction > "$BACKUP_DIR/databases.sql" && \
echo "[$(date)] DB 완료" >> "$LOG"
# 7일 이전 백업 삭제
find /backup -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;
echo "[$(date)] 백업 완료" >> "$LOG"
복구 테스트를 분기마다 반드시 하세요. "백업이 있다"와 "복구할 수 있다"는 다른 이야기입니다.
다음 모듈에서는 SSL/TLS 인증서 관리 — Let's Encrypt 인증서 발급부터 자동 갱신, Nginx/Apache 적용까지 HTTPS 서버를 구성하는 방법을 다룹니다.