Comment copier une base de données multi-environnents ? Les PDBs à la rescousse

Avant Oracle 12c, lorsqu’on souhaitait copier des données d’une base à une autre en Standard Edition, on n’avait pas beaucoup de choix. Généralement on utilisait les exports/imports mais ça pouvait être long, voire très long …
Avec l’arrivée d’Oracle 12c, de nouvelles solutions se profilent, dont la copie de PDB (Pluggable Database). C’est ce que nous avons mis en œuvre pour l’un de nos clients.

Celui-ci souhaitait avoir une copie quotidienne de sa base de production sur son environnement de développement, et une copie hebdomadaire sur son environnement de préproduction.

Des tests avec Datapump ont été effectués. Résultat : le temps de rafraichissement était de l’ordre de 7 heures pour un schéma d’environ 80Go et plus de 1500 tables. Trop long pour le client…

Nous allons voir comment passer à 25 minutes grâce aux PDBs.

Les licences Oracle de ce client étant des Standard Edition 2, nous ne pouvions utiliser qu’une seule PDB par CDB. Qu’importe, nous n’avons pas besoin de plus.

Architecture :

Voici le schéma de l’architecture :

PDBcopy.png

Nous avons donc pour la production un serveur primaire avec sa CDB et sa PDB et un serveur standby (pas de Dataguard, car c’est une option de l’Enterprise Edition, donc copie et application des archives via un script qui tourne toute les 15 minutes). Tous 2 sont reliés en 10 Gb/s à un réseau dédié pour cette réplication et pour la copie de PDB vers le filer haute perf.
La plateforme de préproduction a son propre serveur avec sa CDB et sa PDB (qui sera écrasée hebdomadairement). Ce serveur est relié en 1 Gb/s au filer haute perf.
La plateforme de développement a son propre serveur avec sa CDB et sa PDB (qui sera écrasée quotidiennement). Ce serveur est relié en 1 Gb/s au filer haute perf.

Nous avons choisi d’utiliser un filer pour que :
- les environnements de production, préproduction et développement ne communiquent pas directement entre eux
- la copie de PDB vers les serveurs de préproduction et de développement puisse se faire de façon simultanée sans double impact sur la production (cas hebdomadaire)

Copie de la PDB de production
Il faut savoir que lorsqu’on veut copier ou cloner une PDB, celle-ci doit être en lecture seule. Comme il paraît difficile de mettre la base de production en lecture seule, la copie de la PDB sera faite à partir de la Standby.

Voici les étapes :

  • Mise en pause du process de recover des archivelogs sur la standby
  • Copie sur le montage NFS du filer via lien 10Gb/s de l’ensemble des datafiles de la PDB
  • Génération du fichier de description xml de la PDB sur le montage NFS du filer
  • Réactivation du process de recover des archivelogs de la standby

Ce traitement est effectué par le script ci-dessous(1) présent dans la crontab du user oracle du serveur de standby. La copie de la PDB prend environs 5 minutes (grâce au lien 10Gb/s).

Attention : Si vous utilisez OMF sans ASM sur votre primaire et standby, le répertoire nommé par le GUID de la PDB n’est pas repris par la commande duplicate de RMAN lors de la construction de votre standby. Si votre PDB est créée sur la primaire après la mise en place de la standby, vous n’aurez pas ce problème. Il est donc possible que les paths générés dans le xml ne soient pas conformes à la primaire, ils n’ont pas le GUID de la PDB. Un simple sed dans ce xml permet de définir l’emplacement des datafiles de votre PDB et donc de contourner ce problème.


#!/bin/bash
#
# Copy the standby of the production PDB on NAS
#

export ORACLE_HOME=/data/app/oracle/product/12.1/dbhome_1
export PATH=${PATH}:${ORACLE_HOME}/bin
export ORACLE_SID=CDBPROD
export ORAENV_ASK=NO
. /usr/local/bin/oraenv

export NASPATH=/data/app/oracle/backup/Standby_PDB

echo "Copy the standby of the production PDB on NAS"
echo "============================================="
echo "`date '+%d/%m-%H:%M:%S'`"

# Check if PDB is in mount Status
PDBSTATUS=$(sqlplus -s /nolog << EOF
conn / as sysdba
set pagesize 0 feedback off verify off heading off echo off;
select open_mode from v\$pdbs where name = 'MYPDB';
exit
EOF
)

if [ "${PDBSTATUS}" != "MOUNTED" ] && [ "${PDBSTATUS}" != "READ ONLY" ]
then
echo "The PDB is not in MOUNTED or READ ONLY state (Status = ${PDBSTATUS} ), can't copy it."
exit 1
fi

# Suspend archivelogs recover
echo "`date '+%d/%m-%H:%M:%S'` Suspend the archivelogs recover process and wait a minute"
touch /tmp/suspend_recover

# wait a minute in case of the recover was launch just before suspend it
sleep 60

