[Oracle] RMAN으로 백업 및 복구하기

예전 글에서는 Oracle Data Pump 유틸리티(expdp/impdp)를 사용하여 스키마를 이전하는 절차를 알아봤는데요, 이번 글에서는 RMAN으로 Oracle Database를 백업 및 복구하늕 절차를 정리해 보고자 합니다. 아직까지 백업/복구 모의훈련을 위한 가상서버(VM)가 준비되지 않아서 먼저 정리를 하고, VM이 준비되면 모의훈련을 하면서 부족한 부분을 보충해 나갈 예정입니다. 모의훈련이 끝나면 백업/복구 절차가 검증되었다고 이 글에 남기도록 하겠습니다. 혹시 전문DBA께서 이 글을 보셨다면 부족한 부분에 많은 의견부탁드립니다.

  1. RMAN 환경 구성 및 기본 사용법 알아보기
  2. RMAN으로 백업하기
  3. RMAN으로 복구하기
    1. 전체 복구하기
    2. 특정 데이터파일만 복구하기
    3. 다른 디스크에 복구하기
    4. 다른 데이터베이스 서버에 복구하기(복제 및 이관)

1. RMAN 환경 구성 및 기본 사용법 알아보기

  1. SID 확인: $ORACLE_SID는 v$instance 뷰를 통해 확인합니다.
    SQL> SELECT instance_name AS 운영SID FROM v$instance;
    
  2. LOG모드 확인: ARCHIVELOG인지 확인합니다.
    SQL> SELECT LOG_MODE, OPEN_MODE FROM V$DATABASE;
    LOG_MODE     OPEN_MODE
    ------------ --------------------
    ARCHIVELOG   READ WRITE
    
    --또는
    
    SQL> archive log list;
    Database log mode              Archive Mode
    Automatic archival             Enabled
    Archive destination            USE_DB_RECOVERY_FILE_DEST
    Oldest online log sequence     97419
    Next log sequence to archive   97423
    Current log sequence           97423
    
  3. Retention Policy 설정: 백업본을 며칠간 보관할지 결정하세요. (예: 7일)
    RMAN> CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS;
    
  4. Controlfile Autobackup: DB 구조 변경 시 백업이 자동 생성되도록 설정하세요.
    RMAN> CONFIGURE CONTROLFILE AUTOBACKUP ON;
    
  5. 병렬 처리(PARALLELISM) 설정: 채널을 2개 할당하여 백업 속도를 높이면서도 서비스 부하를 고려합니다.
    RMAN> show device type; 명령으로 병렬 처리 채널를 확인할 수 있습니다.
    RMAN> CONFIGURE DEVICE TYPE DISK PARALLELISM 2;
    
  6. 백업 효율 극대화: 동일한 읽기 전용(Read-Only) 테이블스페이스나 이미 백업된 아카이브 로그 등을 지능적으로 제외하므로, 특히 매일 아카이브 로그를 백업하는 환경에서 불필요한 I/O를 획기적으로 줄여줍니다.
    RMAN> CONFIGURE BACKUP OPTIMIZATION ON;
    

