Component | Primary Site | Standby Site |
Platform | Linux x86_64 | Linux x86_64 |
Servers | west01, west02 | east01, east02 |
Domain | westscan.oravr.in | eastscan.oravr.in |
Oracle Version | 19.10.0.0 | 19.10.0.0 |
Storage | ASM (+DATA, +FRA) | ASM (+DATA_DG, +DATA_DG) |
Database Name | woravr | woravr |
DB_UNIQUE_NAME | woravr | woravrdr |
Instances | woravr1, woravr2 | woravrdr1, woravrdr2 |
Oracle Home | /u01/app/oracle/product/19c/db_1 | /u01/app/oracle/product/19c/db_1 |
Data Guard RAC Architecture
Primary RAC Cluster (west01/west02) synchronizes with Standby RAC Cluster (east01/east02) using redo transport services. Both clusters utilize ASM for storage management and SCAN listeners for client connectivity.
[oracle@west01 ~]$ crsctl check cluster -all ************************************************************** west01: CRS-4537: Cluster Ready Services is online CRS-4529: Cluster Synchronization Services is online CRS-4533: Event Manager is online ************************************************************** west02: CRS-4537: Cluster Ready Services is online CRS-4529: Cluster Synchronization Services is online CRS-4533: Event Manager is online **************************************************************
ASMCMD> pwd
+data/woravr/password
ASMCMD> pwcopy pwdworavr.314.5141100038 /tmp
copying +data/woravr/password/pwdworavr.314.5141100038 -> /tmp/pwdworavr.314.5141100038
[oracle@west02]$ scp -p /tmp/pwdworavr.314.5141100038 oracle@east01:/u01/app/oracle/product/19c/db_1/dbs/orapwworavrdr1
[oracle@west02]$ scp -p /tmp/pwdworavr.314.5141100038 oracle@east02:/u01/app/oracle/product/19c/db_1/dbs/orapwworavrdr2
Step 3: Configure Standby Redo Logs
Standby redo logs are essential for real-time redo apply and protection modes like Maximum Availability and Maximum Protection. The recommended number of standby redo log files is:
Formula(Maximum number of logfiles + 1) × Maximum number of threads
For this configuration: (2 + 1) × 2 = 6 standby redo logs
Verify Current Online Redo Log Configuration
SQL> SELECT b.thread#, a.group#, a.member, b.bytes
FROM v$logfile a, v$log b
WHERE a.group# = b.group#;
THREAD# GROUP# MEMBER BYTES
---------- ---------- ----------------------------------- ----------
1 2 +DATA/woravr/redo02.log 209715200
1 1 +DATA/woravr/redo01.log 209715200
2 3 +DATA/woravr/redo03.log 209715200
2 4 +DATA/woravr/redo04.log 209715200
Create Standby Redo Logs for Thread 1
SQL> ALTER DATABASE ADD STANDBY LOGFILE THREAD 1
GROUP 5 ('+DATA/woravr/redo05.log') SIZE 200M,
GROUP 6 ('+DATA/woravr/redo06.log') SIZE 200M,
GROUP 7 ('+DATA/woravr/redo07.log') SIZE 200M;
Database altered.
Create Standby Redo Logs for Thread 2
SQL> ALTER DATABASE ADD STANDBY LOGFILE THREAD 2
GROUP 8 ('+DATA/woravr/redo08.log') SIZE 200M,
GROUP 9 ('+DATA/woravr/redo09.log') SIZE 200M,
GROUP 10 ('+DATA/woravr/redo10.log') SIZE 200M;
Database altered.
Verify Standby Redo Log Creation
SQL> SELECT b.thread#, a.group#, a.member, b.bytes
FROM v$logfile a, v$standby_log b
WHERE a.group# = b.group#;
THREAD# GROUP#MEMBER BYTES
---------- ---------- ----------------------------------- ----------
1 5 +DATA/woravr/redo05.log 209715200
1 6 +DATA/woravr/redo06.log 209715200
1 7 +DATA/woravr/redo07.log 209715200
2 8 +DATA/woravr/redo08.log 209715200
2 9 +DATA/woravr/redo09.log 209715200
2 10 +DATA/woravr/redo10.log 209715200
6 rows selected.
Step 4: Verify Archive Mode
SQL> ARCHIVE LOG LIST;
Database log mode Archive Mode
Automatic archival Enabled
Archive destination +FRA
Oldest online log sequence 10
Next log sequence to archive 11
Current log sequence 11
Step 5: Configure Primary Database Initialization Parameters
Data Guard requires specific initialization parameters to enable redo transport, log apply services, and file name conversion between sites.
Backup Current Parameter File
SQL> CREATE PFILE='/home/oracle/initworavr.ora.bkp_vr' FROM SPFILE;
File created.
Set Essential Data Guard Parameters
SQL> ALTER SYSTEM SET db_unique_name='woravr' SCOPE=SPFILE SID='*';
SQL> ALTER SYSTEM SET LOG_ARCHIVE_CONFIG='DG_CONFIG=(woravr,woravrdr)' SCOPE=BOTH SID='*';
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_1='LOCATION=+FRA VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=woravr' SCOPE=BOTH SID='*';
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_2='SERVICE=woravrdr LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=woravrdr' SCOPE=BOTH SID='*';
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_1=ENABLE SCOPE=BOTH SID='*';
SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2=ENABLE SCOPE=BOTH SID='*';
Deprecation NoticeThe FAL_CLIENT parameter is deprecated in Oracle 19c but included here for reference. FAL_SERVER remains active for fetch archive log operations.
Configure FAL and File Name Conversion
SQL> ALTER SYSTEM SET fal_client=woravr SCOPE=BOTH SID='*';
SQL> ALTER SYSTEM SET fal_server=woravrdr SCOPE=BOTH SID='*';
SQL> ALTER SYSTEM SET DB_FILE_NAME_CONVERT='+DATA_DG','+DATA' SCOPE=SPFILE SID='*';
SQL> ALTER SYSTEM SET LOG_FILE_NAME_CONVERT='+DATA_DG','+DATA' SCOPE=SPFILE SID='*';
SQL> ALTER SYSTEM SET STANDBY_FILE_MANAGEMENT=AUTO SCOPE=BOTH SID='*';
Key Initialization Parameters Explained
Parameter | Purpose | Configuration |
LOG_ARCHIVE_CONFIG | Defines all databases in Data Guard configuration | DG_CONFIG=(woravr,woravrdr) |
LOG_ARCHIVE_DEST_1 | Local archive destination | +FRA for all roles |
LOG_ARCHIVE_DEST_2 | Remote standby destination using LGWR ASYNC | SERVICE=woravrdr |
FAL_SERVER | Fetch Archive Log server for gap resolution | woravrdr |
DB_FILE_NAME_CONVERT | Maps datafile paths from standby to primary | +DATA_DG → +DATA |
LOG_FILE_NAME_CONVERT | Maps redo log paths from standby to primary | +DATA_DG → +DATA |
STANDBY_FILE_MANAGEMENT | Automates standby file operations | AUTO |
Step 6: Configure TNS Entries on Primary
Both primary and standby sites require TNS entries for bidirectional communication. The UR=A (Uninterruptible Retry Always) parameter ensures connection attempts continue even when the database is not in mounted state.
Primary Site tnsnames.ora (All Nodes)
woravr =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = westscan.oravr.in)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = woravr)
)
)
woravrdr =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = eastscan.oravr.in)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = woravrdr)
(UR=A)
)
)
Verify TNS Connectivity from Primary
[oracle@west01 ~]$ tnsping woravr
OK (10 msec)
[oracle@west01 ~]$ tnsping woravrdr
OK (0 msec)
4. Standby Database Configuration
Step 1: Prepare Standby Initialization Parameters
Create an initialization parameter file for the standby database with appropriate settings for the standby role. Key differences include reversed file name conversions and standby-specific configurations.
Standby Parameter File (initworavrdr.ora)
*.audit_file_dest='/u01/app/oracle/admin/woravrdr/adump'
*.audit_trail='db'
*.cluster_database=false
*.compatible='19.0.0'
*.control_files='+DATA_DG/woravrdr/control01.ctl','+DATA_DG/woravrdr/control02.ctl'
*.db_block_size=8192
*.db_file_name_convert='+DATA/woravr','+DATA_DG/woravrdr'
*.db_name='woravr'
*.db_recovery_file_dest='+DATA_DG'
*.db_recovery_file_dest_size=8016m
*.db_unique_name='woravrdr'
*.diagnostic_dest='/u01/app/oracle'
*.fal_client='woravrdr'
*.fal_server='woravr'
*.instance_name='woravrdr1'
woravrdr1.instance_number=1
*.log_archive_config='DG_CONFIG=(woravr,woravrdr)'
*.log_archive_dest_1='LOCATION=+DATA_DG VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=woravrdr'
*.log_archive_dest_2='SERVICE=woravr LGWR ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=woravr'
*.log_archive_dest_state_1='ENABLE'
*.log_archive_dest_state_2='ENABLE'
*.log_file_name_convert='+DATA/woravr','+DATA_DG/woravrdr'
*.remote_listener='eastscan.oravr.in:1521'
*.remote_login_passwordfile='exclusive'
*.standby_file_management='AUTO'
woravrdr1.thread=1
woravrdr1.undo_tablespace='UNDOTBS1'
[oracle@east01 ~]$ mkdir -p /u01/app/oracle/admin/woravrdr/adump [oracle@east02 ~]$ mkdir -p /u01/app/oracle/admin/woravrdr/adump
[oracle@east01 ~]$ echo "woravr:/u01/app/oracle/product/19c/db_1:N" >> /etc/oratab [oracle@east01 ~]$ echo "woravrdr1:/u01/app/oracle/product/19c/db_1:N" >> /etc/oratab [oracle@east02 ~]$ echo "woravr:/u01/app/oracle/product/19c/db_1:N" >> /etc/oratab [oracle@east02 ~]$ echo "woravrdr2:/u01/app/oracle/product/19c/db_1:N" >> /etc/oratab
SQL> STARTUP NOMOUNT PFILE='/u01/app/oracle/product/19c/db_1/dbs/initworavrdr1.ora'; ORACLE instance started. Total System Global Area 914357200 bytes Fixed Size 9141200 bytes Variable Size 541065216 bytes Database Buffers 356515840 bytes Redo Buffers 7634944 bytes
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = woravrdr)
(ORACLE_HOME = /u01/app/oracle/product/19c/db_1)
(SID_NAME = woravrdr1)
)
)
woravr =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = westscan.oravr.in)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = woravr)
)
)
woravrdr =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = eastscan.oravr.in)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = woravrdr)
(UR=A)
)
)
[oracle@east01 ~]$ sqlplus sys/sys@woravr as sysdba Connected. [oracle@east01 ~]$ sqlplus sys/sys@woravrdr as sysdba Connected.
[oracle@east01 ~]$ rman target sys/sys@woravr auxiliary sys/sys@woravrdr
Recovery Manager: Release 19.0.0.0.0 - Production
connected to target database: woravr (DBID=1311101397)
connected to auxiliary database: woravr (not mounted)
RMAN> DUPLICATE TARGET DATABASE FOR STANDBY FROM ACTIVE DATABASE NOFILENAMECHECK;
Starting Duplicate Db at 29-APR-20
using target database control file instead of recovery catalog
allocated channel: ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: SID=50 device type=DISK
contents of Memory Script:
{
backup as copy reuse
targetfile '+DATA/woravr/PASSWORD/pwdworavr.312.1000670118'
auxiliary format '/u01/app/oracle/product/19c/db_1/dbs/orapwworavrdr1';
}
executing Memory Script
Starting backup at 29-APR-20
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=35 instance=woravr1 device type=DISK
Finished backup at 29-APR-20
Starting restore at 29-APR-20
using channel ORA_AUX_DISK_1
channel ORA_AUX_DISK_1: starting datafile backup set restore
channel ORA_AUX_DISK_1: using network backup set from service woravr1
channel ORA_AUX_DISK_1: restoring control file
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:04
output file name=+DATA_DG/woravrdr/control01.ctl
output file name=+DATA_DG/woravrdr/control02.ctl
Finished restore at 29-APR-20
sql statement: alter database mount standby database
Starting restore at 29-APR-20
channel ORA_AUX_DISK_1: restoring datafile 00001 to +DATA_DG/woravrdr/system01.dbf
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:16
channel ORA_AUX_DISK_1: restoring datafile 00003 to +DATA_DG/woravrdr/sysaux01.dbf
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:09
channel ORA_AUX_DISK_1: restoring datafile 00004 to +DATA_DG/woravrdr/undotbs01.dbf
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:04
channel ORA_AUX_DISK_1: restoring datafile 00005 to +DATA_DG/woravrdr/undotbs02.dbf
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:01
channel ORA_AUX_DISK_1: restoring datafile 00007 to +DATA_DG/woravrdr/users01.dbf
channel ORA_AUX_DISK_1: restore complete, elapsed time: 00:00:02
Finished restore at 29-APR-20
Finished Duplicate Db at 29-APR-20
SQL> SELECT b.thread#, a.group#, a.type, a.member, b.bytes
FROM v$logfile a, v$standby_log b
WHERE a.group# = b.group#;
THREAD# GROUP# TYPE MEMBER BYTES
---------- ---------- ------- -----------------------------------
1 5 STANDBY +DATA_DG/woravrdr/redo05.log 209715200
1 6 STANDBY +DATA_DG/woravrdr/redo06.log 209715200
1 7 STANDBY +DATA_DG/woravrdr/redo07.log 209715200
2 8 STANDBY +DATA_DG/woravrdr/redo08.log 209715200
2 9 STANDBY +DATA_DG/woravrdr/redo09.log 209715200
2 10 STANDBY +DATA_DG/woravrdr/redo10.log 209715200
6 rows selected.
Create SPFILE from PFILE SQL> CREATE SPFILE='+DATA_DG/woravrdr/PARAMETERFILE/spfileworavrdr.ora' FROM PFILE='/u01/app/oracle/product/19c/db_1/dbs/initworavrdr1.ora'; File created. SQL> SHUTDOWN IMMEDIATE; Database dismounted. ORACLE instance shut down. Configure SPFILE Pointer [oracle@east01 dbs]$ mv initworavrdr1.ora initworavrdr1.ora.bkp [oracle@east01 dbs]$ echo "SPFILE='+DATA_DG/woravrdr/PARAMETERFILE/spfileworavrdr.ora'" > initworavrdr1.ora [oracle@east01 dbs]$ scp initworavrdr1.ora oracle@east02:/u01/app/oracle/product/19c/db_1/dbs/initworavrdr2.ora
SQL> ALTER SYSTEM SET undo_tablespace=UNDOTBS2 SID='woravrdr2' SCOPE=SPFILE; SQL> ALTER SYSTEM SET instance_number=1 SID='woravrdr1' SCOPE=SPFILE; SQL> ALTER SYSTEM SET instance_number=2 SID='woravrdr2' SCOPE=SPFILE; SQL> ALTER SYSTEM SET instance_name='woravrdr1' SID='woravrdr1' SCOPE=SPFILE; SQL> ALTER SYSTEM SET instance_name='woravrdr2' SID='woravrdr2' SCOPE=SPFILE; SQL> ALTER SYSTEM SET thread=1 SID='woravrdr1' SCOPE=SPFILE; SQL> ALTER SYSTEM SET thread=2 SID='woravrdr2' SCOPE=SPFILE; SQL> ALTER SYSTEM SET cluster_database=TRUE SCOPE=SPFILE; SQL> ALTER SYSTEM SET remote_listener='eastscan.oravr.in:1521' SCOPE=SPFILE;
[oracle@east01]$ srvctl add database -db woravrdr \ -oraclehome /u01/app/oracle/product/19c/db_1 \ -role physical_standby \ -startoption mount \ -spfile +DATA_DG/woravrdr/PARAMETERFILE/spfileworavrdr.ora [oracle@east01]$ srvctl add instance -db woravrdr -instance woravrdr1 -node east01 [oracle@east01]$ srvctl add instance -db woravrdr -instance woravrdr2 -node east02 [oracle@east01]$ srvctl start database -d woravrdr [oracle@east01]$ srvctl status database -d woravrdr Instance woravrdr1 is running on node east01 Instance woravrdr2 is running on node east02
SQL> SELECT name, open_mode, database_role, cdb FROM v$database; NAME OPEN_MODE DATABASE_ROLE CDB --------- -------------------- ---------------- --- woravr MOUNTED PHYSICAL STANDBY NO
Generate Redo on Primary
-- On Primary Instance 1
SQL> ALTER SYSTEM SWITCH LOGFILE;
SQL> ALTER SYSTEM SWITCH LOGFILE;
SQL> ALTER SYSTEM SWITCH LOGFILE;
-- On Primary Instance 2
SQL> ALTER SYSTEM SWITCH LOGFILE;
SQL> ALTER SYSTEM SWITCH LOGFILE;
SQL> ALTER SYSTEM SWITCH LOGFILE;
Check Archive Log Sequence on Primary
SQL> SELECT thread#, MAX(sequence#)
FROM v$archived_log
WHERE archived='YES'
GROUP BY thread#;
THREAD# MAX(SEQUENCE#)
---------- --------------
1 99
2 87
Verify Applied Logs on Standby
SQL> SELECT thread#, MAX(sequence#)
FROM v$archived_log
WHERE applied='YES'
GROUP BY thread#;
THREAD# MAX(SEQUENCE#)
---------- --------------
1 99
2 87
SQL> SELECT ARCH.THREAD# "Thread",
ARCH.SEQUENCE# "Last Sequence Received",
APPL.SEQUENCE# "Last Sequence Applied",
(ARCH.SEQUENCE# - APPL.SEQUENCE#) "Difference"
FROM (SELECT THREAD#, SEQUENCE# FROM V$ARCHIVED_LOG
WHERE (THREAD#, FIRST_TIME) IN
(SELECT THREAD#, MAX(FIRST_TIME) FROM V$ARCHIVED_LOG GROUP BY THREAD#)) ARCH,
(SELECT THREAD#, SEQUENCE# FROM V$LOG_HISTORY
WHERE (THREAD#, FIRST_TIME) IN
(SELECT THREAD#, MAX(FIRST_TIME) FROM V$LOG_HISTORY GROUP BY THREAD#)) APPL
WHERE ARCH.THREAD# = APPL.THREAD#
ORDER BY 1;
Thread Last Sequence Received Last Sequence Applied Difference
---------- ---------------------- --------------------- ----------
1 99 99 0
2 87 87
SELECT pr.thread# "Node",
pr.primary "Primary",
dr.Standby "DR",
pr.primary - dr.Standby "Difference"
FROM (SELECT thread#, MAX(sequence#) AS primary
FROM v$archived_log
WHERE resetlogs_change# = (SELECT resetlogs_change# FROM v$database)
GROUP BY thread#) Pr,
(SELECT thread#, MAX(sequence#) AS Standby
FROM v$archived_log
WHERE resetlogs_change# = (SELECT resetlogs_change# FROM v$database)
AND applied='YES'
GROUP BY thread#) dr
WHERE pr.thread# = dr.thread#;
SET PAGES 50000 LINES 32767
SET SCAN OFF
SET FEED OFF
BREAK ON ROW SKIP 1
COL "THREAD" FOR A10
COL "PR-ARCHIVED" FOR A15
COL "STBY-ARCHIVED" FOR A15
COL "STBY-APPLIED" FOR A15
COL "SHIPPING GAP(PR -> STBY)" FOR A20
COL "APPLIED GAP(STBY -> STBY)" FOR A20
SET HEAD OFF
SELECT 'sysdate: ' || TO_CHAR(SYSDATE, 'DD-Mon-YYYY HH24:MI:SS') FROM dual;
SELECT '****************Standby Log Ship and Log Apply Status*****************' FROM dual;
SET HEAD ON
SELECT DEST_ID, DESTINATION, TARGET, STATUS
FROM V$ARCHIVE_DEST
WHERE DESTINATION IS NOT NULL;
SELECT
LPAD(t1, 4, ' ') "Thread",
LPAD(pricre, 9, ' ') "PR - Archived",
LPAD(stdcre, 10, ' ') "STBY - Archived",
LPAD(stdnapp, 9, ' ') "STBY - Applied",
LPAD(pricre - stdcre, 13, ' ') "Shipping GAP (PR -> STBY)",
LPAD(stdcre - stdnapp, 15, ' ') "Applied GAP (STBY -> STBY)"
FROM (
SELECT MAX(sequence#) stdcre, thread# t1
FROM v$archived_log
WHERE standby_dest='YES'
AND resetlogs_id IN (SELECT MAX(RESETLOGS_ID) FROM v$archived_log)
AND thread# IN (1, 2)
GROUP BY thread#
) a,
(
SELECT MAX(sequence#) stdnapp, thread# t2
FROM v$archived_log
WHERE standby_dest='YES'
AND resetlogs_id IN (SELECT MAX(RESETLOGS_ID) FROM v$archived_log)
AND thread# IN (1, 2)
AND applied='YES'
GROUP BY thread#
) b,
(
SELECT MAX(sequence#) pricre, thread# t3
FROM v$archived_log
WHERE standby_dest='NO'
AND resetlogs_id IN (SELECT MAX(RESETLOGS_ID) FROM v$archived_log)
AND thread# IN (1, 2)
GROUP BY thread#
) c
WHERE a.t1 = b.t2 AND b.t2 = c.t3 AND c.t3 = a.t1
ORDER BY 1;
| Operation | Command |
| Stop MRP | ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL; |
| Start MRP (Basic) | ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT; |
| Start MRP (Real-time Apply) | ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT; |
| Start MRP (Parallel) | ALTER DATABASE RECOVER MANAGED STANDBY DATABASE PARALLEL 12 DISCONNECT; |
| Start MRP (Serial) | ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT NOPARALLEL; |
-- Temporarily disable redo shipping SQL> ALTER SYSTEM SET log_archive_dest_state_2=DEFER; -- Re-enable redo shipping SQL> ALTER SYSTEM SET log_archive_dest_state_2=ENABLE;
-- Check current SCN on database SQL> SELECT TO_CHAR(CURRENT_SCN) FROM V$DATABASE; -- Find minimum SCN from datafile headers SQL> SELECT MIN(fhscn) FROM x$kcvfh; -- Find minimum SCN excluding read-only files SQL> SELECT MIN(f.fhscn) FROM x$kcvfh f, v$datafile d WHERE f.hxfil = d.file# AND d.enabled != 'READ ONLY';