쉘 스크립트로 DB 자동 백업 시스템 만들기 | MySQL 백업 완벽 가이드

왜 DB 자동 백업이 필요한가?

솔직히 말씀드리면, 저도 처음엔 백업을 수동으로 했어요. “이번 주말에 꼭 백업해야지” 하다가 결국 한 달이 지나가고… 그러다 어느 날 실수로 DROP TABLE 명령을 실행했던 기억이 아직도 생생합니다. 다행히 2주 전 백업이 있어서 큰 피해는 없었지만, 그 2주간의 데이터는 영영 사라졌죠.

수동 백업의 가장 큰 문제는 ‘사람의 기억력에 의존한다’는 점입니다. 바쁜 일상 속에서 백업은 항상 우선순위에서 밀려나기 마련이에요. 특히 1인 운영자라면 개발, 운영, 마케팅까지 혼자 해야 하는데 백업까지 신경 쓰기가 정말 어렵습니다.

자동화를 도입하면 이런 고민에서 완전히 벗어날 수 있어요. 한 번만 설정해두면 매일 새벽 자동으로 백업이 진행되고, 오래된 백업은 알아서 삭제되며, 문제가 생기면 알림까지 받을 수 있습니다. 쉘 스크립트로 DB 자동 백업 시스템 만들기는 생각보다 어렵지 않고, 한 번 만들어두면 평생 써먹을 수 있는 자산이 됩니다.

실제 장애 사례로 보는 백업의 중요성

사례 원인 결과 교훈
쇼핑몰 상품 DB 손실 서버 디스크 장애 3개월치 데이터 복구 불가 정기 백업 필수
회원정보 테이블 삭제 쿼리 실수 당일 백업으로 복구 성공 일일 백업의 중요성
랜섬웨어 공격 보안 취약점 원격 백업으로 전체 복구 오프사이트 백업 필요

백업 스크립트 설계하기

본격적으로 쉘 스크립트로 DB 자동 백업 시스템 만들기를 시작하기 전에, 백업 전략부터 수립해야 합니다. 저는 처음에 이 단계를 건너뛰고 바로 코드부터 짰다가 나중에 스토리지가 가득 차는 문제를 겪었어요.

백업 전략 수립

개인 프로젝트나 소규모 서비스라면 전체 백업(Full Backup)만으로도 충분합니다. 증분 백업(Incremental Backup)은 복잡도는 높지만 용량을 크게 절약할 수 있어서, DB 크기가 10GB 이상이라면 고려해볼 만해요.

백업 방식 장점 단점 적합한 경우
전체 백업 복구 간단, 관리 쉬움 용량 많이 차지 DB 크기 5GB 이하
증분 백업 용량 절약, 빠른 백업 복구 복잡, 설정 어려움 DB 크기 10GB 이상
차등 백업 중간 수준의 복잡도 시간이 지날수록 용량 증가 주간 백업 전략

백업 파일 네이밍 규칙

백업 파일명은 나중에 찾기 쉽도록 일관된 규칙이 필요합니다. 저는 이런 형식을 사용해요:

  • db명_YYYYMMDD_HHMM.sql.gz – 기본 형식
  • myshop_20260315_0300.sql.gz – 실제 예시
  • 날짜와 시간을 포함하면 언제 백업했는지 한눈에 파악 가능
  • .gz 확장자로 압축 여부를 명시

보관 주기와 스토리지 계산

처음엔 “많이 보관할수록 좋겠지”라고 생각했는데, 클라우드 스토리지 비용 청구서를 보고 깜짝 놀랐어요. 현실적인 보관 전략을 추천드립니다:

  • 최근 7일: 일일 백업 전체 보관
  • 최근 4주: 주간 백업 보관 (매주 일요일)
  • 최근 12개월: 월간 백업 보관 (매월 1일)
  • 그 이상: 필요시 분기별 또는 연간 백업

예를 들어 DB 크기가 500MB이고 압축률이 70%라면, 압축 후 약 150MB입니다. 이 경우 필요한 스토리지는 약 3.5GB 정도면 충분해요 (7일×150MB + 4주×150MB + 12개월×150MB).

쉘 스크립트로 DB 자동 백업 시스템 만들기 관련 이미지

MySQL/MariaDB 백업 스크립트 작성

이제 본격적으로 쉘 스크립트로 DB 자동 백업 시스템 만들기의 핵심인 스크립트 작성 단계입니다. 저는 여러 번의 시행착오 끝에 지금 소개할 스크립트에 정착했어요.

mysqldump 기본 사용법

mysqldump는 MySQL/MariaDB의 기본 백업 도구입니다. 가장 간단한 사용법은 이렇습니다:

단일 데이터베이스 백업:
mysqldump -u username -p password database_name > backup.sql