2. RMAN으로 백업하기

  • 아래 스크립트는 증분백업(Incremental backup) 전략을 사용합니다. 일요일은 풀백업, 월요일~토요일에는 증분백업 전략으로 구성하였습니다.
    #!/bin/bash
    # ========================================================
    # Script File Name: integrated_rman_backup.sh
    # Purpose         : Automated Incremental Backup (Sun:Full, Mon~Sat:Incremental)
    # ========================================================
    
    # 1. Environment Configuration
    export ORACLE_BASE=/u01/app/oracle
    export ORACLE_HOME=$ORACLE_BASE/product/11.2.0.4/dbhome_1/
    export ORACLE_SID=CMAIN_2
    export PATH=$ORACLE_HOME/bin:$PATH
    export BASE_PATH=$(cd "$(dirname "$0")" && pwd)
    export BACKUP_ROOT="/nas/backup/orabackup/$ORACLE_SID"
    export DATE_DIR=$(date +%Y-%m-%d)
    export FULL_PATH="$BACKUP_ROOT/$DATE_DIR"
    export LOG_FILE="${BASE_PATH}/rman_backup_total.log"
    
    # Weekday (1:Mon, ..., 7:Sun)
    DAY_OF_WEEK=$(date +%u)
    
    # Sun: Full Backup, Mon~Sat: Incremental Backup
    # %d: Database Name
    # %U: Unique Identifier created by system
    if [ $DAY_OF_WEEK -eq 7 ]; then
        BACKUP_CMD="BACKUP INCREMENTAL LEVEL 0 DATABASE FORMAT '$FULL_PATH/L0_%d_%U' TAG 'WEEKLY_FULL_L0';"
        MODE="Full(L0)"
    else
        BACKUP_CMD="BACKUP INCREMENTAL LEVEL 1 DATABASE FORMAT '$FULL_PATH/L1_%d_%U' TAG 'DAILY_INCR_L1';"
        MODE="Incr(L1)"
    fi
    
    mkdir -p $FULL_PATH
    
    echo "=========================================================" >> $LOG_FILE
    echo "--- Backup Started at $(date '+%Y-%m-%d %H:%M:%S') ---" >> $LOG_FILE
    echo "--- Mode: $MODE ---" >> $LOG_FILE
    
    # 2. RMAN Execution
    rman target / <> $LOG_FILE
    # [운영 최적화 설정] : RMAN 기본 운영환경 변경
    #CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS;
    #CONFIGURE CONTROLFILE AUTOBACKUP ON;
    #CONFIGURE DEVICE TYPE DISK PARALLELISM 2;
    #CONFIGURE BACKUP OPTIMIZATION ON;
    
    # [상태 점검]
    CROSSCHECK BACKUP;
    CROSSCHECK ARCHIVELOG ALL;
    CROSSCHECK COPY OF CONTROLFILE;
    
    # [백업 실행] 쉘 변수로 전달받은 명령 실행
    # FORMAT : 백업파일 저장 경로 설정
    # DELETE INPUT : 아카이브 로그를 백업 세트 안에 포함시킨 후 원본을 자동 삭제
    RUN {
        $BACKUP_CMD
        BACKUP ARCHIVELOG ALL FORMAT '$FULL_PATH/ARC_%d_%U' DELETE INPUT;
    }
    
    # [사후 정리] 
    DELETE NOPROMPT EXPIRED BACKUP;
    DELETE NOPROMPT EXPIRED ARCHIVELOG ALL;
    DELETE NOPROMPT EXPIRED COPY OF CONTROLFILE;
    
    REPORT OBSOLETE;
    DELETE NOPROMPT OBSOLETE;
    
    # [15일 경과 강제 삭제] RETENTION POLICY에도 불구하고 삭제되지 않는 데이터파일 삭제
    DELETE NOPROMPT BACKUP COMPLETED BEFORE 'sysdate - 15';
    DELETE NOPROMPT ARCHIVELOG ALL COMPLETED BEFORE 'sysdate - 15';
    
    EXIT;
    EOF
    
    echo "--- Backup Finished at $(date '+%Y-%m-%d %H:%M:%S') ---" >> $LOG_FILE
    echo "=========================================================" >> $LOG_FILE
    
  • crontab에 등록하여 매일 자동으로 실행합니다.
  • 직접 위 백업 스크립트를 실행했다면 아래 쿼리를 통해 현재 병렬로 작동 중인 채널의 수를 확인할 수 있습니다.
    SELECT SID, SERIAL#, CONTEXT, SOFAR, TOTALWORK, ROUND(SOFAR/TOTALWORK*100, 2) AS "%_COMPLETE"
    FROM V$SESSION_LONGOPS
    WHERE OPNAME LIKE 'RMAN%'
      AND TOTALWORK > 0
      AND SOFAR < TOTALWORK;
    

3-1. 전체 복구하기

  • 테이테베이스를 MOUNT 상태로 올린 후 복구를 시작하세요.
    RMAN> SHUTDOWN ABORT; (이미 DB가 shutdown 상태라면 생략)
    RMAN> STARTUP MOUNT;
    RMAN> RESTORE DATABASE;
    RMAN> RECOVER DATABASE;
    RMAN> ALTER DATABASE OPEN;
    

