8i | 9i | 10g | 11g | 12c | 13c | 18c | 19c | 21c | 23ai | Misc | PL/SQL | SQL | RAC | WebLogic | Linux
Direct NFS (DNFS) CloneDB in Oracle Database 11g Release 2 (Patchset 11.2.0.2 onward)
CloneDB is a new Direct NFS (DNFS) feature introduced in the 11.2.0.2 database patchset. Rather than using the traditional RMAN database duplication, CloneDB uses dNFS technology to instantly fire up a clone using an existing backup of a database as the data store. The clone uses copy-on-write technology, so only changed blocks need to be stored locally, while the unchanged data is referenced directly from the backup files. This drastically increases the speed of cloning a system and means that several separate clones can function against a single set of backup datafiles, thus saving considerable amounts of space.
The backups used as the read-only source datafiles must not change during the lifespan of the instance. They can't be wound forward, like incrementally updated image copy backups, without discarding the clonedb clones.
For this test we have the following servers.
NFS Server: Name : nas1 IP Address : 192.168.2.2 NFS share : /u01/nfs_shares/clonedb/test Production Database Server: Name : prod IP Address : 192.168.2.171 ORACLE_HOME: /u01/app/oracle/product/11.2.0.2/db_1 ORACLE_SID : PROD CloneDB Database Server: Name : test IP Address : 192.168.2.172 ORACLE_HOME: /u01/app/oracle/product/11.2.0.2/db_1 ORACLE_SID : TEST NFS Mount : /u01/app/oracle/oradata/TEST
The database servers are running Oracle 11.2.0.2 (64-bit) on Oracle Enterprise Linux (OEL 5.5 64-bit). The Oracle installation is similar to that described here. The "clonedb" server is a software-only installation.
- The Clone Perl Script
- NFS Server Setup
- Production Backup
- CloneDB Server Setup
- Outstanding Issues
- Considerations
Related articles.
The Clone Perl Script
This article was originally written again 11gR2, where the only source of the "clone.pl" script was from the My Oracle Support (MOS) Note 1210656.1, which also documents its usage. I'd like to say a big thank you to Kevin Closson and Margaret Susairaj from Oracle for introducing me to the feature and helping me to get it up and running. You can see a short video presentation and video demo of CloneDB on Kevin Closson's blog here.
In later releases the Perl script is shipped in the "$ORACLE_HOME/rdbms/install" directory and has been renamed to "clonedb.pl" . Any reference in this article to "clone.pl" can substituted for "clonedb.pl" if you are using a later release.
NFS Server Setup
On the NFS server, create a directory as the copy-on-write location for the cloned instance.
# mkdir -p /u01/nfs_shares/clonedb/test
Export the directory as an NFS share by adding the following lines to the "/etc/exports" file.
/u01/nfs_shares/clonedb/test *(rw,sync,no_wdelay,insecure,insecure_locks,no_root_squash)
Make sure the NFS service is available after reboot and restart the NFS service.
# chkconfig nfs on # service nfs restart
Production Backup
We have to take an image copy of the database using RMAN. The backup should be placed in a location available to the server that will run the clone. In this case I am using a samba (CIFS) share for the "/host/backups/prod" location, but it could just as easily be an NFS mount.
$ rman target=/ configure controlfile autobackup off; #sql 'alter database begin backup'; run { set nocfau; backup as copy database format '/host/backups/prod/%U' ; } #sql 'alter database end backup';
The MOS note suggests switching the database to backup mode during the backup, but this is not necessary.
Next, create a PFILE from the contents of the production SPFILE.
SQL> -- On production server as the SYS user. SQL> CREATE PFILE='/host/backups/prod/initTEST.ora' FROM SPFILE;
Amend the contents of the PFILE to reflect the clone database. Here is the amended PFILE I used. In this case my original database name was PROD, so I have replaced all references to that database name with TEST.
TEST.__db_cache_size=205520896 TEST.__java_pool_size=25165824 TEST.__large_pool_size=4194304 TEST.__oracle_base='/u01/app/oracle'#ORACLE_BASE set from environment TEST.__pga_aggregate_target=293601280 TEST.__sga_target=549453824 TEST.__shared_io_pool_size=0 TEST.__shared_pool_size=301989888 TEST.__streams_pool_size=4194304 *.audit_file_dest='/u01/app/oracle/admin/TEST/adump' *.audit_trail='DB' *.compatible='11.2.0.2.0' *.control_files='/u01/app/oracle/oradata/TEST/control01.ctl','/u01/app/oracle/oradata/TEST/control02.ctl' *.db_block_size=8192 *.db_create_file_dest='/u01/app/oracle/oradata/TEST/' *.db_domain='WORLD' *.db_name='TEST' *.db_recovery_file_dest_size=4070572032 *.db_recovery_file_dest='/u01/app/oracle/fast_recovery_area' *.diagnostic_dest='/u01/app/oracle' *.dispatchers='(PROTOCOL=TCP) (SERVICE=TESTXDB)' *.event='' *.memory_target=843055104 *.open_cursors=300 *.processes=150 *.remote_login_passwordfile='EXCLUSIVE' *.undo_tablespace='UNDOTBS1' # Following parameter is also needed for 11.2.0.3 onward. #*.clonedb=true
Database versions 11.2.0.3 onward include a new initialization parameter called CLONEDB
that must be set to TRUE in the clone for the CloneDB functionality to work. Thanks to Marcin Przepiorowski for pointing out this change.
CloneDB Server Setup
Make sure the Direct NFS client is enabled for the Oracle home on the server that will run the clone.
$ cd $ORACLE_HOME/rdbms/lib $ make -f ins_rdbms.mk dnfs_on
Make directories for the NFS mount point, along with some others needed by the TEST instance.
# su - oracle $ mkdir -p $ORACLE_BASE/oradata/TEST $ mkdir -p $ORACLE_BASE/fast_recovery_area/TEST $ mkdir -p $ORACLE_BASE/admin/TEST/adump $ mkdir -p $ORACLE_BASE/admin/TEST/dpdump
Add the following line into the "/etc/fstab" file so the share is mounted automatically on reboot.
nas1:/u01/nfs_shares/clonedb/test /u01/app/oracle/oradata/TEST nfs rw,bg,hard,nointr,tcp,vers=3,timeo=600,rsize=32768,wsize=32768,actimeo=0 0 0
Mount the backup share. If you are consistent with the UID of the OS "oracle" user the ownership and permissions should be fine.
# mount /u01/app/oracle/oradata/TEST
Move the PFILE to the "$ORACLE_HOME/dbs" directory.
# su - oracle $ mv /host/backups/prod/initTEST.ora $ORACLE_HOME/dbs
Remove everything other than datafile image copies from the backup directory. If other file types are present, a later script will assume they are datafiles when creating the new controlfile. The contents of my backup directory is displayed below.
$ cd /host/backups/prod $ ls -l total 1662132 -rw-r----- 1 oracle vboxsf 362422272 Feb 4 10:07 data_D-PROD_I-153794047_TS-EXAMPLE_FNO-5_0nm3qgqb -rw-r----- 1 oracle vboxsf 555753472 Feb 4 10:06 data_D-PROD_I-153794047_TS-SYSAUX_FNO-2_0mm3qgph -rw-r----- 1 oracle vboxsf 744497152 Feb 4 10:06 data_D-PROD_I-153794047_TS-SYSTEM_FNO-1_0lm3qgoo -rw-r----- 1 oracle vboxsf 78651392 Feb 4 10:07 data_D-PROD_I-153794047_TS-UNDOTBS1_FNO-3_0om3qgqq -rw-r----- 1 oracle vboxsf 5251072 Feb 4 10:07 data_D-PROD_I-153794047_TS-USERS_FNO-4_0pm3qgqt $
Set the following environment variables to the appropriate values for your setup.
$ export ORACLE_SID=TEST $ export MASTER_COPY_DIR=/host/backups/prod $ export CLONE_FILE_CREATE_DEST=/u01/app/oracle/oradata/TEST $ export CLONEDB_NAME=TEST
Switch to the "/tmp" directory and run the clone Perl script, naming the correct "init.ora" file to start the instance and specifying name for the cloning script it will create.
$ # 11gR2. $ cd /tmp $ perl /u01/software/clone.pl $ORACLE_HOME/dbs/initTEST.ora crtdb.sql dbren.sql $ # Later Releases. $ cd /tmp $ perl $ORACLE_HOME/rdbms/install/clonedb.pl $ORACLE_HOME/dbs/initTEST.ora crtdb.sql dbren.sql
Start SQL*Plus as SYSDBA and run the scripts created by the clone Perl script. The cloning script contains a generated CREATE CONTROLFILE
command and calls to DBMS_DNFS.CLONEDB_RENAMEFILE
to associate the copy-on-write location with the backup datafile.
$ sqlplus / as sysdba @crtdb.sql @dbren.sql
The following output shows you what to expect.
$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.2.0 Production on Wed Feb 2 21:39:34 2011 Copyright (c) 1982, 2010, Oracle. All rights reserved. Connected to an idle instance. SQL> @crtdb.sql SQL> SET FEEDBACK 1 SQL> SET NUMWIDTH 10 SQL> SET LINESIZE 80 SQL> SET TRIMSPOOL ON SQL> SET TAB OFF SQL> SET PAGESIZE 100 SQL> SQL> STARTUP NOMOUNT PFILE=/u01/app/oracle/oradata/TEST/initTEST.ora ORACLE instance started. Total System Global Area 839282688 bytes Fixed Size 2231128 bytes Variable Size 629146792 bytes Database Buffers 205520896 bytes Redo Buffers 2383872 bytes SQL> CREATE CONTROLFILE REUSE SET DATABASE TEST RESETLOGS 2 MAXLOGFILES 32 3 MAXLOGMEMBERS 2 4 MAXINSTANCES 1 5 MAXLOGHISTORY 908 6 LOGFILE 7 GROUP 1 '/u01/app/oracle/oradata/TEST/TEST_log1.log' SIZE 100M BLOCKSIZE 512, 8 GROUP 2 '/u01/app/oracle/oradata/TEST/TEST_log2.log' SIZE 100M BLOCKSIZE 512 9 DATAFILE 10 '/host/backups/prod/data_D-PROD_I-153794047_TS-EXAMPLE_FNO-5_0nm3qgqb', 11 '/host/backups/prod/data_D-PROD_I-153794047_TS-SYSAUX_FNO-2_0mm3qgph', 12 '/host/backups/prod/data_D-PROD_I-153794047_TS-SYSTEM_FNO-1_0lm3qgoo', 13 '/host/backups/prod/data_D-PROD_I-153794047_TS-UNDOTBS1_FNO-3_0om3qgqq', 14 '/host/backups/prod/data_D-PROD_I-153794047_TS-USERS_FNO-4_0pm3qgqt' 15 CHARACTER SET WE8DEC; Control file created. SQL> @dbren.sql SQL> REM Rename clonedb files to local copy from backup SQL> declare 2 begin 3 dbms_dnfs.clonedb_renamefile('/host/backups/prod/data_D-PROD_I-153794047_TS-EXAMPLE_FNO-5_0nm3qgqb' , '/u01/app/oracle/oradata/TEST/ora_data_TEST0.dbf'); 4 dbms_dnfs.clonedb_renamefile('/host/backups/prod/data_D-PROD_I-153794047_TS-SYSAUX_FNO-2_0mm3qgph' , '/u01/app/oracle/oradata/TEST/ora_data_TEST1.dbf'); 5 dbms_dnfs.clonedb_renamefile('/host/backups/prod/data_D-PROD_I-153794047_TS-SYSTEM_FNO-1_0lm3qgoo' , '/u01/app/oracle/oradata/TEST/ora_data_TEST2.dbf'); 6 dbms_dnfs.clonedb_renamefile('/host/backups/prod/data_D-PROD_I-153794047_TS-UNDOTBS1_FNO-3_0om3qgqq' , '/u01/app/oracle/oradata/TEST/ora_data_TEST3.dbf'); 7 dbms_dnfs.clonedb_renamefile('/host/backups/prod/data_D-PROD_I-153794047_TS-USERS_FNO-4_0pm3qgqt' , '/u01/app/oracle/oradata/TEST/ora_data_TEST4.dbf'); 8 end; 9 / PL/SQL procedure successfully completed. SQL> SQL> REM open clone database SQL> WHENEVER SQLERROR CONTINUE SQL> alter database open resetlogs; Database altered. SQL> SQL> REM create any temp tablespaces needed SQL> drop tablespace TEMP; drop tablespace TEMP * ERROR at line 1: ORA-12906: cannot drop default temporary tablespace SQL> create temporary tablespace TEMP; create temporary tablespace TEMP * ERROR at line 1: ORA-01543: tablespace 'TEMP' already exists SQL>
If the backup is fuzzy it may need media recovery using the archived redo logs from production. You can do this using the following commands.
RECOVER DATABASE USING BACKUP CONTROLFILE UNTIL CANCEL; ALTER DATABASE OPEN RESETLOGS;
Once the scripts are complete you will have a functioning clone.
COLUMN df_name FORMAT A50 COLUMN ts_name FORMAT A10 SELECT t.name AS ts_name, d.name AS df_name, status FROM v$datafile d JOIN v$tablespace t ON t.ts# = d.ts# ORDER BY t.name; TS_NAME DF_NAME STATUS ---------- -------------------------------------------------- ------- EXAMPLE /u01/app/oracle/oradata/TEST/ora_data_TEST0.dbf ONLINE SYSAUX /u01/app/oracle/oradata/TEST/ora_data_TEST1.dbf ONLINE SYSTEM /u01/app/oracle/oradata/TEST/ora_data_TEST2.dbf SYSTEM UNDOTBS1 /u01/app/oracle/oradata/TEST/ora_data_TEST3.dbf ONLINE USERS /u01/app/oracle/oradata/TEST/ora_data_TEST4.dbf ONLINE SQL>
We can see the copy-on-write location doesn't contain a whole copy of the backup datafiles, just the changed blocks, using the "du" command. If listed using the "ls" command they show as full size.
$ du -k /host/backups/prod/* 354280 /host/backups/prod/data_D-DB11G_I-199362479_TS-EXAMPLE_FNO-5_1mmjkqp5 717512 /host/backups/prod/data_D-DB11G_I-199362479_TS-SYSAUX_FNO-2_1kmjkqmb 738012 /host/backups/prod/data_D-DB11G_I-199362479_TS-SYSTEM_FNO-1_1jmjkqku 563764 /host/backups/prod/data_D-DB11G_I-199362479_TS-UNDOTBS1_FNO-3_1lmjkqno 30764 /host/backups/prod/data_D-DB11G_I-199362479_TS-USERS_FNO-4_1nmjkqpv $ $ du -k /u01/app/oracle/oradata/TEST/*.dbf 16 /u01/app/oracle/oradata/TEST/ora_data_TEST0.dbf 52 /u01/app/oracle/oradata/TEST/ora_data_TEST1.dbf 76 /u01/app/oracle/oradata/TEST/ora_data_TEST2.dbf 176 /u01/app/oracle/oradata/TEST/ora_data_TEST3.dbf 16 /u01/app/oracle/oradata/TEST/ora_data_TEST4.dbf 8832 /u01/app/oracle/oradata/TEST/TEST_ctl.dbf $
Outstanding Issues
In 11gR2 the "clone.pl" script is still not bullet proof.
The script doesn't handle the TEMP tablespace correctly. It needs to create a new TEMP tablespace, make it the default temporary tablespace, then drop the existing tablespace. Should replace current part of script with something like this.
CREATE TEMPORARY TABLESPACE TEMP2; ALTER DATABASE DEFAULT TEMPORARY TABLESPACE TEMP2; DROP TABLESPACE TEMP; ALTER TABLESPACE TEMP2 RENAME TO TEMP;
There is a typo in the "clonedb.pl" script shipped with 12.1.0.2 onward, resulting the following error.
Missing braces on \o{} clonedb.pl line 247, near "$lne' , '$clonedbdir"
This is fixed by the following change to line 247 of the "clonedb.pl" script.
from: print OUTFILE1 "dbms_dnfs.clonedb_renamefile('$lne' , '$clonedbdir/\ora_data_$cldbname$i.dbf'); \n"; to: print OUTFILE1 "dbms_dnfs.clonedb_renamefile('$lne' , '$clonedbdir/ora_data_$cldbname$i.dbf'); \n";
Thanks to Patrick Jolliffe for pointing this out and Martin Bach for his post about it.
Considerations
Here are some things to consider before choosing to use this approach.
- The image copy backups must remain read-only and unchanged for the lifetime of all clonedb instances using them as the source datafiles. If these image copies are part of an incrementally updated image copy backup schedule, they are likely to be wound forward every day, making them inappropriate for anything other than short-lived clones.
- Over time more and more blocks will get written to the copy-on-write location for each instance, which in turn will reduce the space savings associated with the clones. Imagine a scenario where you create 10 clones from one set of backups. You have effectively made 10 instances using the disk space for 1. Over time you could get to the point where all blocks in all instance have been touched, and written to the copy-on-write location, leaving you with 10 instances taking up the disk space for 11.
- For a long-term clone, the faster creation time becomes a very small percentage of the lifespan of the clone, so any time savings compared to an RMAN duplicate may become less relevant.
Clone DB has a sweet spot, where you need to create several short-lived clones quickly and you want to save space while you are doing it. It's not a blanket replacement for other cloning techniques.
For more information see:
- My Oracle Support (MOS) Note 1210656.1
- Oracle Database 11g Direct NFS CloneDB Feature – Part I.
- Cloning a Database with CloneDB
Hope this helps. Regards Tim...