Create an Oracle DataGuard Physical Standby
Introduction
This time we are going to build a DataGuard environment by generating a Physical Standby for our Oracle 19c multitenant installation.
Prerequisites
We have a Primary Oracle 19c multitenant instance prmydb
with one pluggable database taller
running in the Virtual Machine Instance patodgprmy
on Google Cloud Platform.
For database creation steps check Create Oracle Multitenant Database in Silent Mode.
Also we need another Virtual Machine Instance patodgstby
with the same operating system, and same oracle software version installed that will be our Physical Standby server.
Prepare the Primary Database
We need to do some preparation of the database like archive mode, force logging and standby redo, before initiating DataGuard configuration.
Validate Archive Mode
[oracle@patodgprmy prmydb]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Wed Jun 17 18:20:33 2020
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
SQL> archive log list
Database log mode Archive Mode
Automatic archival Enabled
Archive destination USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence 2
Next log sequence to archive 4
Current log sequence 4
Enable Logging
SQL> ALTER DATABASE FORCE LOGGING;
Database altered.
SQL> SELECT force_logging FROM v$database;
FORCE_LOGGING
---------------------------------------
YES
Configure Redo for Future Switchover
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/oradata/cdbs/PRMYDB/stbyredo1.rdo') SIZE 64M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/oradata/cdbs/PRMYDB/stbyredo2.rdo') SIZE 64M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/oradata/cdbs/PRMYDB/stbyredo3.rdo') SIZE 64M;
Database altered.
SQL> ALTER DATABASE ADD STANDBY LOGFILE thread 1 ('/oradata/cdbs/PRMYDB/stbyredo4.rdo') SIZE 64M;
Database altered.
SQL> select group#, type, member from v$logfile order by 1;
GROUP# TYPE MEMBER
---------- ------- --------------------------------------------------
1 ONLINE /oradata/cdbs/PRMYDB/redo01.log
2 ONLINE /oradata/cdbs/PRMYDB/redo02.log
3 ONLINE /oradata/cdbs/PRMYDB/redo03.log
4 STANDBY /oradata/cdbs/PRMYDB/stbyredo1.rdo
5 STANDBY /oradata/cdbs/PRMYDB/stbyredo2.rdo
6 STANDBY /oradata/cdbs/PRMYDB/stbyredo3.rdo
7 STANDBY /oradata/cdbs/PRMYDB/stbyredo4.rdo
7 rows selected.
Configure Primary DataGuard
Set Primary Database Initialization Parameters
Define the DataGuard archiving configuration with the unique database name of the members of the replication:
alter system set LOG_ARCHIVE_CONFIG='DG_CONFIG=(prmydb,stbydb)' scope=both;
System altered.
Setup the destination for the archive logs, to the Primary and to the Standby:
alter system set LOG_ARCHIVE_DEST_1='LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=prmydb' scope=both;
System altered.
alter system set LOG_ARCHIVE_DEST_2='SERVICE=stbydb ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=stbydb' scope=both;
System altered.
Configure our Standby instance as the failover server:
alter system set FAL_SERVER=stbydb scope=both;
System altered.
Configure automatic datafile management for creation/modification and also define naming conversion for archivelogs and datafiles according the instance directory name:
alter system set STANDBY_FILE_MANAGEMENT=AUTO scope=both;
System altered.
SQL> alter system set db_file_name_convert='/STBYDB/','/PRMYDB/' scope=spfile;
System altered.
SQL> alter system set log_file_name_convert='/STBYDB/','/PRMYDB/' scope=spfile;
System altered.
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
Prepare Data and Files for the Standby
We need to generate a backup and some configuration files from the Primary instance.
Generate a Backup
This time we are going to do an offline backup and restore, following the procedure described in the document Duplicate Oracle Database from RMAN Offline Backup
but you can also try other methods like RMAN duplicate
.
So we mount and backup the database:
[oracle@patoracle ~]$ rman target /
Recovery Manager: Release 19.0.0.0.0 - Production on Wed Jun 17 18:32:14 2020
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle and/or its affiliates. All rights reserved.
connected to target database (not started)
RMAN> startup mount
Oracle instance started
database mounted
RMAN> backup database ;
Starting backup at 17-JUN-20
using channel ORA_DISK_1
channel ORA_DISK_1: starting compressed full datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00001 name=/oradata/cdbs/PRMYDB/system01.dbf
input datafile file number=00003 name=/oradata/cdbs/PRMYDB/sysaux01.dbf
input datafile file number=00014 name=/oradata/cdbs/PRMYDB/undotbsp.dbf
input datafile file number=00007 name=/oradata/cdbs/PRMYDB/users01.dbf
channel ORA_DISK_1: starting piece 1 at 17-JUN-20
channel ORA_DISK_1: finished piece 1 at 17-JUN-20
piece handle=/rman/respaldo/PRMYDB_20200617_1av30dhp.bkp tag=TAG20200617T183641 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:35
channel ORA_DISK_1: starting compressed full datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00006 name=/oradata/cdbs/PRMYDB/pdbseed/sysaux01.dbf
input datafile file number=00005 name=/oradata/cdbs/PRMYDB/pdbseed/system01.dbf
input datafile file number=00008 name=/oradata/cdbs/PRMYDB/pdbseed/undotbs01.dbf
channel ORA_DISK_1: starting piece 1 at 17-JUN-20
channel ORA_DISK_1: finished piece 1 at 17-JUN-20
piece handle=/rman/respaldo/PRMYDB_20200617_1bv30dis.bkp tag=TAG20200617T183641 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:25
channel ORA_DISK_1: starting compressed full datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00010 name=/oradata/pdbs/taller/sysaux01.dbf
input datafile file number=00009 name=/oradata/pdbs/taller/system01.dbf
input datafile file number=00012 name=/oradata/pdbs/taller/datos.dbf
channel ORA_DISK_1: starting piece 1 at 17-JUN-20
channel ORA_DISK_1: finished piece 1 at 17-JUN-20
piece handle=/rman/respaldo/PRMYDB_20200617_1cv30djl.bkp tag=TAG20200617T183641 comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:00:15
Finished backup at 17-JUN-20
Starting Control File and SPFILE Autobackup at 17-JUN-20
piece handle=/rman/controlfile/c-2978577906-20200617-01.bkp comment=NONE
Finished Control File and SPFILE Autobackup at 17-JUN-20
RMAN>
write down the backup tag TAG20200617T183641
for later reference in the restore.
Generate Standby Control File
SQL> ALTER DATABASE CREATE STANDBY CONTROLFILE AS '/home/oracle/stbydb.ctl';
Database altered.
Validate or Create the Password File
[oracle@patodgprmy ~]$ ls -l $ORACLE_HOME/dbs/orapw*
-rw-r-----. 1 oracle oinstall 6144 Jun 17 18:16 /opt/oracle/product/19c/dbhome_1/dbs/orapwprmydb
if there is none available you can create one using the utility orapwd
:
[oracle@patodgprmy ~]$ orapwd file=$ORACLE_HOME/dbs/orapw$ORACLE_SID sysdg=y
Enter password for SYS:
Enter password for SYSDG:
[oracle@patodgprmy ~]$
Create Standby Init File
Generate a pfile from the current spfile:
SQL> CREATE PFILE='/home/oracle/initstbydb.ora' FROM SPFILE;
File created.
then edit it to modify only the following parameters with the following values:
[oracle@patodgprmy ~]$ vi /home/oracle/initstbydb.ora
*.db_file_name_convert='/PRMYDB/','/STBYDB/'
*.db_name=prmydb
...
*.db_unique_name=stbydb
...
*.fal_server='STBYDB'
...
*.log_archive_dest_1='LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=stbydb'
*.log_archive_dest_2='SERVICE=prmydb ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=prmydb'
...
*.log_file_name_convert='/PRMYDB/','/STBYDB/'
Prepare Networking
We created our machines using the reserved static addresses from our subnet patosubnet
as described in the document Using Customized Internal IP, and we assigned the following IP addresses:
patodgprmy
: prmynet (10.20.0.10) andpatodgstby
: stbynet (10.20.0.20)
Configure Listener
Configure the Listener in both machines using our internal IP addresses:
[oracle@patodgprmy ~]$ vi $ORACLE_HOME/network/admin/listener.ora
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.0.10)(PORT = 1521))
[oracle@patodgstby ~]$ vi $ORACLE_HOME/network/admin/listener.ora
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.0.20)(PORT = 1521))
Start Listeners
And start the listener in both servers:
[oracle@patodgstby ~}$ lsnrctl start
TNSLSNR for Linux: Version 19.0.0.0.0 - Production
System parameter file is /opt/oracle/product/19c/dbhome_1/network/admin/listener.ora
Log messages written to /opt/oracle/diag/tnslsnr/patodgstby/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=10.20.0.10)(PORT=1521)))
[oracle@patodgstby ~}$ lsnrctl start
TNSLSNR for Linux: Version 19.0.0.0.0 - Production
System parameter file is /opt/oracle/product/19c/dbhome_1/network/admin/listener.ora
Log messages written to /opt/oracle/diag/tnslsnr/patodgstby/listener/alert/log.xml
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=10.20.0.20)(PORT=1521)))
Add the Other Instance in TNSNAMES
We need to access the Primary service from the Standby and the Standby service from the Primary so make sure
we have both databases registered in both tnsnames.ora
files:
$ vi $ORACLE_HOME/network/admin/tnsnames.ora
prmydb =
(DESCRIPTION =
(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.0.10)(PORT = 1521)))
(CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = prmydb))
)
stbydb =
(DESCRIPTION =
(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.0.20)(PORT = 1521)))
(CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = stbydb))
)
and then test we can communicate in both ways:
[oracle@patodgprmy ~]$ tnsping stbydb
TNS Ping Utility for Linux: Version 19.0.0.0.0 - Production on 17-JUN-2020 19:01:09
Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.0.20)(PORT = 1521))) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = stbydb)))
OK (0 msec)
[oracle@patodgstby ~]$ tnsping prmydb
TNS Ping Utility for Linux: Version 19.0.0.0.0 - Production on 17-JUN-2020 19:01:59
Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.20.0.10)(PORT = 1521))) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = prmydb)))
OK (0 msec)
Prepare the Standby Server
Create Directory Structure
Create the directories where the Primary data files are stored and also the directories referred by the init.ora file but this time pointing to the new instance name:
[oracle@patodgstby ~]$ sudo mkdir /oradata
[oracle@patodgstby ~]$ sudo chown oracle:oinstall /oradata
[oracle@patodgstby ~]$ mkdir /oradata/cdbs
[oracle@patodgstby ~]$ mkdir /oradata/pdbs
[oracle@patodgstby ~]$ mkdir /oradata/recovery
[oracle@patodgstby ~]$ mkdir /oradata/cdbs/STBYDB
[oracle@patodgstby ~]$ mkdir /oradata/recovery/STBYDB
[oracle@patodgstby ~]$ mkdir -p /opt/oracle/admin/stbydb/adump
Copy Configuration Files
Copy the modified Standby init, the generated Standby controlfile and the Oracle password file to the new server, at the following locations and with the following names:
[oracle@patodgprmy ~]$ gcloud config set compute/zone us-central1-f
Updated property [compute/zone].
[oracle@patodgprmy ~]$ gcloud compute scp initstbydb.ora patodgstby:$ORACLE_HOME/dbs
initstbydb.ora 100% 1708 2.3MB/s 00:00
[oracle@patodgprmy ~]$ gcloud compute scp stbydb.ctl patodgstby:/oradata/cdbs/STBYDB/control01.ctl
stbydb.ctl 100% 18MB 36.3MB/s 00:00
[oracle@patodgprmy ~]$ gcloud compute scp stbydb.ctl patodgstby:/oradata/recovery/STBYDB/control02.ctl
stbydb.ctl 100% 18MB 37.2MB/s 00:00
[oracle@patodgprmy ~]$ gcloud compute scp $ORACLE_HOME/dbs/orapwprmydb patodgstby:$ORACLE_HOME/dbs/orapwstbydb
orapwprmydb 100% 6144 2.8MB/s 00:00
Share Backup Files
We need to have the generated backup available on the Standby server.
You can copy the backup files to the other machine or to a shared location, we are going to use our RMAN Google disk.
Add the RMAN disk to the new Virtual Machine and then mount it to /rman
directory so we can read the Primary backup:
[oracle@patodgstby ~]$ sudo mkdir /rman
[oracle@patodgstby ~]$ sudo chown oracle:oinstall /rman
[oracle@patodgstby ~]$ sudo mount -o discard,defaults /dev/sdb /rman
mount: /dev/sdb is write-protected, mounting read-only
[oracle@patodgstby ~]$ cd /rman
[oracle@patodgstby rman]$ ls
controlfile lost+found respaldo
For more information on the RMAN disk we are using here please check Google Disk for RMAN backups
Setup Oracle Variables
Export the following Oracle variables, for persistence include them in your .bash_profile
:
[oracle@patodgstby ~]$ vi .bash_profile
# Database Variables
export ORACLE_BASE=/opt/oracle
export ORACLE_HOME=/opt/oracle/product/19c/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
export ORACLE_SID=stbydb
Restore Primary Backup into the Standby
Now that our environment is prepared we need to connect to RMAN
to perform the restore.
Restore Database
We startup the database with mount
option and we restore our database using the TAG from our offline backup:
[oracle@patodgstby ~]$ rman target /
Recovery Manager: Release 19.0.0.0.0 - Production on Wed Jun 17 19:57:11 2020
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle and/or its affiliates. All rights reserved.
connected to target database (not started)
RMAN> startup mount
Oracle instance started
database mounted
RMAN> restore database from tag 'TAG20200617T183641';
Starting restore at 17-JUN-20
Starting implicit crosscheck backup at 17-JUN-20
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=261 device type=DISK
Crosschecked 3 objects
Finished implicit crosscheck backup at 17-JUN-20
Starting implicit crosscheck copy at 17-JUN-20
using channel ORA_DISK_1
Crosschecked 2 objects
Finished implicit crosscheck copy at 17-JUN-20
searching for all files in the recovery area
cataloging files...
no files cataloged
using channel ORA_DISK_1
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00001 to /oradata/cdbs/STBYDB/system01.dbf
channel ORA_DISK_1: restoring datafile 00003 to /oradata/cdbs/STBYDB/sysaux01.dbf
channel ORA_DISK_1: restoring datafile 00007 to /oradata/cdbs/STBYDB/users01.dbf
channel ORA_DISK_1: restoring datafile 00014 to /oradata/cdbs/STBYDB/undotbsp.dbf
channel ORA_DISK_1: reading from backup piece /rman/respaldo/PRMYDB_PRMYDB_20200617_1av30dhp.bkp
channel ORA_DISK_1: piece handle=/rman/respaldo/PRMYDB_20200617_1av30dhp.bkp tag=TAG20200617T183641
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:55
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00005 to /oradata/cdbs/STBYDB/pdbseed/system01.dbf
channel ORA_DISK_1: restoring datafile 00006 to /oradata/cdbs/STBYDB/pdbseed/sysaux01.dbf
channel ORA_DISK_1: restoring datafile 00008 to /oradata/cdbs/STBYDB/pdbseed/undotbs01.dbf
channel ORA_DISK_1: reading from backup piece /rman/respaldo/PRMYDB_20200617_1bv30dis.bkp
channel ORA_DISK_1: piece handle=/rman/respaldo/PRMYDB_20200617_1bv30dis.bkp tag=TAG20200617T183641
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:25
channel ORA_DISK_1: starting datafile backup set restore
channel ORA_DISK_1: specifying datafile(s) to restore from backup set
channel ORA_DISK_1: restoring datafile 00009 to /oradata/pdbs/taller/system01.dbf
channel ORA_DISK_1: restoring datafile 00010 to /oradata/pdbs/taller/sysaux01.dbf
channel ORA_DISK_1: restoring datafile 00012 to /oradata/pdbs/taller/datos.dbf
channel ORA_DISK_1: reading from backup piece /rman/respaldo/PRMYDB_20200617_1cv30djl.bkp
channel ORA_DISK_1: piece handle=/rman/respaldo/PRMYDB_20200617_1cv30djl.bkp tag=TAG20200617T183641
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:25
Finished restore at 17-JUN-20
RMAN> exit
Recovery Manager complete.
DataGuard Standby
Initiate Standby Recovery
We initiate our replication issuing the command alter database recover
:
[oracle@patodgstby ~]$ sqlplus / as sysdba
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT FROM SESSION;
Database altered.
SQL> select name, open_mode, database_role, switchover_status from v$database ;
NAME OPEN_MODE DATABASE_ROLE SWITCHOVER_STATUS
--------- -------------------- ---------------- --------------------
PRMYDB MOUNTED PHYSICAL STANDBY TO PRIMARY
SQL>
Validate the DataGuard Process
Review that the DataGuard processes are running and the last sequence applied:
SQL> SELECT ROLE, THREAD#, SEQUENCE#, ACTION FROM V$DATAGUARD_PROCESS;
ROLE THREAD# SEQUENCE# ACTION
------------------------ ---------- ---------- ------------
RFS ping 1 3 IDLE
recovery apply slave 0 0 IDLE
recovery apply slave 0 0 IDLE
managed recovery 0 0 IDLE
RFS archive 0 0 IDLE
archive local 0 0 IDLE
archive redo 0 0 IDLE
archive redo 0 0 IDLE
redo transport timer 0 0 IDLE
archive redo 0 0 IDLE
gap manager 0 0 IDLE
redo transport monitor 0 0 IDLE
RFS async 1 3 IDLE
log writer 0 0 IDLE
recovery logmerger 1 3 APPLYING_LOG
15 rows selected.
and we can see in the alert log that the archive logs are being transferred and applied:
[oracle@patodgstby ~]$ cd $ORACLE_BASE/diag/rdbms/stbydb/stbydb/trace/
[oracle@patodgstby trace]$ tail -f alert_stbydb.log
2020-06-17T20:16:05.871028-05:00
rfs (PID:4757): Primary database is in MAXIMUM PERFORMANCE mode
rfs (PID:4757): Re-archiving LNO:6 T-1.S-2
2020-06-17T20:16:06.155055-05:00
ARC2 (PID:2756): Archived Log entry 2 added for T-1.S-2 ID 0xb1b5cab6 LAD:1
2020-06-17T20:16:06.219735-05:00
rfs (PID:4757): Selected LNO:4 for T-1.S-3 dbid 2978577906 branch 1043350981
2020-06-17T20:16:07.082072-05:00
PR00 (PID:3761): Media Recovery Waiting for T-1.S-3 (in transit)
2020-06-17T20:16:07.082724-05:00
Recovery of Online Redo Log: Thread 1 Group 4 Seq 3 Reading mem 0
Mem# 0: /oradata/cdbs/STBYDB/stbyredo1.rdo
Validate Replication
Create Data and Objects in Primary
In this example our user will connect to the pluggable database and create one table and insert a row inside:
[oracle@patodgprmy ~]$ sqlplus /nolog
SQL> conn pato@taller;
Enter password:
Connected.
SQL> create table tdg1 (i1 int, c1 varchar(20), d1 timestamp);
Table created.
SQL> alter table tdg1 add (constraint i1_pk primary key (i1) );
Table altered.
SQL> insert into tdg1 values (1,'DataGuard Test',current_timestamp);
1 row created.
SQL> commit;
Commit complete.
Validate Data Replicated in Standby
Disable replication and open the Standby in read only mode to validate that the new table and data are already here:
[oracle@patodgstby ~]$ sqlplus / as sysdba
SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL;
Database altered.
SQL> alter database open read only;
Database altered.
SQL> alter pluggable database taller open;
Pluggable database altered.
SQL> alter session set container = taller;
Session altered.
SQL> select * from pato.tdg1 ;
I2 C2 D2
---------- -------------------- ------------------------------
1 DataGuard Test 17-JUN-20 08.20.14.216007 PM
Our DataGuard environment is working and data and objects are being recovered from the Primary to the Standby!
Conclusion
We have successfully configured a DataGuard environment with one Physical Standby using Oracle 19c multitenant instances running on Virtual Machine Instances from Google Cloud Platform.