# clean previous refresh
rm -Rf ${NASPATH}/MYPDB/*
rm -f ${NASPATH}/pdb_mypdb.xml

# create the xml description of the PDB
echo "`date '+%d/%m-%H:%M:%S'` Create the xml description on NAS"
sqlplus -s /nolog << EOF2 2>&1
conn / as sysdba
alter database open read only;
exec dbms_pdb.describe(pdb_descr_file=>'${NASPATH}/pdb_mypdb.xml', pdb_name =>'mypdb');
shutdown immediate
startup nomount
alter database mount standby database;
exit
EOF2

# Get the GUID from the xml file
if [ -f ${NASPATH}/pdb_mypdb.xml ]
then
GUID=$(xmllint --xpath '//PDB/guid/text()' ${NASPATH}/pdb_mypdb.xml)
fi

# Get the datafile list
if [ -f ${NASPATH}/pdb_mypdb.xml ]
then
DBFLIST=$(xmllint --xpath '//PDB/tablespace/file/path' ${NASPATH}/pdb_mypdb.xml | sed 's/<\/path>/\n/g;s///g')
fi

# Create the directories
mkdir -p ${NASPATH}/MYPDB/${GUID}/datafile

# copy all files of the PDB
echo "`date '+%d/%m-%H:%M:%S'` Start the copy on NAS"
for file in ${DBFLIST}
do
cp -p ${file} ${NASPATH}/MYPDB/${GUID}/datafile/
done

# change the directory tree in the xml file (to respect the OMF tree)
sed -i "s/\/CDBPROD\/datafile/\/CDBPROD\/${GUID}\/datafile/g" ${NASPATH}/pdb_mypdb.xml

# Resume archivelogs recover
echo "`date '+%d/%m-%H:%M:%S'` Resume archivelogs recover"
rm -f /tmp/suspend_recover

Recréation de la PDB sur les environnements de dev/preprod

Pour pouvoir rafraichir les PDBs des environnements de développement et de pré-production, nous devons :

supprimer les PDBs actuelles,
recopier les fichiers de la PDB de prod présents sur le montage NFS du filer vers les disques locaux,
et créer les PDBs à partir du fichier de description xml.

Voici les étapes :

  • Si le fichier xml présent sur le montage NFS du filer a moins de 20h (en cas de reprise en journée), suppression de la PDB actuelle et de ses datafiles
  • Recopie des datafiles de la PDB de production depuis le montage NFS du filer vers les disques locaux
  • Création de la PDB à partir du fichier de description xml de la production présent sur le montage NFS du filer

A savoir : le process de recréation de la PDB est effectué simultanément sur les environnements de développement et de préproduction hebdomadairement.
La copie/recréation de PDB en simultané sur les 2 environnements prend environs 20 minutes.

Ce traitement est effectué par le script(1) ci-dessous présent en crontab du user oracle.

#!/bin/bash

#
# Plug the production PDB in the new environment
#

export ORACLE_HOME=/data/app/oracle/product/12.1/dbhome_1
export PATH=${PATH}:${ORACLE_HOME}/bin
export ORACLE_SID=CDBDEV
export ORAENV_ASK=NO
. /usr/local/bin/oraenv

export NASPATH=/data/app/oracle/backup/Standby_PDB

# check PDB files freshness
DATAFRESHNESS=$((($(date +%s)-$(date -r ${NASPATH}/pdb_mypdb.xml +%s))/3600))

if [ ${DATAFRESHNESS} -gt 20 ]
then
echo "Standby PDB files are too old, re-run the copy_PDB.sh script on the production standby server."
exit 1
fi

# Get GUID of the PDB
PDBGUID=$(sqlplus -s /nolog << EOF
conn / as sysdba
set pagesize 0 feedback off verify off heading off echo off;
select guid from v\$pdbs where name = 'MYPDB';
exit
EOF
)

# drop the PDB
sqlplus -s /nolog << EOF
conn / as sysdba
alter PLUGGABLE DATABASE MYPDB close immediate;
drop PLUGGABLE DATABASE MYPDB including datafiles;
exit
EOF

if [ -n "${PDBGUID}" ]
then
rm -Rf /data/app/oracle/oradata/${ORACLE_SID}/${PDBGUID}
fi

# copy all datafiles
cp -r ${NASPATH}/MYPDB/* /data/app/oracle/oradata/${ORACLE_SID}/

# create the PDB
sqlplus -s /nolog << EOF
conn / as sysdba
create pluggable database MYPDB using '${NASPATH}/pdb_mypdb.xml' SOURCE_FILE_NAME_CONVERT=('/data/app/oracle/oradata/CDBPROD','/data/app/oracle/oradata/${ORACLE_SID}') nocopy tempfile reuse;
alter pluggable database MYPDB open;
exit
EOF

# set the password of the new environment
sqlplus -s /nolog << EOF
conn / as sysdba
alter session set container = mypdb;
alter user MYUSER identified by "newpassforthisenv";
alter user MYUSER account unlock;
exit
EOF

Conclusion : des bases de données copiées/clonées simplement et rapidement grâce aux Pluggable databases.
Christophe LE ROUX, DBA Claranet en charge de l’implémentation des nouveaux projets
(1)A noter : les scripts de cet article sont fournis à titre indicatif et ne doivent pas être utilisés tels quels.