안녕하세요 Surmin입니다.
오늘은 RMAN DUPLICATE(ACTIVE) 기능에 대한 테스트 결과를 공유해 드리고자 합니다. 이 내용이 앞으로 관련 작업을 진행하실 때 참고가 되기를 바랍니다.
RMAN DUPLICATE(ACTIVE)란?
- 활성 데이터베이스 복제는 소스 데이터베이스를 백업할 필요가 없습니다. 네트워크를 통해 데이터베이스 파일을 보조(복제) 인스턴스로 복사하여 활성 소스 데이터베이스를 대상 호스트에 복제합니다.
Test 환경
- Oracle 19c 단일 노드
- 소스DB 리스너 포트는1522
- 리스너 설정 자세한 부분은 생략하였습니다.
- 여기서는 방화벽 Down 상태 입니다.
방법1- 설치 후 컨트롤 파일 재생성 통하여 데이터 파일등 옮김
소스DB 준비
- DB생성
- 생성 시 비밀번호 파일의 password하고 USER SYS IDENTIFIED, USER SYSTEM IDENTIFIED 비밀번호하고 일치 시켜줘야함
- #잘못주었을 경우
- ALTER USER SYS IDENTIFIED BY oracle;
- ALTER USER SYSTEM IDENTIFIED BY oracle;
- 생성 시 비밀번호 파일의 password하고 USER SYS IDENTIFIED, USER SYSTEM IDENTIFIED 비밀번호하고 일치 시켜줘야함
#상황에 따라 다를 수 있음
cd $ORACLE_BASE/product/
mkdir TESTDB
#aud 위하여
mkdir -p $ORACLE_BASE/admin/TESTDB/adump
#dump지정을 위하여
mkdir -p $ORACLE_BASE/admin/TESTDB/dpdump
#데이타 파일 위하여
mkdir -p $ORACLE_BASE/oradata/TESTDB
#생성한거 확인
[oracle@ORA19C product]$ ls
19c TESTDB
#ORACLE_HOME/dbs 이동
#패스워드 파일생성
[oracle@ORA19C dbs]$ orapwd file=orapwTESTDB format=12 force=y password=oracle
#init파일 생성
#여기서는 기존 DB의 init 파일 복사 후 수정 그리고 메모리 자원에 맞게 수정을 해줍니다.
[oracle@ORA19C dbs]$ cp -av initTARGET.ora initTESTDB.ora
'initTARGET.ora' -> 'initTESTDB.ora'
==
*.audit_file_dest='/app/oracle/admin/TESTDB/adump'
*.audit_trail='NONE'
*.compatible='19.0.0'
#필수 파라미터
*.control_files='/app/oracle/oradata/TESTDB/control01.ctl','/app/oracle/oradata/TESTDB/control02.ctl'
#필수 파라미터
*.shared_pool_size=164m
#필수 파라미터
db_cache_size=50m
*.db_block_size=8192
*.db_files=1000
*.db_name='TESTDB'
*.db_securefile='PREFERRED'
*.diagnostic_dest='/app/oracle'
*.dispatchers='(PROTOCOL=TCP) (SERVICE=ORA19CXDB)'
*.local_listener='TESTDB'
*.log_archive_dest_1=''
*.log_archive_format='arch_%t_%s_%r.arc'
*.nls_language='AMERICAN'
*.nls_territory='AMERICA'
*.open_cursors=300
*.pga_aggregate_target=389m
*.processes=1000
*.remote_login_passwordfile='EXCLUSIVE'
*.sga_target=1167m
*.undo_tablespace='UNDOTBS1'
==
export ORACLE_SID=TESTDB
sqlplus "/as sysdba"
#DB 생성은 파라미터를 읽을 수 있는 상태인 nomount 상태에서 가능하다.
startup nomount
#이걸로 교체가능 : CHARACTER SET AL32UTF8
CREATE DATABASE TESTDB
USER SYS IDENTIFIED BY oracle
USER SYSTEM IDENTIFIED BY oracle
LOGFILE
GROUP 1 ('/app/oracle/oradata/TESTDB/redo01.log') SIZE 100M,
GROUP 2 ('/app/oracle/oradata/TESTDB/redo02.log') SIZE 100M,
GROUP 3 ('/app/oracle/oradata/TESTDB/redo03.log') SIZE 100M
DATAFILE '/app/oracle/oradata/TESTDB/system01.dbf' SIZE 500M AUTOEXTEND ON NEXT 100M MAXSIZE UNLIMITED
SYSAUX DATAFILE '/app/oracle/oradata/TESTDB/sysaux01.dbf' SIZE 500M AUTOEXTEND ON NEXT 100M MAXSIZE UNLIMITED
DEFAULT TABLESPACE USERS
DATAFILE '/app/oracle/oradata/TESTDB/users01.dbf' SIZE 100M AUTOEXTEND ON NEXT 50M MAXSIZE UNLIMITED
UNDO TABLESPACE UNDOTBS1
DATAFILE '/app/oracle/oradata/TESTDB/undotbs01.dbf' SIZE 200M AUTOEXTEND ON NEXT 50M MAXSIZE UNLIMITED
DEFAULT TEMPORARY TABLESPACE TEMP
TEMPFILE '/app/oracle/oradata/TESTDB/temp01.dbf' SIZE 200M AUTOEXTEND ON NEXT 50M MAXSIZE UNLIMITED
CHARACTER SET KO16KSC5601
NATIONAL CHARACTER SET AL16UTF16
EXTENT MANAGEMENT LOCAL;
exit
cd $ORACLE_HOME/rdbms/admin/
@catalog.sql
@catproc.sql
@pupbld.sql
SET LINESIZE 200
SET PAGESIZE 100
COLUMN OWNER FORMAT A10
COLUMN OBJECT_NAME FORMAT A20
COLUMN OBJECT_TYPE FORMAT A15
COLUMN STATUS FORMAT A10
SELECT OWNER, OBJECT_NAME, OBJECT_TYPE, STATUS
FROM DBA_OBJECTS
WHERE OWNER = 'SYS' AND OBJECT_NAME = 'STANDARD';
@utlrp.sql
select object_name from dba_objects where status='INVALID' and owner='SYS';
#아카이브 설정
SQL> shut immediate;
SQL> startup mount
SQL> ALTER DATABASE ARCHIVELOG;
SQL> alter database open;
!mkdir -p /app/oracle/fast_recovery_area/TESTDB
ALTER SYSTEM SET log_archive_dest_1='location=/app/oracle/fast_recovery_area/TESTDB mandatory' SCOPE=SPFILE;
SQL> shut immediate;
SQL> startup
SHOW PARAMETER log
#테스트 데이터 생성
create tablespace test_data datafile '/app/oracle/oradata/TESTDB/test_data01.dbf' size 200M;
CREATE USER testuser IDENTIFIED BY Oracle123;
GRANT CONNECT, RESOURCE TO testuser;
ALTER USER testuser QUOTA UNLIMITED ON TEST_DATA;
-- 테스트 데이터 생성
CONNECT testuser/Oracle123
CREATE TABLE customer (
id NUMBER PRIMARY KEY,
name VARCHAR2(50),
email VARCHAR2(100),
create_date DATE
) TABLESPACE TEST_DATA;
-- 대량 데이터 생성
BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO customer VALUES (
i,
'Customer_' || i,
'customer' || i || '@example.com',
SYSDATE - (DBMS_RANDOM.VALUE(0, 365))
);
IF MOD(i, 1000) = 0 THEN
COMMIT;
END IF;
END LOOP;
COMMIT;
END;
/
-- 다양한 데이터 타입을 가진 테이블 추가
CREATE TABLE product (
id NUMBER PRIMARY KEY,
name VARCHAR2(100),
price NUMBER(10,2),
description CLOB,
last_update TIMESTAMP
) TABLESPACE TEST_DATA;
-- 데이터 삽입
BEGIN
FOR i IN 1..100 LOOP
INSERT INTO product (id, name, price, description, last_update)
VALUES (
i,
'Product_' || i,
ROUND(DBMS_RANDOM.VALUE(10, 1000), 2),
'Description for product ' || i || '. Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
SYSTIMESTAMP
);
END LOOP;
COMMIT;
END;
/
SQL> create pfile from spfile;
File created.
SQL> select count(*) from testuser.product;
COUNT(*)
----------
100
SQL> select count(*) from testuser.customer ;
COUNT(*)
----------
100000
init파일로 다시 생성 후 타켓서버로 옮겨줍니다.
- 여기서는 프롬프트 환경이 모바엑스텀임으로 SFTP로 옮겨줍니다.
- 옮기기전 혹은 옮긴 후 환경에 맞게 db_name 등을 수정하여 줍니다.
- 여기서는 TESTDB ⇒ TEST 로 DB NAME 변경
SQL> create pfile from spfile;
#생성된 파일을 타겟 서버로 복사하고 다음과 같이 수정:
- db_name을 'TARGET'으로 변경
- control_files 경로 수정
- 데이터파일 관련 경로 수정
- 로그파일 관련 경로 수정
==
TEST.__data_transfer_cache_size=0
TEST.__db_cache_size=620756992
TEST.__inmemory_ext_roarea=0
TEST.__inmemory_ext_rwarea=0
TEST.__java_pool_size=0
TEST.__large_pool_size=16777216
TEST.__oracle_base='/app/oracle'#ORACLE_BASE set from environment
TEST.__pga_aggregate_target=419430400
TEST.__sga_target=1224736768
TEST.__shared_io_pool_size=67108864
TEST.__shared_pool_size=469762048
TEST.__streams_pool_size=33554432
TEST.__unified_pga_pool_size=0
*.audit_file_dest='/app/oracle/admin/TEST/adump'
*.audit_trail='NONE'
*.compatible='19.0.0'
*.control_files='/app/oracle/oradata/TEST/control01.ctl','/app/oracle/oradata/TEST/control02.ctl'
*.db_block_size=8192
*.db_cache_size=50m
*.db_files=1000
*.db_name='TEST'
*.db_securefile='PREFERRED'
*.diagnostic_dest='/app/oracle'
*.dispatchers='(PROTOCOL=TCP) (SERVICE=ORA19CXDB)'
*.local_listener='TESTDB'
*.log_archive_dest_1='location=/app/oracle/fast_recovery_area/TEST mandatory'
*.log_archive_format='arch_%t_%s_%r.arc'
*.nls_language='AMERICAN'
*.nls_territory='AMERICA'
*.open_cursors=300
*.pga_aggregate_target=389m
*.processes=1000
*.remote_login_passwordfile='EXCLUSIVE'
*.sga_target=1167m
*.shared_pool_size=164m
*.undo_tablespace='UNDOTBS1'
==
- TNS 설정
- 소스와 타겟 서버 모두의 tnsnames.ora 파일에 다음 항목 추가 및 확인
- 소스(원본)는 어차피 설정되어 있으니 타겟만 확인및 설정을 한다.
- 소스는 상관없지만 타겟에다가는 (UR=A) 항목을 추가한다.
- (UR=A) : nomount 상태일 때는 리스너가 “BLOCKED” 상태가 되어 외부 연결을 허용하지 않습니다. UR=A를 설정하면 이러한 제한을 우회하여 nomount 상태에서도 연결이 가능해집니다.
- 소스와 타겟 서버 모두의 tnsnames.ora 파일에 다음 항목 추가 및 확인
#소스서버
#tnsnames.ora
TEST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.153.37)(PORT = 1522))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = TEST)
(UR=A)
)
)
==
#타겟서버
#rman 테스트 시 리스너를 동적으로 할경우 DUPLICATE 시 중간에 실패해서 정적으로 설정하였습니다.
#listener.ora 파일
SID_LIST_TEST =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = TEST)
(ORACLE_HOME = /app/oracle/product/19c)
(SID_NAME = TEST)
)
)
#tnsnames.ora 파일
TEST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.153.37)(PORT = 1522))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = TEST)
(UR=A)
)
)
TESTDB =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora19c)(PORT = 1522))
(CONNECT_DATA = (SERVICE_NAME = TESTDB))
)
타겟 DB준비
#target 에서 원격접속을 위해 passwd 파일생성
#오라클 홈의 dbs로 이동 후 수행
orapwd file=orapwTEST format=12 force=y password=oracle
export ORACLE_SID=TEST
sqlplus / as sysdba
STARTUP NOMOUNT
exit
# 타겟 서버에서 RMAN 실행
#RMAN으로 액티브 복제 수행위해 접속
rman target sys/oracle@TESTDB auxiliary sys/oracle@TEST
- 복제수행
- 수행 중 RMAN-05158: WARNING 발생
- MOS 문서 확인 시 NOFILENAMECHECK 옵션을 사용할 때 동일한 파일명으로 인해 파일이 덮어쓰여질 가능성이 있다는 경고입니다. 소스와 타겟 데이터베이스가 서로 다른 서버에 있고 파일 시스템을 공유하지 않는다면 실제로 덮어쓰기 위험은 없으므로 이 경고를 무시해도 됩니다.
- 수행 중 RMAN-05158: WARNING 발생
DUPLICATE TARGET DATABASE TO "TEST" FROM ACTIVE DATABASE SPFILE NOFILENAMECHECK;
#원본과 동일한 행수의 데이터 확인
SQL> select count(*) from testuser.product;
COUNT(*)
----------
100
SQL> select count(*) from testuser.customer ;
COUNT(*)
----------
100000
하지만 데이터 파일 등 확인 시 컨트롤 파일 제외하고 TEST가 아닌 TESTDB에 생성된 컨트롤 파일 재생성을 통하여 원하는 위치로 옮겨주자
#다른 경로확인 됨
[oracle@ORA19C TESTDB]$ ls
redo01.log redo02.log redo03.log sysaux01.dbf system01.dbf temp01.dbf test_data01.dbf undotbs01.dbf users01.dbf
#컨트롤 파일 재생성 하기 위하여 절차
SHUTDOWN IMMEDIATE;
# 디렉토리가 없으면 생성
mkdir -p /app/oracle/oradata/TEST
# 데이터 파일 복사
cp /app/oracle/oradata/TESTDB/system01.dbf /app/oracle/oradata/TEST/
cp /app/oracle/oradata/TESTDB/sysaux01.dbf /app/oracle/oradata/TEST/
cp /app/oracle/oradata/TESTDB/undotbs01.dbf /app/oracle/oradata/TEST/
cp /app/oracle/oradata/TESTDB/users01.dbf /app/oracle/oradata/TEST/
cp /app/oracle/oradata/TESTDB/test_data01.dbf /app/oracle/oradata/TEST/
cp /app/oracle/oradata/TESTDB/temp01.dbf /app/oracle/oradata/TEST/
# 리두 로그 파일 복사
cp /app/oracle/oradata/TESTDB/redo01.log /app/oracle/oradata/TEST/
cp /app/oracle/oradata/TESTDB/redo02.log /app/oracle/oradata/TEST/
cp /app/oracle/oradata/TESTDB/redo03.log /app/oracle/oradata/TEST/
#sqlplus접속
STARTUP NOMOUNT;
#제어 파일 재생성
CREATE CONTROLFILE REUSE SET DATABASE "TEST" RESETLOGS ARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 292
LOGFILE
GROUP 1 '/app/oracle/oradata/TEST/redo01.log' SIZE 50M,
GROUP 2 '/app/oracle/oradata/TEST/redo02.log' SIZE 50M,
GROUP 3 '/app/oracle/oradata/TEST/redo03.log' SIZE 50M
DATAFILE
'/app/oracle/oradata/TEST/system01.dbf',
'/app/oracle/oradata/TEST/sysaux01.dbf',
'/app/oracle/oradata/TEST/undotbs01.dbf',
'/app/oracle/oradata/TEST/users01.dbf',
'/app/oracle/oradata/TEST/test_data01.dbf'
CHARACTER SET KO16KSC5601; #언어셋은 항상주의하자.
#리두 리셋함
ALTER DATABASE OPEN RESETLOGS;
#temp재사용
ALTER TABLESPACE TEMP ADD TEMPFILE '/app/oracle/oradata/TEST/temp01.dbf' REUSE;\
#확인
SET PAGESIZE 100
SET LINESIZE 200
COLUMN file_type FORMAT A20
COLUMN file_name FORMAT A80
BREAK ON file_type SKIP 1
SELECT 'Controlfile' AS file_type, name AS file_name FROM v$controlfile
UNION ALL
SELECT 'Datafile', file_name FROM dba_data_files
UNION ALL
SELECT 'Tempfile', file_name FROM dba_temp_files
UNION ALL
SELECT 'Redolog', member FROM v$logfile
UNION ALL
SELECT 'Archive Destination', destination FROM v$archive_dest WHERE status != 'INACTIVE'
ORDER BY 1, 2;
FILE_TYPE FILE_NAME
-------------------- --------------------------------------------------------------------------------
Archive Destination /app/oracle/fast_recovery_area/TEST
Controlfile /app/oracle/oradata/TEST/control01.ctl
/app/oracle/oradata/TEST/control02.ctl
Datafile /app/oracle/oradata/TEST/sysaux01.dbf
/app/oracle/oradata/TEST/system01.dbf
/app/oracle/oradata/TEST/test_data01.dbf
/app/oracle/oradata/TEST/undotbs01.dbf
/app/oracle/oradata/TEST/users01.dbf
Redolog /app/oracle/oradata/TEST/redo01.log
/app/oracle/oradata/TEST/redo02.log
/app/oracle/oradata/TEST/redo03.log
Tempfile /app/oracle/oradata/TEST/temp01.dbf
12 rows selected.
#데이터 확인
SQL> select count(*) from testuser.customer ;
COUNT(*)
----------
100000
#물리적 위치에서도 확인
[oracle@ORA19C TEST]$ ls
control01.ctl control02.ctl redo01.log redo02.log redo03.log sysaux01.dbf system01.dbf temp01.dbf test_data01.dbf undotbs01.dbf users01.dbf
#oratab에 확인 후 작성한다.
vi /etc/oratab
==
TEST:/app/oracle/product/19c:N
==
방법2-RMAN 할때 한번에 원하는 디렉터리에 옮김((소스서버는 LISTENER_TESTDB 로 네이밍 변경하였습니다.))
#TNS 설정
#소스서버
##tnsnames.ora
TEST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.153.37)(PORT = 1522))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = TEST)
)
)
======
#타겟서버
##tnsnames.ora
LISTENER_TESTDB =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.153.199)(PORT = 1522))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = TESTDB)
)
)
TEST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ORA19C)(PORT = 1522))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = TEST)
(UR=A)
)
)
- init 파일에서 경로수정
- 여기서 수정목록
- audit_file_dest
- control_files
- log_archive_dest_1
- db_file_name_convert
- log_file_name_convert
- 여기서 수정목록
[oracle@ORA19C dbs]$ cat initTEST.ora
TEST.__data_transfer_cache_size=0
TEST.__db_cache_size=620756992
TEST.__inmemory_ext_roarea=0
TEST.__inmemory_ext_rwarea=0
TEST.__java_pool_size=0
TEST.__large_pool_size=16777216
TEST.__oracle_base='/app/oracle'#ORACLE_BASE set from environment
TEST.__pga_aggregate_target=419430400
TEST.__sga_target=1224736768
TEST.__shared_io_pool_size=67108864
TEST.__shared_pool_size=469762048
TEST.__streams_pool_size=33554432
TEST.__unified_pga_pool_size=0
*.audit_file_dest='/app/oracle/admin/TEST/adump'
*.audit_trail='NONE'
*.compatible='19.0.0'
*.control_files='/app/oracle/oradata/TEST/control01.ctl','/app/oracle/oradata/TEST/control02.ctl'
*.db_block_size=8192
*.db_cache_size=50m
*.db_files=1000
*.db_name='TEST'
*.db_securefile='PREFERRED'
*.diagnostic_dest='/app/oracle'
*.dispatchers='(PROTOCOL=TCP) (SERVICE=ORA19CXDB)'
*.local_listener='TEST'
*.log_archive_dest_1='location=/app/oracle/fast_recovery_area/TEST mandatory'
*.log_archive_format='arch_%t_%s_%r.arc'
*.nls_language='AMERICAN'
*.nls_territory='AMERICA'
*.open_cursors=300
*.pga_aggregate_target=389m
*.processes=1000
*.remote_login_passwordfile='EXCLUSIVE'
*.sga_target=1167m
*.shared_pool_size=164m
*.undo_tablespace='UNDOTBS1'
*.db_file_name_convert='/app/oracle/oradata/TESTDB','/app/oracle/oradata/TEST'
*.log_file_name_convert='/app/oracle/oradata/TESTDB','/app/oracle/oradata/TEST'
sqlplus / as sysdba
startup nomount
exit
# 타겟 서버에서 RMAN 실행
#RMAN으로 액티브 복제 수행위해 접속
rman target sys/oracle@LISTENER_TESTDB auxiliary sys/oracle@TEST
#명령어 수행
DUPLICATE TARGET DATABASE TO "TEST" FROM ACTIVE DATABASE NOFILENAMECHECK;
#sp파일 생성된거 확인
[oracle@ORA19C dbs]$ ls
c-2499451409-20250516-00 hc_ORA19C.dat hc_TEST.dat init.ora initTEST.ora lkTEST orapwTEST snapcf_TEST.f spfileTEST.ora
#DB명 변경확인
SQL> SELECT name FROM v$database;
NAME
---------
TEST
#spfile로 올라온거 확인
SQL> SHOW PARAMETER SPFILE;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
spfile string /app/oracle/product/19c/dbs/sp
fileTEST.ora
#데이터 파일 TEST 디렉터리로 이동된거 확인
SQL> SET PAGESIZE 100
SET LINESIZE 200
COLUMN file_type FORMAT A20
COLUMN file_name FORMAT A80
SQL> SQL> SQL> SQL> BREAK ON file_type SKIP 1
SQL>
SQL> SELECT 'Controlfile' AS file_type, name AS file_name FROM v$controlfile
2 UNION ALL
3 SELECT 'Datafile', file_name FROM dba_data_files
UNION ALL
4 5 SELECT 'Tempfile', file_name FROM dba_temp_files
UNION ALL
6 7 SELECT 'Redolog', member FROM v$logfile
8 UNION ALL
SELECT 'Archive Destination', destination FROM v$archive_dest WHERE status != 'INACTIVE'
9 10 ORDER BY 1, 2;
FILE_TYPE FILE_NAME
-------------------- --------------------------------------------------------------------------------
Archive Destination /app/oracle/fast_recovery_area/TEST
Controlfile /app/oracle/oradata/TEST/control01.ctl
/app/oracle/oradata/TEST/control02.ctl
Datafile /app/oracle/oradata/TEST/sysaux01.dbf
/app/oracle/oradata/TEST/system01.dbf
/app/oracle/oradata/TEST/test_data01.dbf
/app/oracle/oradata/TEST/undotbs01.dbf
/app/oracle/oradata/TEST/users01.dbf
Redolog /app/oracle/oradata/TEST/redo01.log
/app/oracle/oradata/TEST/redo02.log
/app/oracle/oradata/TEST/redo03.log
Tempfile /app/oracle/oradata/TEST/temp01.dbf
12 rows selected.
#소스 데이터 들어왔는지 확인함
SQL> select count(*) from testuser.product;
COUNT(*)
----------
100
SQL> select count(*) from testuser.customer ;
COUNT(*)
----------
100000
#oratab 기입 필요합니다.
감사합니다.