13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] systemd timer

  • [Linux] LVM 스냅샷 백업으로 Linux 서버 무중단 백업과 복구

    [Linux] LVM 스냅샷 백업으로 Linux 서버 무중단 백업과 복구

    [Linux] LVM 스냅샷 백업으로 Linux 서버 무중단 백업과 복구

    운영 중인 Linux 서버 백업은 늘 같은 딜레마가 있습니다. 서비스를 내리면 백업은 편하지만 운영 현실과는 좀 멀어지죠. 서비스를 계속 열어두면 백업 시점이 흔들리고요. 그래서 저는 LVM 스냅샷 백업을 자주 씁니다. 이 방식이 만능이라서가 아니라, 백업이 읽어야 할 기준 시점을 짧고 또렷하게 고정해주기 때문입니다.

    실무에서 진짜 중요한 건 “스냅샷을 만들었다”가 아닙니다. 스냅샷이 살아 있는 동안 백업을 끝낼 수 있는지, 복구 때 권한과 속성이 그대로 돌아오는지, DB처럼 파일시스템 바깥의 일관성 문제를 따로 통제했는지가 더 중요하거든요. 이 글에서는 LVM 스냅샷 백업을 운영 관점에서 어떻게 설계하고, 어떻게 복구까지 이어가는지 한 흐름으로 정리해보겠습니다. 명령어만 던지는 글보다는, 어디서 자주 깨지는지까지 같이 짚어볼게요.

    LVM 스냅샷 백업 기반 Linux 서버 무중단 백업 아키텍처

    LVM 스냅샷, 운영 볼륨, 백업 저장소, 복구 흐름을 한눈에 보여주는 개요 이미지입니다.

    LVM 스냅샷 백업이 실무에서 통하는 이유와, 안 맞는 상황

    이 방식을 높게 보는 이유는 구조가 단순해서입니다. 운영 볼륨에서 직접 백업을 읽지 않고, 스냅샷을 읽기 전용 기준점으로 삼아 백업 작업을 분리합니다. 서비스는 원본 LV에서 계속 쓰고, 백업 프로세스는 스냅샷에서 읽습니다. 그러면 백업 도중 파일이 바뀌어서 생기는 중간 상태를 줄이기 훨씬 수월합니다.

    다만 많이 오해하는 부분도 있습니다. LVM 스냅샷은 백업 사본이 아닙니다. 스냅샷 LV만 만들어두고 안심하면 안 됩니다. 스냅샷은 원본 변경 블록을 붙잡아두는 임시 장치라서 공간이 차면 무효화될 수 있고, 원본 스토리지 장애까지 막아주지도 못합니다. 그래서 제 기준에선 스냅샷은 “백업을 뜨는 동안만 잠깐 존재해야 하는 작업용 안전장치”에 더 가깝습니다. 이 점을 놓치면 설계가 금방 흔들리더라고요.

    상황 추천 방식 이유 제가 피하는 경우
    일반 웹 서버, 파일 서버 LVM 스냅샷 + rsync 구현이 단순하고 파일 단위 복구가 빠릅니다 백업 시간이 길고 변경량이 큰 대용량 쓰기 워크로드
    MySQL, PostgreSQL 같은 DB 서버 DB 네이티브 백업 + 필요 시 LVM 스냅샷 보조 파일시스템 일관성과 트랜잭션 일관성은 다릅니다 LVM 스냅샷만 믿고 복구 가능하다고 보는 설계
    스토리지 기능이 강한 SAN/NAS 환경 스토리지 스냅샷 우선, LVM은 보조 대규모 환경에선 오프로드 이점이 큽니다 호스트 레벨 작업이 병목이 되는 구조
    단일 디스크 장애까지 대비해야 하는 경우 LVM 스냅샷 + 원격/별도 저장소 복제 같은 VG 안 스냅샷만으로는 재해 대응이 안 됩니다 로컬 디스크 안에만 백업을 두는 구성

    제가 먼저 보는 판단 기준: 스냅샷이 버티는가, 읽기 마운트가 안전한가

    실제 운영에서 핵심은 이 두 가지입니다.

    1. 백업이 끝날 때까지 COW 영역이 살아남는가
    2. 스냅샷을 읽기 전용으로 마운트할 때 파일시스템 특성에 맞는 옵션을 썼는가

    첫 번째는 용량 문제이고, 두 번째는 복구 품질 문제입니다. 스냅샷이 중간에 터지면 백업은 실패입니다. 반대로 스냅샷이 살아 있어도 ACL, xattr, SELinux 컨텍스트가 복구 후 어긋나면 운영 입장에선 실패나 다름없습니다.

    파일시스템별로 마운트 습관도 조금 달라야 합니다. 예를 들어 XFS 스냅샷을 같은 호스트에 읽기 전용 마운트할 때는 보통 <code>nouuid를 같이 고려합니다. 원본과 동일 UUID를 가진 파일시스템을 같은 시스템에서 마운트하려다 막히는 경우가 많기 때문입니다. ext4는 일반적인 파일 복사 백업이라면 ro만으로 충분한 경우가 많지만, 저널 재생 없이 조사성으로 확인해야 하는 작업이라면 noload를 같이 검토합니다. 이런 차이를 모르고 들어가면 “마운트가 왜 안 되지?”에서 시간을 꽤 쓰게 됩니다.

    LVM, 스냅샷, COW를 실무 관점으로 이해해보기

    스냅샷을 깊게 파고들 필요는 없지만, 한 가지만은 정확히 보셔야 합니다. 스냅샷 용량은 원본 크기가 아니라 스냅샷 생성 후 변경될 블록량을 감당하는 공간입니다. 그래서 2TB 원본 볼륨이라고 해서 스냅샷도 무조건 거대해야 하는 건 아닙니다. 반대로 100GB 볼륨이라도 백업 시간 동안 쓰기 폭주가 있으면 작은 스냅샷은 금방 무너집니다.

    • 원본 LV: 서비스가 계속 쓰는 볼륨입니다.
    • 스냅샷 LV: 백업 프로세스가 읽을 시점 기준점입니다.
    • COW 영역: 원본 블록이 바뀌기 전에 기존 내용을 보존하는 공간입니다.

    현장에서 가장 자주 보는 실패는 “원본이 크니까 스냅샷도 크게 잡아야 한다”가 아닙니다. 오히려 “백업은 금방 끝나겠지”라고 가볍게 보고 스냅샷을 너무 작게 잡는 경우가 더 많습니다. 원인은 거의 항상 같습니다. 백업 소요 시간과 그 시간 동안의 쓰기량을 계산하지 않았기 때문입니다. 로그 서버, 업로드가 몰리는 애플리케이션 서버, 배치나 VACUUM이 도는 DB 서버는 이 부분이 특히 민감합니다.

    LVM 스냅샷 백업 구현 전 체크리스트

    작업 전에 확인하는 항목은 아래 다섯 가지입니다. 이 단계가 허술하면 백업보다 복구 때 더 고생합니다.

    1. 대상 마운트가 정말 LVM LV 위에 올라가 있는지 확인합니다.
    2. VG의 VFree가 스냅샷과 메타데이터를 감당할 만큼 남아 있는지 봅니다.
    3. 파일시스템이 ext4인지 XFS인지 확인하고 마운트 옵션을 다르게 잡습니다.
    4. DB나 메시지 큐처럼 쓰기 일관성이 중요한 프로세스는 flush, lock, checkpoint 또는 native backup 절차를 따로 준비합니다.
    5. 백업 결과를 같은 VG가 아닌 별도 디스크나 원격 저장소로 보낼지 결정합니다.
    lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINT
    pvs -o pv_name,vg_name,pv_size,pv_free
    vgs -o vg_name,vg_size,vg_free
    lvs -a -o lv_name,vg_name,lv_size,origin,data_percent,metadata_percent,lv_attr
    findmnt -no SOURCE,TARGET,FSTYPE,OPTIONS /data

    여기서 vgs의 vg_free는 그냥 “남은 공간”이 아니라, 스냅샷이 쓸 생존 예산이라고 보시면 편합니다. findmnt도 꽤 중요합니다. 운영에선 심볼릭 링크, bind mount, 컨테이너 볼륨 때문에 “내가 백업한다고 생각한 경로”와 “실제 파일시스템 경로”가 어긋나는 일이 생각보다 자주 생기거든요.

    실전 구현 1: 스냅샷 생성 전에 정합성 수준부터 정합니다

    이 작업에서 먼저 정하는 건 명령어가 아니라 어느 수준의 정합성을 요구하는지입니다.

    대상 권장 기준 실무 판단 추가 작업
    정적 파일, 문서, 업로드 디렉터리 파일시스템 크래시 일관성 LVM 스냅샷만으로도 충분한 경우가 많습니다 읽기 전용 마운트와 권한 보존 확인
    Nginx/Apache 설정, 일반 앱 배포 파일 파일시스템 일관성 + 서비스 검증 복구 후 설정 테스트가 중요합니다 nginx -t, 서비스 기동 확인
    MySQL/PostgreSQL 데이터 파일 애플리케이션 일관성 LVM 단독으론 불충분할 수 있습니다 flush, checkpoint, dump, native backup 병행

    파일시스템 스냅샷은 어디까지나 파일시스템 관점입니다. DB는 쓰기 캐시, 체크포인트, WAL이나 redo 로그, 버퍼 상태가 얽혀 있어서 “파일이 멈춰 보인다”와 “복구 가능한 상태다”가 같지 않습니다. 그래서 DB 서버에선 LVM 스냅샷을 주력 백업으로 두기보다, 네이티브 백업을 주력으로 두고 LVM은 빠른 파일 보조 복구 수단으로 쓰는 편이 안전합니다.

    실전 구현 2: LVM 스냅샷 생성과 읽기 전용 마운트

    예시는 /dev/vgdata/lvdata를 운영 볼륨으로 가정하겠습니다. 스냅샷은 lvdata_snap, 마운트 지점은 /mnt/backup_snap으로 두겠습니다. ext4와 XFS는 마운트 옵션을 다르게 예시하겠습니다.

    # 공통: 스냅샷 생성
    lvcreate -L 10G -s -n lvdata_snap /dev/vgdata/lvdata
    mkdir -p /mnt/backup_snap
    
    # ext4 예시
    mount -t ext4 -o ro /dev/vgdata/lvdata_snap /mnt/backup_snap
    
    # XFS 예시: 같은 호스트에서 원본과 함께 마운트할 때 nouuid 고려
    # mount -t xfs -o ro,nouuid /dev/vgdata/lvdata_snap /mnt/backup_snap
    
    lvs -a -o lv_name,origin,lv_size,data_percent,metadata_percent,lv_attr /dev/vgdata

    여기서 -L 10G는 샘플일 뿐입니다. 실무에선 이 숫자가 제일 중요합니다. 기준은 “원본 크기”가 아니라 백업이 끝날 때까지 바뀔 블록량입니다. 백업이 40분 걸리고 그 시간 동안 로그 파일과 업로드 파일이 많이 늘어난다면, 스냅샷은 생각보다 빨리 찹니다.

    한 가지는 꼭 바로잡고 싶습니다. 일반적인 LVM 스냅샷 백업에서는 수동 fsfreeze를 기본 절차로 넣지 않는 편이 안전합니다. LVM이 스냅샷 생성 시 파일시스템 freeze를 자동으로 처리하는 경우가 많아서, 이미 얼린 상태에서 다시 lvcreate를 호출하면 대기 상태에 빠질 수 있거든요. 대신 DB처럼 애플리케이션 정합성이 더 중요한 대상은 파일시스템 freeze보다 서비스별 체크포인트나 잠금 절차를 먼저 설계하는 쪽이 낫습니다.

    # 애플리케이션 정합성이 필요할 때는
    # 파일시스템 전체 freeze보다 서비스별 절차를 먼저 검토합니다.
    # 예: PostgreSQL CHECKPOINT, MySQL native backup 또는 flush 전략 확인
    lvcreate -L 10G -s -n lvdata_snap /dev/vgdata/lvdata

    그리고 ACL, xattr, 소유자 보존이 중요한 서버라면 백업과 복구 작업을 root 권한으로 수행하는지도 같이 확인하세요. 옵션만 넣어두고 권한이 부족하면 기대한 복구 품질이 안 나올 수 있습니다.

    LVM 스냅샷 백업 생성과 마운트 절차 이미지

    원본 LV에서 스냅샷을 생성하고 읽기 전용으로 마운트하는 흐름을 설명하는 이미지입니다.

    실전 구현 3: 스냅샷에서 백업을 뜰 때 옵션을 왜 그렇게 주는지

    스냅샷을 마운트했으면 백업은 그 지점에서 읽습니다. 파일 복구 비중이 높은 환경에서는 rsync를 많이 씁니다. 이유는 단순합니다. 권한, 타임스탬프, 하드링크, ACL, xattr를 비교적 일관되게 가져가기 좋고, 복구도 부분 단위로 끊어 하기 쉽습니다. 이 조합은 실제 운영에서 꽤 편하더라고요.

    BACKUP_DIR=/backup/$(date +%F)
    mkdir -p "$BACKUP_DIR"
    
    rsync -aHAX --numeric-ids \
      --info=stats2,progress2 \
      /mnt/backup_snap/ "$BACKUP_DIR/"
    
    sync

    -aHAX는 그냥 관성적으로 붙이는 옵션이 아닙니다. -H는 하드링크, -A는 ACL, -X는 xattr입니다. SELinux를 쓰거나 ACL 기반 권한을 쓰는 서버에선 이 차이가 꽤 큽니다. --numeric-ids도 실무에선 중요할 때가 많습니다. 복원 대상 서버에서 사용자 이름 매핑이 다를 수 있기 때문입니다.

    초안처럼 날짜별 새 디렉터리를 매번 만드는 구조라면 --delete는 보통 불필요합니다. 대상 디렉터리가 매일 새로 생기는데 --delete를 붙여도 얻는 이득이 거의 없습니다. 반대로 같은 미러 디렉터리를 계속 갱신하는 구조라면 --delete가 필요할 수 있지만, 잘못된 경로를 넣었을 때 파괴 범위도 같이 커집니다. 그래서 날짜별 보관과 미러 보관은 목적을 분리하는 편이 안전합니다.

    백업이 끝났으면 스냅샷은 바로 정리합니다.

    umount /mnt/backup_snap
    lvremove -y /dev/vgdata/lvdata_snap

    이건 습관처럼 가져가시는 게 좋습니다. 스냅샷을 오래 들고 가면 원본 쓰기마다 COW 부담이 쌓이고, 결국 성능과 안정성 둘 다 애매해집니다. 짧게 만들고, 빨리 읽고, 바로 제거하는 흐름이 제일 덜 사고 납니다.

    자동화 예시: 실패 시 정리까지 되는 백업 스크립트

    자동화는 단순히 cron이나 timer에 걸어두는 걸 말하지 않습니다. 중간 실패 시 스냅샷과 마운트를 어떻게 치울지까지 포함해야 합니다. 운영에서 진짜 귀찮은 건 백업 실패보다, 실패 뒤에 남은 찌꺼기입니다. 마운트가 남고 스냅샷이 남아 쓰기 성능을 갉아먹는 경우가 생각보다 많습니다.

    #!/usr/bin/env bash
    set -euo pipefail
    
    VG="vgdata"
    ORIGIN="lvdata"
    SNAP="lvdata_snap"
    SNAP_SIZE="10G"
    SOURCE_MNT="/data"
    SNAP_MNT="/mnt/backup_snap"
    BACKUP_ROOT="/backup"
    TODAY="$(date +%F)"
    BACKUP_DIR="$BACKUP_ROOT/$TODAY"
    LV_PATH="/dev/$VG/$ORIGIN"
    SNAP_PATH="/dev/$VG/$SNAP"
    FSTYPE="$(findmnt -no FSTYPE "$SOURCE_MNT")"
    VG_FREE_BYTES="$(vgs --noheadings --units b --nosuffix -o vg_free "$VG" | tr -d ' ')"
    SNAP_SIZE_BYTES="$(numfmt --from=iec "$SNAP_SIZE")"
    
    cleanup() {
      mountpoint -q "$SNAP_MNT" && umount "$SNAP_MNT" || true
      lvs "$SNAP_PATH" >/dev/null 2>&1 && lvremove -y "$SNAP_PATH" || true
    }
    trap cleanup EXIT
    
    if [ "$VG_FREE_BYTES" -le "$SNAP_SIZE_BYTES" ]; then
      echo "Not enough free space in VG $VG" >&2
      exit 1
    fi
    
    mkdir -p "$SNAP_MNT" "$BACKUP_DIR"
    
    lvcreate -L "$SNAP_SIZE" -s -n "$SNAP" "$LV_PATH"
    
    case "$FSTYPE" in
      xfs)
        mount -t xfs -o ro,nouuid "$SNAP_PATH" "$SNAP_MNT"
        ;;
      ext4)
        mount -t ext4 -o ro "$SNAP_PATH" "$SNAP_MNT"
        ;;
      *)
        echo "Unsupported filesystem: $FSTYPE" >&2
        exit 1
        ;;
    esac
    
    rsync -aHAX --numeric-ids --info=stats2 "$SNAP_MNT/" "$BACKUP_DIR/"
    sync
    
    lvs -a -o lv_name,origin,data_percent,metadata_percent,lv_attr "$VG"

    이 스크립트에서 꼭 넣는 건 세 가지입니다. set -euo pipefail, trap cleanup EXIT, 그리고 스냅샷 생성 전 여유 공간 검사입니다. 특히 cleanup trap은 중요합니다. rsync가 중간에 실패하더라도 스냅샷과 마운트가 남지 않게 막아줍니다.

    systemd 타이머는 그대로 써도 되지만, 서비스 유닛에 실패 로그를 남기기 쉽게 구성해두면 운영 추적이 편합니다. 이 블로그의 rsync 증분 백업 가이드나 systemd timer 운영 글이 있다면 내부 링크로 같이 묶어두는 것도 추천합니다. 검색 유입 이후에 다음 글로 자연스럽게 넘어가더라고요.

    # /etc/systemd/system/lvm-snapshot-backup.service
    [Unit]
    Description=LVM snapshot backup job
    After=local-fs.target
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/sbin/lvm-snapshot-backup.sh
    
    # /etc/systemd/system/lvm-snapshot-backup.timer
    [Unit]
    Description=Run LVM snapshot backup daily
    
    [Timer]
    OnCalendar=*-*-* 02:30:00
    Persistent=true
    
    [Install]
    WantedBy=timers.target
    chmod +x /usr/local/sbin/lvm-snapshot-backup.sh
    systemctl daemon-reload
    systemctl enable --now lvm-snapshot-backup.timer
    systemctl status lvm-snapshot-backup.timer
    systemctl list-timers --all | grep lvm-snapshot-backup

    systemctl status와 list-timers를 둘 다 보는 이유도 단순합니다. 타이머가 로드됐는지와 다음 실행 시각이 잡혔는지는 따로 확인하는 편이 실수를 줄여주거든요.

    주의사항과 트러블슈팅: LVM 스냅샷 백업에서 자주 깨지는 지점

    운영에서 자주 깨지는 지점은 대체로 아래 다섯 가지였습니다. 겉증상보다 원인을 먼저 보셔야 대응이 빨라집니다.

    • VG 여유 공간 부족: 원인은 단순히 디스크 부족이 아니라, 스냅샷 크기 산정이 쓰기량 기준이 아니었기 때문입니다.
    • 스냅샷 Data% 급상승: 백업이 느리거나, 백업 시간대의 쓰기 패턴을 과소평가한 경우가 많습니다.
    • XFS 스냅샷 마운트 실패: 같은 UUID 파일시스템 중복 마운트 문제를 놓친 경우가 흔합니다.
    • 복구 후 권한이나 컨텍스트 이상: rsync 옵션에서 ACL이나 xattr 보존을 빼먹었거나, 복구 대상 시스템 정책이 달랐던 경우입니다.
    • 백업 성공, 복구 실패: 파일 복사는 끝났지만 애플리케이션 기동 검증이 없었던 경우입니다.

    자주 보는 모니터링 명령은 아래입니다.

    lvs -a -o lv_name,origin,lv_size,data_percent,metadata_percent,lv_attr /dev/vgdata
    journalctl -u lvm-snapshot-backup.service -n 50 --no-pager
    1. data_percent가 계속 오르면 스냅샷이 변경 블록을 빠르게 소비하고 있다는 뜻입니다.
    2. data_percent가 100에 가까워지면 스냅샷 무효화 위험이 큽니다. 이때는 스냅샷 크기를 키우거나, 백업 속도를 올리거나, 백업 시간대를 바꾸는 쪽으로 접근합니다.
    3. metadata_percent는 스냅샷 유형과 LVM 버전에 따라 표시되지 않거나 의미가 다를 수 있으니, 항상 data_percent와 함께 해석합니다.
    4. lv_attr 값이 평소와 다르면, 특히 snapshot 관련 속성이 예상과 다르면 스냅샷 상태 이상부터 의심합니다.

    제 판단은 꽤 단순합니다. 스냅샷 크기를 무작정 키우는 것보다, 백업 시간을 줄이거나 쓰기 피크를 피하는 게 먼저입니다. 스냅샷을 크게 잡는 건 임시 처방이지 구조적 해결은 아닙니다.

    그리고 파일 복구와 볼륨 롤백은 완전히 다른 작업입니다. 이 둘을 섞어 생각하시면 운영 반영 시점에서 사고가 납니다.

    복구 방식 적합한 상황 주요 도구 리스크 포인트
    파일 단위 복구 설정 파일, 업로드 디렉터리, 일부 데이터만 되살릴 때 rsync, cp, tar 권한, ACL, xattr, 서비스 재기동 검증 누락
    스냅샷 병합 롤백 볼륨 전체를 특정 시점으로 되돌려야 할 때 lvconvert –merge 운영 중인 origin 반영 시점, 재활성화나 재부팅 절차
    LVM 스냅샷 백업 Data 퍼센트 모니터링 대시보드

    스냅샷 사용량 증가와 경고 상태를 관찰하는 모니터링 예시 이미지입니다.

    LVM 복구 시나리오 1: 파일 단위 복원

    실제 장애는 대부분 전체 롤백까지 갈 필요가 없습니다. 설정 파일 하나, 업로드 경로 일부, 잘못 덮어쓴 정적 자산 몇 개처럼 부분 복구가 더 많습니다. 이럴 때 LVM 스냅샷 기반 백업은 꽤 강합니다. 백업을 통째로 되돌리지 않고 필요한 경로만 살릴 수 있어서 영향 범위를 줄이기 쉽습니다.

    rsync -aHAX --numeric-ids /backup/2026-08-16/etc/nginx/ /etc/nginx/
    rsync -aHAX --numeric-ids /backup/2026-08-16/data/uploads/ /data/uploads/
    
    nginx -t
    systemctl reload nginx

    복구 직후엔 파일 존재 여부만 보면 부족합니다. 최소한 설정 문법 검사, 서비스 reload 또는 재기동, 실제 read/write 동작 확인까지 보셔야 합니다. 파일은 돌아왔는데 애플리케이션 권한이 막혀서 실패하는 경우도 생각보다 많습니다.

    LVM 복구 시나리오 2: 스냅샷 병합으로 시점 롤백

    볼륨 전체를 특정 시점으로 되돌려야 한다면 lvconvert --merge를 씁니다. 다만 이건 영향도가 큽니다. 가볍게 권하기 어려운 이유도 명확합니다. merge는 파일 몇 개를 되돌리는 작업이 아니라, origin LV 전체 상태를 되감는 작업이기 때문입니다.

    umount /data
    lvchange -an /dev/vgdata/lvdata
    lvconvert --merge /dev/vgdata/lvdata_snap
    lvchange -ay /dev/vgdata/lvdata
    mount /dev/vgdata/lvdata /data

    환경에 따라 merge 반영 시점은 즉시가 아니라 다음 활성화 시점이 될 수 있습니다. 특히 origin LV가 열려 있으면 더 조심하셔야 합니다. 루트 파일시스템이 걸린 경우라면 유지보수 창, rescue 모드, 재부팅 절차까지 포함해서 반드시 사전 검증하는 편이 안전합니다.

    검증: 백업 성공보다 복구 성공 신호를 봅니다

    운영에선 “백업 로그가 성공으로 끝났다”보다 “복구 검증이 통과했다”가 훨씬 중요합니다. 최소 기준으로 잡는 항목은 아래 네 가지입니다.

    1. rsync 종료 코드와 systemd 서비스 종료 상태를 확인합니다.
    2. 백업 사본에서 샘플 파일을 실제로 열어 읽어봅니다.
    3. 권한, 소유자, 심볼릭 링크, ACL, xattr가 유지됐는지 확인합니다.
    4. 복구 테스트 환경에서 서비스가 떠서 실제 요청을 처리하는지 확인합니다.
    echo $?
    getfacl /data/somefile
    getfattr -d /data/somefile || true
    find /backup/$(date +%F) -maxdepth 2 | head
    systemctl status lvm-snapshot-backup.service --no-pager

    echo $?가 0이 아니면 백업 작업은 실패로 보는 편이 맞습니다. getfacl이나 getfattr 결과가 기대와 다르면, 복구 후 접근 제어 문제가 날 가능성이 큽니다. 그리고 복구 테스트는 프로세스가 떴는지만 보면 부족합니다. 웹 서비스라면 실제 요청을 보내보고, 업로드 경로라면 테스트 파일 생성과 삭제까지 해보는 쪽이 훨씬 현실적입니다.

    LVM 스냅샷 백업 검증과 복구 테스트 체크리스트

    백업 성공 여부보다 복구 가능성을 점검하는 체크리스트를 요약한 이미지입니다.

    실무 추천 시나리오: LVM 스냅샷 백업은 언제 쓰면 좋을까

    운영에서 내리는 추천은 비교적 분명합니다.

    • 일반 웹 서버, 파일 서버, 홈랩: LVM 스냅샷 + rsync 조합이 가장 균형이 좋습니다. 구현 난이도 대비 복구 유연성이 좋습니다.
    • 트랜잭션 정합성이 중요한 DB 서버: DB 네이티브 백업을 주력으로 두고, LVM 스냅샷은 파일 단위 보조 복구나 빠른 시점 확보 수단으로 쓰는 편이 안전합니다.
    • 백업 창이 길고 쓰기량이 높은 서버: 스냅샷 크기를 키우기 전에 백업 시간대 조정, 대상 분리, 백업 속도 개선부터 보시는 게 맞습니다.
    • 디스크 장애나 호스트 장애까지 대비해야 하는 환경: 로컬 스냅샷만으로 끝내지 말고 원격 저장소 복제를 붙이셔야 합니다.

    실무에서 느끼는 건 늘 비슷합니다. 빠르게 시점을 고정하는 기술, 사본을 오래 보관하는 기술, 서비스를 다시 살리는 기술은 서로 다릅니다. LVM 스냅샷은 첫 번째에 강합니다. 그래서 잘 쓰면 진짜 편하지만, 혼자 모든 걸 해결해주진 않습니다.

    추천을 한 줄로 좁히면 이렇습니다. 운영 파일 백업이라면 LVM 스냅샷을 짧게 만들고 rsync로 빠르게 뽑으세요. DB라면 그 위에 네이티브 백업을 얹으세요. 그리고 어떤 경우든 복구 리허설을 백업 성공보다 우선순위 높게 두세요.

    자주 묻는 질문

    LVM 스냅샷 백업만 있으면 충분한가요?

    아닙니다. 스냅샷은 시점 확보 장치이고, 실제 백업 사본과 복구 검증이 함께 있어야 의미가 있습니다. 같은 VG 안에만 결과를 두는 구성도 재해 대응 관점에선 부족합니다.

    XFS에서도 쓸 수 있나요?

    가능합니다. 다만 같은 호스트에 원본과 스냅샷을 함께 마운트할 때는 nouuid를 검토하셔야 합니다. 파일시스템 일관성과 애플리케이션 정합성은 별개라는 점도 그대로 유효합니다.

    운영 중 성능 영향은 없나요?

    영향이 0은 아닙니다. 스냅샷 유지 시간이 길수록, 그리고 원본 쓰기량이 많을수록 COW 부담이 커집니다. 그래서 “짧게 생성, 빠르게 백업, 즉시 제거”가 가장 안전한 운영 패턴입니다.

  • [Linux] systemd timer vs Cron: 리눅스 작업 스케줄러 성능 및 자원 비교

    [Linux] systemd timer vs Cron: 리눅스 작업 스케줄러 성능 및 자원 비교

    [리눅스] systemd timer vs Cron 비교: 작업 스케줄러 성능 및 자원 사용량

    리눅스 서버를 오래 굴리다 보면 결국 한 번은 붙잡게 되는 주제가 있습니다. 바로 systemd timer Cron 비교입니다. 백업, 로그 정리, 캐시 삭제, 인증서 갱신 같은 작업 자동화는 작아 보여도 장애를 막는 핵심 축이거든요. 저도 처음엔 Cron(크론, 전통적인 작업 스케줄러)만 익숙해서 그냥 crontab부터 열었었는데, systemd timer(시스템디 타이머, systemd 기반 스케줄링)는 또 다른 장점이 분명하더라고요. 특히 서비스 단위 관리, 로그 추적, 의존성 처리에서 차이가 꽤 크거든요.

    이번 글은 단순 기능 소개가 아니라, 리눅스 스케줄러를 실제 운영 관점에서 어떻게 비교해야 하는지, 그리고 성능 벤치마크를 할 때 무엇을 봐야 하는지에 초점을 맞췄습니다. 숫자를 억지로 꾸며 넣는 대신, 제가 홈랩에서 비교할 때 사용한 방식과 해석 포인트를 정리해보겠습니다. 혹시 스케줄러 바꿨다가 로그 찾느라 삽질해보신 적 있으신가요? 그 마음 제가 잘 압니다 ㅎㅎ

    systemd timer Cron 비교를 보여주는 리눅스 스케줄링 개요 다이어그램

    systemd timer와 Cron이 각각 어떤 흐름으로 작업을 실행하는지 보여주는 개요 이미지입니다.

    1. 왜 systemd timer vs Cron 비교가 중요한가

    쉽게 말해 Cron은 시간이 되면 명령어를 실행하는 데 특화되어 있고, systemd timer는 서비스 단위로 작업을 관리하는 데 강하죠. 둘 다 예약 실행은 되지만, 운영에서 중요한 건 그 다음입니다. 실패했을 때 어디서 로그를 볼지, 부팅 직후 누락된 작업을 보정할지, 프로세스 제한을 걸 수 있는지, 다른 서비스가 올라온 뒤에만 실행할지 같은 부분이요.

    • Cron: 단순하고 가볍고 쓰기 편하죠.
    • systemd timer: 추적성과 제어성이 좋거든요.
    • 운영 포인트: 성능 차이보다 관리 편의성 차이가 더 크게 느껴지는 경우가 많습니다.

    여기서 중요한 포인트! 많은 분들이 systemd가 무조건 무겁다고 생각하시는데, 실제로는 작업 자체의 비용보다 어떻게 프로세스를 감싸고 기록하느냐의 차이예요. 이 부분을 제대로 이해하면 선택이 훨씬 쉬워집니다.

    2. 개념 설명: Cron과 systemd timer를 쉽게 말해보면

    Cron은 오래된 표준입니다. <code>* * * * * 같은 표현으로 시간을 적고 명령을 실행하죠. 반면 systemd timer는 .service 파일과 .timer 파일을 분리해서 써요. 처음엔 이게 뭔가 싶었는데, 실제로 써보니까 역할이 나뉘어 있어서 나중에 유지보수할 때 편하더라고요.

    항목 Cron systemd timer
    설정 방식 crontab 한 줄 .service + .timer 파일
    로그 확인 메일 또는 리다이렉션 필요 journalctl(저널ctl, systemd 로그 조회)로 추적 가능
    의존성 처리 제한적 After=, Wants= 등으로 제어 가능
    누락 실행 보정 기본적으로 약함 Persistent=true 지원
    리소스 제어 쉘 수준 처리 위주 CPUQuota=, MemoryMax= 등 cgroup 기반 제어 가능
    진입 장벽 낮음 초반 학습 필요

    systemd timer Cron 비교를 할 때 핵심은 “무엇이 더 빠른가” 하나만 보면 안 된다는 점입니다. 실행 지연(latency, 지연 시간), 프로세스 생성 오버헤드, 로그 추적성, 실패 복구성까지 같이 봐야 제대로 판단할 수 있거든요.

    3. 벤치마크 기준: 성능 및 자원 비교는 무엇을 봐야 하나

    성능 벤치마크라고 하면 보통 처리량부터 떠올리는데, 스케줄러는 조금 달라요. 작업 자동화에서는 아래 기준이 더 실무적입니다.

    1. 실행 정확성: 예약한 시점에 얼마나 정확하게 시작되는가
    2. 오버헤드: 짧은 작업을 실행할 때 추가 비용이 얼마나 붙는가
    3. 로그 가시성: 실패 원인을 얼마나 빨리 찾을 수 있는가
    4. 자원 사용량: 메모리, 프로세스 수, cgroup 제어 가능 여부
    5. 운영 편의성: 배포, 수정, 재시작, 권한 관리가 쉬운가

    제가 직접 체크할 때는 아주 짧은 작업 하나와, 조금 긴 백업성 작업 하나를 나눠서 봅니다. 왜냐하면 짧은 작업에서는 스케줄러 자체의 오버헤드가 더 눈에 띄고, 긴 작업에서는 스케줄러보다 실제 작업 로직이 훨씬 큰 비중을 차지하거든요.

    💡 팁: 성능 벤치마크를 한다면 숫자 하나만 보지 말고 time, journalctl, systemctl status, ps, /usr/bin/time -v를 같이 보는 게 좋아요.

    4. 실전 구현: Cron 방식으로 작업 자동화 구성하기

    먼저 Cron 예시입니다. 가장 익숙한 방식이죠. 예제 작업은 매 5분마다 타임스탬프를 남기는 간단한 스크립트로 잡아보겠습니다.

    mkdir -p ~/scheduler-test
    cat > ~/scheduler-test/job.sh <<'EOF'
    #!/usr/bin/env bash
    set -eu
    printf '%s cron job executed\n' "$(date --iso-8601=seconds)" >> /tmp/scheduler-test.log
    EOF
    chmod +x ~/scheduler-test/job.sh

    이제 crontab에 등록합니다.

    crontab -e
    */5 * * * * /home/USER/scheduler-test/job.sh

    여기서 흔한 삽질이 하나 있어요. Cron은 로그인 셸(login shell)이 아니기 때문에 환경 변수(Environment Variable, 환경 변수)가 생각보다 비어 있습니다. PATH가 달라서 명령을 못 찾는 경우가 진짜 자주 나와요. 저도 처음엔 스크립트는 잘 도는데 Cron에서만 실패해서 한참 봤었네요.

    • 명령어는 가능하면 절대 경로를 써요.
    • 로그 파일 리다이렉션을 명시합니다.
    • 실패 시 메일 설정 또는 별도 알림을 붙여야 해요.
    systemd timer Cron 비교 글의 Cron 설정 예시 이미지

    Cron 작업 등록과 기본 실행 흐름을 이해하기 쉽게 보여주는 예시 이미지입니다.

    5. 실전 구현: systemd timer 방식으로 구성하기

    이번엔 같은 작업을 systemd timer로 옮겨보겠습니다. 파일이 둘로 나뉘니까 복잡해 보이지만, 한 번 패턴 잡히면 오히려 정리가 잘 되거든요.

    5-1. service 파일 작성

    # /etc/systemd/system/scheduler-test.service
    [Unit]
    Description=Scheduler test job
    
    [Service]
    Type=oneshot
    ExecStart=/home/USER/scheduler-test/job.sh
    User=USER
    Group=USER

    5-2. timer 파일 작성

    # /etc/systemd/system/scheduler-test.timer
    [Unit]
    Description=Run scheduler test every 5 minutes
    
    [Timer]
    OnCalendar=*:0/5
    Persistent=true
    Unit=scheduler-test.service
    
    [Install]
    WantedBy=timers.target

    5-3. 활성화 및 확인

    sudo systemctl daemon-reload
    sudo systemctl enable --now scheduler-test.timer
    systemctl list-timers --all | grep scheduler-test
    systemctl status scheduler-test.timer

    실제로 써보니까 여기서 편한 건 딱 세 가지였어요. 첫째, 로그 추적이 쉽거든요. 둘째, 서비스 단위 재실행이 쉽고요. 셋째, 리소스 제한을 붙이기 좋아요. 예를 들어 아래처럼 제어할 수 있거든요.

    [Service]
    Type=oneshot
    ExecStart=/home/USER/scheduler-test/job.sh
    CPUQuota=20%
    MemoryMax=128M
    NoNewPrivileges=true

    이 부분은 Cron보다 systemd 쪽이 확실히 운영 친화적이에요. 특히 여러 작업이 섞이는 서버에서는 누가 언제 뭘 실행했는지 보기가 훨씬 수월합니다.

    6. ⚠️ 주의사항과 트러블슈팅: 제가 자주 겪었던 문제들

    여기서부터가 진짜 실전입니다. 문서만 보면 쉬워 보이는데, 현장에서는 자잘한 문제들이 계속 나와요.

    6-1. Cron은 환경 변수가 다릅니다

    문제: 터미널에서는 되는데 Cron에서 실패합니다.

    원인: PATH, HOME, locale(로케일, 지역화 설정)이 다를 수 있어요.

    해결: 스크립트 상단에 필요한 환경을 명시하고, 명령어 절대 경로를 사용합니다.

    #!/usr/bin/env bash
    export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    set -eu

    6-2. systemd timer는 service 파일과 짝이 맞아야 합니다

    문제: 타이머는 살아 있는데 작업이 실행되지 않아요.

    원인: Unit= 이름이 다르거나 ExecStart 경로가 틀린 경우가 많거든요.

    해결: systemctl status와 journalctl -u scheduler-test.service를 같이 봐요.

    6-3. 부팅 중 누락 작업은 해석이 다릅니다

    Cron은 시스템이 꺼져 있던 동안의 스케줄을 기본적으로 보정하지 않아요. 반면 systemd timer의 Persistent=true는 누락된 실행을 어느 정도 메워줍니다. 백업이나 동기화 작업처럼 “한 번은 꼭 돌아야 하는” 작업이면 이 차이가 꽤 크거든요.

    • Cron 적합: 단순 정리 작업, 개인 계정 배치
    • systemd 적합: 서비스와 연동된 운영 작업, 추적이 중요한 작업
    systemd timer Cron 비교에서 systemd timer 구성과 로그 흐름을 보여주는 다이어그램

    systemd timer 구성 요소와 로그 확인 포인트를 한 번에 보여주는 다이어그램입니다.

    7. 검증 및 결과: 무엇을 확인하면 비교가 되는가

    이제 결과를 봐야겠죠. 다만 여기서 조심할 점이 있어요. 자원 사용량과 실행 지연은 배포판, systemd 버전, 파일시스템 상태, CPU 절전 정책에 따라 달라집니다. 그래서 저는 특정 숫자를 일반화하기보다, 아래 체크리스트 기준으로 해석하는 편을 권해요.

    1. 스케줄 등록 확인: crontab -l, systemctl list-timers
    2. 실행 이력 확인: 로그 파일, journalctl -u 서비스명
    3. 실행 시간 측정: /usr/bin/time -v로 스크립트 자체 비용 확인
    4. 프로세스 추적: ps -ef, systemd-cgls로 실행 구조 확인
    journalctl -u scheduler-test.service --since today
    systemctl status scheduler-test.service
    /usr/bin/time -v /home/USER/scheduler-test/job.sh

    제가 실무에서 해석하는 기준은 이렇습니다.

    비교 포인트 보통 유리한 쪽 해석
    초기 설정 단순함 Cron 한 줄로 끝나는 작업은 여전히 편해요.
    장애 분석 속도 systemd timer journalctl 기반 추적이 강하죠.
    리소스 제어 systemd timer cgroup 정책을 붙이기 좋거든요.
    짧은 개인 작업 Cron 학습 비용이 낮은 편입니다.
    운영 표준화 systemd timer 서비스 단위 관리가 깔끔해요.

    🎉 정리하면, systemd timer Cron 비교에서 절대적인 승자는 없습니다. 대신 운영 규모가 커질수록 systemd timer 쪽의 장점이 더 또렷하게 보여요. 반대로 가벼운 서버나 개인 계정 자동화라면 Cron이 아직도 충분히 실용적입니다.

    systemd timer Cron 비교의 성능 벤치마크 검증 결과를 표현한 대시보드 이미지

    실행 상태, 로그, 자원 사용량 확인 포인트를 대시보드 형태로 정리한 결과 이미지입니다.

    8. 정리 및 FAQ: 어떤 기준으로 선택하면 되나

    마지막으로 제가 멘토링할 때 가장 많이 드리는 기준을 남겨보겠습니다. 저도 처음엔 Cron만 썼는데, 서비스 운영 범위가 넓어지면서 systemd timer로 조금씩 옮겼거든요. 드디어 기준이 잡히고 나니까 선택이 쉬워졌어요.

    • 단순한 작업 자동화가 필요하면 Cron으로 시작해도 됩니다.
    • 로그 추적, 실패 복구, 의존성 관리가 중요하면 systemd timer가 나아요.
    • 리눅스 스케줄러를 팀 표준으로 맞춘다면 systemd 방식이 문서화하기 편합니다.
    • 성능 벤치마크는 숫자 경쟁보다 운영 관찰 가능성까지 함께 봐야 하고요.

    자주 묻는 질문

    Q. Cron이 systemd timer보다 항상 가볍나요?
    꼭 그렇진 않아요. 짧은 작업에서는 체감 차이가 있을 수 있지만, 대부분은 실제 작업 로직이 더 큰 비중을 차지합니다.

    Q. 기존 Cron을 전부 systemd timer로 바꿔야 하나요?
    아니에요. 운영상 이점이 큰 작업부터 옮기면 돼요. 예를 들면 백업, 동기화, 서비스 연계 배치처럼요.

    Q. 둘을 같이 써도 되나요?
    물론이죠. 저도 실제로는 혼용하는 편입니다. 다만 동일한 작업이 중복 실행되지 않게 기준은 분명히 잡아야 해요.

    다음 글에서는 systemd service 하드닝(hardening, 보안 강화)이나 백업 배치 표준화 쪽을 따로 다뤄볼 예정입니다. 이전 글에서 다뤘던 로그 관리와 묶어서 보면 더 이해가 잘 될 거예요. 혹시 지금 운영 중인 서버에서 어느 쪽이 맞을지 고민된다면, 먼저 “실패했을 때 얼마나 빨리 원인을 찾을 수 있나”부터 따져보세요. 그 질문 하나가 생각보다 방향을 잘 잡아줍니다.

    systemd timer Cron 비교의 선택 기준과 장단점을 정리한 인포그래픽

    Cron과 systemd timer 선택 기준을 빠르게 판단할 수 있도록 요약한 인포그래픽입니다.