[Oracle 11gR2] Data Guard 기반의 백업 오프로딩(Backup Offloading) 구조 구현하기 – Part4

아래 순서대로 “Data Guard 기반의 백업 오프로딩(Backup Offloading)” 환경구성 및 모의훈련을 실시할 예정입니다.
- Basic: Oracle DataGuard 아키텍처와 프로세스의 이해
- Part1: Catalog DB → Primary DB → Standby DB 운영환경 구성
- Part2: Catalog DB 및 Standby DB를 활용한 백업환경 구성
- Part3: 서버 중지 및 재기동 절차
- Part4: Primary DB → Standby DB로의 데이터 전송 테스트
- Part5: Primary DB의 복구 모의훈련
- Part6: Standby DB로 Failover 모의훈련
- Part7: Primary DB로 Switchback 모의훈련
- Part8: 모니터링 및 트러블슈팅 가이드
Part3에서는 서버 중지 및 재기동 절차에 대해 알아봤는데요, Part4에서는 데이터 전송 테스트를 통해 Data Loss가 어느 정보 발생할 수 있는지 확인해 보겠습니다.
- 데이터용 테이블스페이스와 인덱스용 테이블스페이스 생성
- 데이터용 테이블스페이스와 인덱스용 테이블스페이스를 통합해서 하나로 생성해도 되지만, DB운영 상 권장 사항이므로 별도로 분리하겠습니다.
-- 데이터용 테이블스페이스 (100M) CREATE TABLESPACE TS_DATA DATAFILE SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED; -- 인덱스용 테이블스페이스 (100M) CREATE TABLESPACE TS_INDX DATAFILE SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED;
- 데이터용 테이블스페이스와 인덱스용 테이블스페이스를 통합해서 하나로 생성해도 되지만, DB운영 상 권장 사항이므로 별도로 분리하겠습니다.
- 카달로그를 동기화하고 테이블스페이스 반영 확인
- Primary DB 서버를 통해 Catalog DB 서버에 접속합니다.
[oracle@primary-db ~]$ rman target sys/orclsys@pri_db catalog rman_admin/orclsys@cat_db
- 카달로그를 동기화시킨후
report schema; 명령어를 실행하여 생성된 테이블스페이스가 카탈로그 정보에 업데이트되었는지 확인해 봅니다.RMAN> resync catalog; starting full resync of recovery catalog full resync complete RMAN> report schema; Report of database schema for database with db_unique_name PRIDB List of Permanent Datafiles =========================== File Size(MB) Tablespace RB segs Datafile Name ---- -------- -------------------- ------- ------------------------ 1 750 SYSTEM YES /u01/app/oracle/oradata/ORCL11G/system01.dbf 2 620 SYSAUX NO /u01/app/oracle/oradata/ORCL11G/sysaux01.dbf 3 75 UNDOTBS1 YES /u01/app/oracle/oradata/ORCL11G/undotbs01.dbf 4 5 USERS NO /u01/app/oracle/oradata/ORCL11G/users01.dbf 5 100 TS_DATA NO /u01/app/oracle/oradata/PRIDB/datafile/o1_mf_ts_data_ntdy5l6k_.dbf 6 100 TS_INDX NO /u01/app/oracle/oradata/PRIDB/datafile/o1_mf_ts_indx_ntdy5wm6_.dbf List of Temporary Files ======================= File Size(MB) Tablespace Maxsize(MB) Tempfile Name ---- -------- -------------------- ----------- -------------------- 1 29 TEMP 32767 /u01/app/oracle/oradata/ORCL11G/temp01.dbf
- Primary DB 서버를 통해 Catalog DB 서버에 접속합니다.
- 스키마 생성 및 권한 부여
- 스키마를 생성하고 데이터 생성을 위한 권한을 부여합니다.
-- 유저 생성 (dguser) CREATE USER dguser IDENTIFIED BY dguser123 DEFAULT TABLESPACE TS_DATA QUOTA UNLIMITED ON TS_DATA QUOTA UNLIMITED ON TS_INDX; -- 데이터 생성을 위해서는 CONNECT와 RESOURCE 권한이 필요합니다. GRANT CONNECT, RESOURCE TO dguser;
- 스키마를 생성하고 데이터 생성을 위한 권한을 부여합니다.
- 테이블 및 인덱스 생성
- 테이블 및 인덱스를 각각 TS_DATA 및 TS_INDX에 생성합니다.
-- 테이블 및 인덱스 생성 CREATE TABLE dguser.tb_sysdate ( seq_id NUMBER, log_date TIMESTAMP DEFAULT SYSTIMESTAMP, remark VARCHAR2(50), -- seq_id를 PK로 지정하고 인덱스는 TS_INDX에 생성 CONSTRAINT pk_tb_sysdate PRIMARY KEY (seq_id) USING INDEX TABLESPACE TS_INDX ) TABLESPACE TS_DATA; -- 생성된 테이블 및 인덱스 확인 SET LINESIZE 200; COL OBJECT_TYPE FOR A15; COL OWNER FOR A15; COL OBJECT_NAME FOR A15; COL TABLESPACE_NAME FOR A15; SELECT 'TABLE' AS OBJECT_TYPE, OWNER, TABLE_NAME AS OBJECT_NAME, TABLESPACE_NAME FROM DBA_TABLES WHERE TABLE_NAME = 'TB_SYSDATE' UNION ALL SELECT 'INDEX', OWNER, INDEX_NAME, TABLESPACE_NAME FROM DBA_INDEXES WHERE INDEX_NAME = 'PK_TB_SYSDATE' ; OBJECT_TYPE OWNER OBJECT_NAME TABLESPACE_NAME --------------- --------------- --------------- --------------- TABLE DGUSER TB_SYSDATE TS_DATA INDEX DGUSER PK_TB_SYSDATE TS_INDX
- 테이블 및 인덱스를 각각 TS_DATA 및 TS_INDX에 생성합니다.
- Primary DB에 일정 시간 간격으로 데이터를 입력하는 프로시저 생성
- NORMAL 모드와 CRASH 모드를 시뮬레이션할 수 있도록 구성
SQL> GRANT EXECUTE ON DBMS_LOCK TO dguser; SQL> GRANT ALTER SYSTEM TO dguser; SQL> CREATE OR REPLACE PROCEDURE dguser.proc_test_insert ( p_mode IN VARCHAR2, -- NORMAL, CRASH p_count IN NUMBER, p_interval IN NUMBER ) IS v_next_id NUMBER; BEGIN FOR i IN 1..p_count LOOP -- 1. 현재 테이블에서 최대값을 찾아 다음 ID 계산 (데이터가 없으면 1로 시작) SELECT NVL(MAX(seq_id), 0) + 1 INTO v_next_id FROM dguser.tb_sysdate; -- 2. 계산된 ID로 데이터 입력 INSERT INTO dguser.tb_sysdate (seq_id, remark) VALUES (v_next_id, 'Data Guard Test - ' || v_next_id); COMMIT; -- 3. NORMAL 모드의 경우, 100번마다 아카이브 로그 강제 생성 (전송 테스트용) IF p_mode = 'NORMAL' AND MOD(i, 100) = 0 THEN EXECUTE IMMEDIATE 'ALTER SYSTEM ARCHIVE LOG CURRENT'; END IF; SYS.DBMS_LOCK.SLEEP(p_interval); END LOOP; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM); END; /
- NORMAL 모드와 CRASH 모드를 시뮬레이션할 수 있도록 구성
- Standby DB에서 전송되는 데이터를 확인
- NORMAL 모드 테스트: 1000번 Loop를 실행하며, 100번 마다
'ALTER SYSTEM ARCHIVE LOG CURRENT'명령어 실행< Primary DB > SQL> exec dguser.proc_test_insert('NORMAL', 1000, 0.5) -- dguser.proc_test_insert 프로시저가 실행되는 동안 아래 쿼리를 실행하여 Archive Log 파일의 전송 확인 SQL> SET LINESIZE 200; COL DEST_ID FOR 9; COL STATUS FOR A10; COL DATABASE_MODE FOR A20; COL MAX_SEQ FOR 99999; COL SENT_SEQ FOR 99999; COL APP_SEQ FOR 99999; COL TRANS_GAP FOR 99999; COL APPLY_GAP FOR 99999; SELECT DEST_ID, STATUS, DATABASE_MODE, (SELECT MAX(SEQUENCE#) FROM V$ARCHIVED_LOG WHERE DEST_ID=1) AS MAX_SEQ, ARCHIVED_SEQ# AS SENT_SEQ, APPLIED_SEQ# AS APP_SEQ, (SELECT MAX(SEQUENCE#) FROM V$ARCHIVED_LOG WHERE DEST_ID=1) - ARCHIVED_SEQ# AS TRANS_GAP, ARCHIVED_SEQ# - APPLIED_SEQ# AS APPLY_GAP FROM V$ARCHIVE_DEST_STATUS WHERE DEST_ID IN (1, 2); -- Primary에서 GAP 확인 SELECT STATUS, GAP_STATUS FROM V$ARCHIVE_DEST_STATUS WHERE DEST_ID = 2; < Standby DB > -- GAP 확인 SELECT * FROM V$ARCHIVE_GAP; -- 가장 최근 전송받은 시퀀스 확인 SELECT 'RECEIVED_SEQ' AS TYPE, THREAD#, MAX(SEQUENCE#) FROM V$ARCHIVED_LOG GROUP BY THREAD# UNION ALL SELECT 'APPLIED_SEQ', THREAD#, MAX(SEQUENCE#) AS APPLIED_SEQ FROM V$ARCHIVED_LOG WHERE APPLIED='YES' GROUP BY THREAD#; -- MRP 프로세스가 갭을 메우고 현재 로그까지 따라왔는지 확인 SELECT PROCESS, STATUS, SEQUENCE# FROM V$MANAGED_STANDBY WHERE PROCESS LIKE 'MRP%'; - CRASH 모드 테스트: 1000번 Loop를 실행하며, Loop가 종료되면
'SHUTDOWN ABORT'명령어 실행< Primary DB > -- 최대 seq_id 값을 확인합니다. SQL> SELECT SEQ_ID AS BEFORE_MAX, LOG_DATE, REMARK FROM DGUSER.TB_SYSDATE WHERE SEQ_ID = (SELECT MAX(SEQ_ID) FROM DGUSER.TB_SYSDATE) ; -- 아래 쉘 스크립트를 생성/실행합니다. sector_1 종료 후 sector_2가 실행됩니다. ---- sector_1을 백그라운드로 실행하려면 sqlplus / as sysdba <<EOF & 로 변경합니다. [oracle@primary-db scripts]$ vi crash_test.sh #!/bin/bash # sector 1 sqlplus / as sysdba <<EOF exec dguser.proc_test_insert('CRASH', $1, $2); exit; EOF # sector 2 sqlplus / as sysdba <<EOF shutdown abort; exit; EOF [oracle@primary-db scripts]$ ./crash_test.sh 20000 0 < Standby DB > -- Primary DB가 종료된 후 실행 SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL; SQL> ALTER DATABASE OPEN; -- Primary DB의 (before_max+1000)값과 Standby DB의 trans_max값을 비교하여 Data Loss를 확인해 봅니다. SQL> SELECT SEQ_ID AS TRANS_MAX, LOG_DATE, REMARK FROM DGUSER.TB_SYSDATE WHERE SEQ_ID = (SELECT MAX(SEQ_ID) FROM DGUSER.TB_SYSDATE) ;
- NORMAL 모드 테스트: 1000번 Loop를 실행하며, 100번 마다
- 반복해서 CRASH 테스트를 하려면 Part3: 서버 중지 및 재기동 절차 준용
- Standby DB Shutdown 및 MOUNT 상태로 재기동
- Primary DB 재기동