3-2. 특정 데이터파일만 복구하기

  • V$RECOVER_FILE 뷰 조회 시 ERROR 컬럼이 OFFLINE NORMAL인 경우는 관리자에 의한 정상적 오프라인 상태이며, 그 외 CANNOT OPEN, FILE NOT FOUND, I/O ERROR 등의 메시지가 발생할 경우에만 실제 물리적 장애로 간주하여 RMAN 복구 절차를 수행합니다.
    SELECT file#, ERROR 
    FROM   v$recover_file
    WHERE  error <> 'OFFLINE NORMAL';
    
  • sqlplus / as sysdba에서 쿼리를 실행해 스크립트를 추출한 후, rman target /에 접속하여 FILE_OFFLINE -> RMAN_RESTOR -> RMAN_RECOVER -> FILE_ONLINE 순으로 실행합니다.
    SELECT d.name AS DATAFILE_NAME, 
           'ALTER DATABASE DATAFILE ' || r.file# || ' OFFLINE;' AS FILE_OFFLINE,
           'RESTORE DATAFILE ' || r.file# || ';' AS RMAN_RESTOR,
           'RECOVER DATAFILE ' || r.file# || ';' AS RMAN_RECOVER,
           'ALTER DATABASE DATAFILE ' || r.file# || ' ONLINE;' AS FILE_ONLINE
    FROM   v$datafile d,
           v$recover_file r
    WHERE  d.file# = r.file#
    AND    r.error <> 'OFFLINE NORMAL';
    

3-3. 다른 디스크에 복구하기

원래 데이터파일이 있던 디스크가 물리적으로 파손되었거나(전체 복구), 용량 부족으로 인해 새로운 경로로 파일을 옮겨서 복구(데이터파일 복구)해야 할 때 사용합니다. 단순히 RESTORE만 하면 원래 경로로 돌아가려 하기 때문에, RMAN에게 “백업본을 이 새로운 경로에 풀어라”라고 명령하는 것이 핵심입니다.

  • 전체 데이터베이스를 다른 디스크에 복구하려면,3-1 전체 복구하기“와 동일하게 테이테베이스는 MOUNT 상태여야 합니다.
    -- SET NEWNAME : 모든 데이터 파일들의 새 위치를 '/path/to/%U'로 지정합니다. ASM(Automatic Storage Management) 환경에서는 '+DATA'로 변경합니다.
    -- SWITCH DATAFILE ALL : 데이터 파일의 새 위치를 인식하도록 control file을 업데이트합니다.
    RMAN> SHUTDOWN ABORT; (이미 DB가 shutdown 상태라면 생략)
    RMAN> STARTUP MOUNT;
    RMAN> RUN {
        SET NEWNAME FOR DATABASE TO '/path/to/%U';
        RESTORE DATABASE;
        SWITCH DATAFILE ALL;
        RECOVER DATABASE;
    }
    RMAN> ALTER DATABASE OPEN;
    
  • 특정 데이터파일/테이블스페이스만 다른 디스크로 복구하려면,3-2. 특정 데이터파일만 복구하기“와 동일하게 테이테베이스는 OPEN 상태여야 합니다.
    RMAN> ALTER DATABASE DATAFILE file# OFFLINE;
    RMAN> RUN {
        SET NEWNAME FOR DATAFILE file# TO '/path/to/DATAFILE_NAME.dbf';
        RESTORE DATAFILE file#;
        SWITCH DATAFILE file#;
        RECOVER DATAFILE file#;
    }
    RMAN> ALTER DATABASE DATAFILE file# ONLINE;
    

3-4. 다른 데이터베이스 서버에 복구하기(복제 및 이관)

