목요일 오후, DB 서버 디스크가 갑자기 죽었습니다. 마지막 백업을 언제 했는지 기억이 안 납니다. 차장이 "백업은 있죠?"라고 물어봅니다. 파일이 있긴 한데 복구 절차를 한 번도 연습해본 적이 없습니다. 백업은 만들어두는 것이 아니라 복구할 수 있어야 진짜 백업입니다. 이 모듈을 마치면 장애 상황에서 침착하게 데이터를 복구할 수 있습니다.
백업과 복구 전략
"백업을 한 번도 안 쓴 사람"과 "백업이 필요했던 사람"은 있어도 "백업이 필요 없는 사람"은 없습니다. 데이터 유실은 시간 문제입니다. 이 모듈에서는 리눅스 환경에서 실무에서 쓰는 백업 방법과 복구 절차를 다룹니다.
백업은 만드는 것보다 복구하는 것이 더 중요합니다. 복구 안 되는 백업은 백업이 아닙니다.
- 13-2-1 백업 규칙과 백업 유형 (전체/증분/차등)
- 2tar — 아카이브 생성과 복구
- 3rsync — 증분 미러 백업과 원격 동기화
- 4스냅샷 — LVM/파일시스템 스냅샷 기반 백업
- 5복구 절차와 복구 테스트
백업 유형 — 전체/증분/차등 차이
| 유형 | 방법 | 백업 속도 | 복구 속도 | 저장 공간 |
|---|---|---|---|---|
| 전체(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
- sha256sum -c 실행 시 'OK' 메시지가 출력됐는가? (체크섬 일치 확인)
- tar -tzf로 백업 파일 내부 목록이 정상적으로 출력됐는가?
- 특정 파일 복구 시 경로에서 맨 앞 슬래시(/)를 제거했는가?
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 실행 결과에서 삭제될 파일 목록을 먼저 검토했는가?
- rsync 완료 후 대상 경로의 파일 수와 원본이 일치하는가?
- cron 등록 후 /var/log/backup.log에서 정상 실행 기록이 남는가?
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처럼 파일이 계속 변경 중일 때도 일관된 시점의 백업 가능
# 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"
복구 테스트를 분기마다 반드시 하세요. "백업이 있다"와 "복구할 수 있다"는 다른 이야기입니다.