전체 데이터베이스 백업:
mysqldump -u username -p password –all-databases > all_backup.sql

하지만 실전에서는 더 많은 옵션이 필요합니다. 제가 실제로 사용하는 옵션들을 설명드릴게요.

실전 백업 스크립트 코드

아래 스크립트는 제가 실제로 사용하는 버전입니다. 처음엔 10줄짜리 간단한 스크립트로 시작했다가, 하나씩 문제를 해결하면서 지금의 형태가 되었어요:

backup_mysql.sh

#!/bin/bash

# 설정 변수
DB_USER="your_username"
DB_PASS="your_password"
DB_NAME="your_database"
BACKUP_DIR="/home/backup/mysql"
DATE=$(date +%Y%m%d_%H%M)
BACKUP_FILE="${BACKUP_DIR}/${DB_NAME}_${DATE}.sql"
DAYS_TO_KEEP=7

# 백업 디렉토리 생성 (없으면)
mkdir -p ${BACKUP_DIR}

# 백업 시작 로그
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 백업 시작: ${DB_NAME}" >> ${BACKUP_DIR}/backup.log

# mysqldump 실행
mysqldump -u${DB_USER} -p${DB_PASS} \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  ${DB_NAME} > ${BACKUP_FILE}

# 백업 성공 여부 확인
if [ $? -eq 0 ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 백업 성공: ${BACKUP_FILE}" >> ${BACKUP_DIR}/backup.log
    
    # 압축
    gzip ${BACKUP_FILE}
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 압축 완료: ${BACKUP_FILE}.gz" >> ${BACKUP_DIR}/backup.log
    
    # 오래된 백업 삭제
    find ${BACKUP_DIR} -name "${DB_NAME}_*.sql.gz" -mtime +${DAYS_TO_KEEP} -delete
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ${DAYS_TO_KEEP}일 이전 백업 삭제 완료" >> ${BACKUP_DIR}/backup.log
else
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 백업 실패!" >> ${BACKUP_DIR}/backup.log
    exit 1
fi

여기서 중요한 옵션들을 설명드릴게요:

  • –single-transaction: InnoDB 테이블을 락 없이 백업 (서비스 중단 없음)
  • –routines: 저장 프로시저와 함수도 함께 백업
  • –triggers: 트리거도 백업에 포함
  • –events: 이벤트 스케줄러도 백업

저는 처음에 –single-transaction 옵션을 몰라서 백업할 때마다 서비스가 느려지는 문제를 겪었어요. 이 옵션 하나로 완전히 해결됐습니다!

압축 및 암호화 적용하기

500MB짜리 SQL 파일이 gzip으로 압축하면 50MB 정도로 줄어들어요. 압축률이 정말 놀랍습니다. 더 나아가 보안이 중요하다면 암호화도 추가할 수 있어요:

암호화 추가 버전:

# 압축 후 암호화
gzip ${BACKUP_FILE}
openssl enc -aes-256-cbc -salt -in ${BACKUP_FILE}.gz -out ${BACKUP_FILE}.gz.enc -pass pass:your_encryption_password
rm ${BACKUP_FILE}.gz  # 암호화 전 파일 삭제

다만 암호화를 추가하면 복호화 비밀번호를 안전하게 관리해야 하는 부담이 생깁니다. 저는 클라우드에 업로드하는 백업만 암호화하고, 로컬 백업은 압축만 적용하는 방식을 사용해요.

오래된 백업 파일 자동 삭제

스크립트에 이미 포함되어 있지만, find 명령어를 좀 더 자세히 설명드릴게요:

find ${BACKUP_DIR} -name "${DB_NAME}_*.sql.gz" -mtime +${DAYS_TO_KEEP} -delete
  • -name: 파일명 패턴 지정
  • -mtime +7: 7일 이상 된 파일
  • -delete: 찾은 파일 삭제

처음엔 -delete 옵션이 무서워서 -exec rm {} \; 를 사용했는데, 나중에 -delete가 더 안전하다는 걸 알게 됐어요.

Crontab으로 백업 자동화 설정

쉘 스크립트로 DB 자동 백업 시스템 만들기의 마지막 단계는 자동화 설정입니다. 아무리 좋은 백업 스크립트를 만들어도 실행을 깜빡하면 소용없으니까요.

Cron 표현식 이해하기

Cron 표현식은 처음엔 정말 헷갈렸어요. 하지만 기본 패턴만 알면 금방 익숙해집니다:

Editor’s Pick

휴대용 노트북 거치대
개발자 필수 거북목 방지 아이템

자세히 보기

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

위치 의미 범위 예시
1번째 분(Minute) 0-59 30 = 30분
2번째 시(Hour) 0-23 3 = 새벽 3시
3번째 일(Day) 1-31 15 = 15일
4번째 월(Month) 1-12 * = 매월
5번째 요일(Day of week) 0-7 (0,7=일요일) 0 = 일요일

자주 사용하는 패턴들을 정리해봤어요:

  • 0 3 * * * – 매일 새벽 3시
  • 0 0 * * 0 – 매주 일요일 자정
  • 0 2 1 * * – 매월 1일 새벽 2시
  • */30 * * * * – 30분마다
  • 0 */6 * * * – 6시간마다

백업 스케줄 등록 방법

먼저 스크립트에 실행 권한을 부여해야 합니다:

chmod +x /path/to/backup_mysql.sh

그 다음 crontab을 편집합니다:

crontab -e

에디터가 열리면 다음 라인을 추가하세요:

# MySQL 데이터베이스 일일 백업 (매일 새벽 3시)
0 3 * * * /home/user/scripts/backup_mysql.sh

# 주간 백업 (매주 일요일 새벽 2시)
0 2 * * 0 /home/user/scripts/backup_mysql_weekly.sh

저는 처음에 상대 경로로 스크립트를 지정했다가 cron이 실행을 못 하는 문제를 겪었어요. 반드시 절대 경로를 사용하세요!

로그 기록 및 모니터링 설정

스크립트가 잘 실행되는지 확인하려면 로그가 필수입니다. 위 스크립트에는 이미 로그 기능이 포함되어 있지만, cron 자체의 로그도 확인할 수 있어요:

# Cron 로그 확인 (Ubuntu/Debian)
grep CRON /var/log/syslog

# Cron 로그 확인 (CentOS/RHEL)
grep CRON /var/log/cron

또한 crontab 라인에 직접 로그 리다이렉션을 추가할 수도 있습니다:

0 3 * * * /home/user/scripts/backup_mysql.sh >> /var/log/mysql_backup.log 2>&1

백업 검증 및 복구 테스트

백업을 만들기만 하고 복구 테스트를 안 해보는 건 정말 위험해요. 저도 실제로 복구가 필요한 순간에 백업 파일이 손상되어 있었던 경험이 있습니다. 그때 정말 식은땀이 났어요.

백업 파일 무결성 확인

압축 파일이 정상적으로 압축되었는지 확인하는 스크립트를 추가하면 좋습니다:

# 스크립트에 추가할 검증 코드
if gzip -t ${BACKUP_FILE}.gz; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 백업 파일 무결성 확인 성공" >> ${BACKUP_DIR}/backup.log
else
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 백업 파일 손상 발견!" >> ${BACKUP_DIR}/backup.log
    # 알림 전송 (뒤에서 설명)
fi

실제 복구 시뮬레이션

최소한 월 1회는 실제 복구 테스트를 해보는 걸 권장합니다. 테스트용 데이터베이스를 만들어서 연습해보세요:

# 1. 압축 해제
gunzip backup_file.sql.gz

# 2. 테스트 DB 생성
mysql -u root -p -e "CREATE DATABASE test_restore;"

# 3. 복구 실행
mysql -u root -p test_restore < backup_file.sql

# 4. 데이터 확인
mysql -u root -p test_restore -e "SHOW TABLES;"

# 5. 테스트 DB 삭제
mysql -u root -p -e "DROP DATABASE test_restore;"

저는 매월 첫째 주 월요일에 이 작업을 달력에 등록해두고 실행하고 있어요.

슬랙/이메일 알림 연동

백업 실패 시 즉시 알림을 받는 건 정말 중요합니다. 슬랙 웹훅을 사용한 알림 예시를 공유할게요:

# 슬랙 알림 함수
send_slack_notification() {
    local message=$1
    local webhook_url="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
    
    curl -X POST ${webhook_url} \
        -H 'Content-Type: application/json' \
        -d "{\"text\":\"${message}\"}"
}

# 백업 실패 시 알림
if [ $? -ne 0 ]; then
    send_slack_notification "⚠️ MySQL 백업 실패: ${DB_NAME} ($(date))"
fi

이메일 알림을 원하시면 mailx나 sendmail을 사용할 수 있어요:

# 이메일 알림 (mailx 설치 필요)
echo "백업 실패: ${DB_NAME}" | mail -s "DB Backup Failed" your@email.com

자주 묻는 질문 (FAQ)

Q. 백업 중 DB 성능에 영향은 없나요?

--single-transaction 옵션을 사용하면 InnoDB 테이블의 경우 서비스에 거의 영향을 주지 않습니다. 다만 MyISAM 테이블은 읽기 락이 걸리므로, 가능하면 서비스 사용이 적은 새벽 시간대에 백업하는 걸 추천드려요. 저는 새벽 3시로 설정했는데, 이 시간대는 사용자가 거의 없어서 문제가 없었습니다.

Q. 여러 DB를 한 번에 백업하려면?

배열을 사용해서 여러 데이터베이스를 순회하면 됩니다. 스크립트 상단에 DB_NAMES=("db1" "db2" "db3") 형태로 배열을 선언하고, for 루프로 각 DB를 백업하면 돼요. 또는 --all-databases 옵션으로 전체를 한 번에 백업할 수도 있지만, 복구 시 선택적으로 할 수 없다는 단점이 있습니다.

Q. 원격 서버로 백업 파일 전송 방법은?

rsync나 scp를 사용하면 됩니다. 저는 rsync를 선호해요. 백업 스크립트 마지막에 이 코드를 추가하세요: rsync -avz ${BACKUP_FILE}.gz user@remote-server:/backup/path/ SSH 키 인증을 설정해두면 비밀번호 없이 자동으로 전송됩니다. AWS S3나 Google Cloud Storage를 사용하는 것도 좋은 방법이에요.

Q. PostgreSQL이나 Oracle은 어떻게 백업하나요?

PostgreSQL은 pg_dump 명령어를 사용합니다: pg_dump -U username database_name > backup.sql Oracle은 expdp (Data Pump Export) 또는 전통적인 exp 명령어를 사용해요. 기본 원리는 MySQL과 동일하지만, 각 DBMS의 특성에 맞는 옵션들이 다릅니다. 쉘 스크립트로 DB 자동 백업 시스템 만들기 원리는 모든 DBMS에 동일하게 적용할 수 있어요.

Q. 백업 스크립트가 실행되지 않을 때 어떻게 해야 하나요?

가장 흔한 원인은 경로 문제와 권한 문제예요. 스크립트에 실행 권한이 있는지 확인하고(chmod +x), crontab에는 반드시 절대 경로를 사용하세요. 또 cron은 최소한의 환경변수만 가지고 있어서, 스크립트 상단에 PATH를 명시적으로 지정해주는 것도 도움이 됩니다: PATH=/usr/local/bin:/usr/bin:/bin

마치며

쉘 스크립트로 DB 자동 백업 시스템 만들기는 처음엔 복잡해 보일 수 있지만, 한 번 만들어두면 정말 든든한 안전장치가 됩니다. 저도 처음엔 10줄짜리 간단한 스크립트로 시작했어요. 문제가 생길 때마다 조금씩 개선하다 보니 지금의 완성도 높은 스크립트가 되었습니다.

가장 중요한 건 완벽한 스크립트를 만드는 것보다, 지금 당장 백업을 시작하는 거예요. 간단한 버전이라도 자동 백업이 돌아가고 있다면, 그건 수동 백업을 깜빡하는 것보다 100배 낫습니다.

백업 자동화 체크리스트

  • ✅ 백업 스크립트 작성 및 테스트 완료
  • ✅ 스크립트 실행 권한 부여 (chmod +x)
  • ✅ Crontab에 백업 스케줄 등록
  • ✅ 로그 파일 경로 설정 및 확인
  • ✅ 최소 1회 이상 복구 테스트 완료
  • ✅ 오래된 백업 자동 삭제 설정
  • ✅ 백업 실패 시 알림 설정
  • ✅ 원격 백업 또는 클라우드 백업 설정 (선택)
  • ✅ 월 1회 복구 테스트 일정 등록

추가로 고려할 사항들

여유가 생기면 이런 것들도 추가해보세요:

  • 백업 모니터링 대시보드: Grafana 같은 도구로 백업 상태를 시각화
  • 3-2-1 백업 원칙: 3개의 복사본, 2가지 다른 매체, 1개는 오프사이트
  • 증분 백업 도입: DB 크기가 커지면 전체 백업은 부담스러워요
  • 바이너리 로그 백업: 특정 시점 복구(PITR)가 가능해집니다
  • 백업 암호화: 민감한 데이터라면 필수
  • 복구 시간 목표(RTO) 설정: 얼마나 빨리 복구해야 하는지 미리 정의

데이터는 서비스의 생명입니다. 혹시 아직 백업 시스템이 없으시다면, 이 글을 읽은 지금 바로 시작해보세요. 미래의 당신이 오늘의 당신에게 감사할 거예요. 저도 처음엔 "나중에 해야지" 했다가 큰 낭패를 봤던 기억이 있어서, 여러분은 그런 일을 겪지 않으셨으면 좋겠습니다.

백업은 필요 없을 때까지는 쓸모없어 보이지만, 필요한 순간에는 돈으로도 살 수 없는 가치를 지닙니다. 지금 바로 쉘 스크립트로 DB 자동 백업 시스템 만들기를 시작해보세요!

쉘 스크립트로 DB 자동 백업 시스템 만들기 상세 정보

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