이 과정은 보통 ‘Database Duplicate’ 또는 ‘DR(Disaster Recovery) 구축’이라고 부릅니다. 운영 서버의 데이터를 전혀 다른 서버(Auxiliary)로 옮겨서 동일한 DB를 하나 더 만드는 과정입니다. 실무에서는 운영 데이터를 개발 서버로 이관하거나, 서버 장비 교체(Migration) 시에 가장 많이 사용됩니다.

  • 사전 준비 사항 (운영자 Action): 다른 서버에 복구하기 위해서는 환경 설정이 가장 중요합니다.
    1. 비밀번호 파일 동기화: 운영 서버의 비밀번호 파일을 복사한 후 이름을 변경하여 사용할 수 있으나($ORACLE_HOME/dbs/orapw<SID>), orapwd 명령어를 사용해서 새 비밀번호 파일을 생성하는 것을 추천합니다.
      << 대상 서버 >>
      ---- 복사해 온 비밀번호 파일의 이름을 변경하는 경우,
      $ mv $ORACLE_HOME/dbs/orapw<운영SID> $ORACLE_HOME/dbs/orapw<대상SID>
      
      ---- 오라클의 orapwd 명령어를 사용하는 경우,
      -- 데이터베이스 관리자(SYSDBA) 권한으로 원격 접속할 때 필요한 패스워드 파일을 생성하거나 수정하는 도구
      -- entries=10: 10개의 비밀번호 저장, force=y: 이미 파일이 존재할 경우 덮어쓰기
      $ orapwd file=$ORACLE_HOME/dbs/orapw<SID> password=sys비밀번호 entries=10 force=y
      
    2. 환경 파일 설정 (PFILE): 운영 서버의 pfile(init<SID>.ora) 파일을 복사하여 대상 서버에 맞게 수정합니다. 특히 pfile에 설정된 디렉토리들은 미리 생성해 줘야 합니다. 그렇지 않으면 start NOMOUNT 명령어 실행 시
      << 운영 서버 >>
      ---- spfile 저장 경로를 확인합니다. 출력되지 않으면 pfile($ORACLE_HOME/dbs/init<SID>)를 사용하는 겁니다.
      SELECT name, value AS SPFILE_PATH
      FROM   v$parameter
      WHERE  name = 'spfile';
      
      ---- spfile를 통해 pfile을 생성합니다.
      -- (DB가 기동 중일 때, PFILE경로를 설정하지 않으면 기본 경로인 $ORACLE_HOME/dbs/init<SID>.ora에 생성)
      SQL> CREATE PFILE='?/dbs/init<운영SID>.ora_yyyymmdd' FROM SPFILE;
      -- (DB가 기동 중이지 않을 때, pfile 및 spfile의 경로를 지정합니다.) 
      SQL> CREATE PFILE='?/dbs/init<운영SID>.ora_yyyymmdd' FROM SPFILE='SPFILE_PATH';
      
      << 대상 서버 >>
      ---- 복사해 온 pfile의 이름을 변경합니다.
      $ mv $ORACLE_HOME/dbs/init<운영SID>.ora_yyyymmdd $ORACLE_HOME/dbs/init<대상SID>.ora
      
      ---- pfile 파일의 내용을 대상 서버에 맞게 수정합니다.(예시)
      $ vi $ORACLE_HOME/dbs/init<대상SID>.ora
      *.audit_file_dest=
      *.control_files=
      *.core_dump_dest=
      *.control_files=
      *.db_create_file_dest=
      *.db_create_online_log_dest_1=
      *.db_recovery_file_dest=
      
    3. 정적 리스너 등록(listener 유저): 정적 리스너(Static Listener) 설정은 DB가 꺼져 있거나 NOMOUNT 상태일 때도 외부(특히 RMAN)에서 접속할 수 있게 해주는 필수 관문입니다. Oracle Grid Infrastructure(GI)가 설치된 경우에는 grid 유저로 정적 리스너를 시작($ ps -ef | grep ohasd)해야 합니다. 그 이외의 경우에는 oracle 유저로 정적 리스너를 시작합니다.
      $ vi $ORACLE_HOME/network/admin/listener.ora
      # 1. 리스너의 네트워크 주소 정의
      LISTENER_DG =
        (DESCRIPTION_LIST =
          (DESCRIPTION =
            (ADDRESS = (PROTOCOL = TCP)(HOST = 대상서버_IP주소)(PORT = 1521))
            (ADDRESS = (PROTOCOL = IPC)(KEY = LISTENER_DG))
          )
        )
      
      # 2. 리스너가 강제로 서비스할 DB 목록 설정
      SID_LIST_LISTENER_DG =
        (SID_LIST =
          (SID_DESC =
            (GLOBAL_DBNAME = 대상1DBNAME)              # 외부에서 접속할 서비스명
            (ORACLE_HOME = /oracle_home/path/to)      # DB 홈 경로
            (SID_NAME = 대상1SID)                      # 대상 인스턴스 SID
          )
          (SID_DESC =
            (GLOBAL_DBNAME = 대상2DBNAME)              # 외부에서 접속할 서비스명
            (ORACLE_HOME = /oracle_home/path/to)      # DB 홈 경로
            (SID_NAME = 대상2SID)                      # 대상 인스턴스 SID
          )
        )
      
      -- 정적 리스너를 시작하고 상태를 확인합니다. 리스너 이름(LISTENER_DG)을 명시하지 않으면 기본값인 LISTENER를 대상으로 동작하므로, 별도의 리스너 이름을 생성한 경우에는 반드시 해당 이름을 지정해 주어야 합니다.
      $ lsnrctl start LISTENER_DG
      $ lsnrctl status LISTENER_DG
      
      -- ora_pmon_대상#SID 프로세스가 출력되어야 합니다.
      $ ps -elf | grep pmom
      
    4. 인스턴스 기동(oracle 유저): 대상 서버에서 DB를 NOMOUNT 상태로 올립니다. “ORACLE instance started”라는 메시지가 나오면 PFILE 수정이 성공적으로 이루어진 것입니다.
      $ sqlplus / as sysdba
      SQL> STARTUP NOMOUNT PFILE='?/dbs/init<대상SID>.ora';
      
      ---- pfile를 통해 spfile을 생성합니다.
      SQL> CREATE SPFILE FROM PFILE='?/dbs/init<대상SID>.ora';
      
    5. TNS Configuration: 운영 서버와 대상 서버는 tnsnames.ora를 통해 통신이 가능해야 합니다.(tnsping 명령어)
      $ vi $ORACLE_HOME/network/admin/tnsnames.ora (예시)
      CMAIN =
        (DESCRIPTION =
          (ADDRESS = (PROTOCOL = TCP)(HOST = hostname 또는 ip주소)(PORT = 1521))
          (CONNECT_DATA =
            (SERVER = DEDICATED)
            (SERVICE_NAME = CMAIN)
          )
        )
      DR_CMAIN =
        (DESCRIPTION =
          (ADDRESS_LIST =
            (ADDRESS = (PROTOCOL = TCP)(HOST = hostname 또는 ip주소)(PORT = 1581))
          )
          (CONNECT_DATA =
            (SERVER = DEDICATED)
            (SERVICE_NAME = DR_CMAIN)
          )
        )
      
  • RMAN Backup-based Duplication
    1. 백업 파일 전송: 운영 서버의 RMAN 백업 파일과 아카이브 로그를 대상 서버의 동일한 경로로 복사합니다.(NAS를 공유해서 쓴다면 마운트만 하면 됩니다.)
      -- CATALOG START WITH 명령어로 백업 파일의 위치를 인식시켜주는 과정이 필요할 수 있습니다.
      RMAN> CATALOG START WITH '/path/to/backups/';
      
    2. Backup-based Duplication 실행
      -- <New_DB_Name> : 복제가 완료된 후 새롭게 탄생할 데이터베이스의 DB_NAME(ORACLE_SID)
      -- FROM BACKUP 옵션: 기본값이며, 명시적으로 FROM BACKUP을 쓰기도 함
      RMAN> DUPLICATE TARGET DATABASE TO <New_DB_Name> FROM BACKUP LOCATION '/path/to/backups/';
      
  • RMAN Active Database Duplicate
    1. 대상 서버에서 운영 서버로 접속하여 운영 서버에서 대상 서버로 복제할 준비를 합니다.
      $ rman target sys/pass@운영DB auxiliary /
      
    2. Active Database Duplicate 실행
      -- <New_DB_Name> : 복제가 완료된 후 새롭게 탄생할 데이터베이스의 DB_NAME(ORACLE_SID)
      -- FROM ACTIVE DATABASE 옵션: 최신 백업 파일이 없을 때 아주 유용하나 운영 서버에 부하 발생
      RMAN> DUPLICATE TARGET DATABASE TO <New_DB_Name> FROM ACTIVE DATABASE;
      

You may also like...

답글 남기기

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