Oracle et les PDBs, épisode II : l'attaque des clones

Il y a bien longtemps, dans une galaxie lointaine, très lointaine...

Vous vous souvenez sûrement de l'article sur les pluggables databases d'Oracle où je présentais via un cas concret comment les copies de PDBs peuvent nous faciliter la vie.

Aujourd'hui, nous allons voir comment effectuer des copies instantanées de PDB via les snapshots du filesystem BTRFS.

En effet, le besoin de notre client ayant évolué, il souhaitait avoir deux bases de DEV rafraîchies tous les jours par la production. Comme ce client est en "Standard Edition 2", il n'était pas possible d'avoir plusieurs PDBs dans la même instance. Nous avons donc créé une seconde instance.

Pour rappel, voici le schéma d'architecture :

PDBcopy.png

Voici comment se déroulait le rafraîchissement sur la plateforme de DEV jusqu'à présent :

côté standby :

  • 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

côté serveur de DEV :

  • 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

C'est cette partie que l'on va faire évoluer. Comme notre filesystem est de type BTRFS, nous allons créer un subvolume pour la PDB avant la copie des données
et nous allons ensuite effectuer un clone de ce subvolume via la commande btrfs subvolume snapshot. Ce clone devient le subvolume de la PDB de la seconde instance.

Le script ressemble désormais à ça :
A noter : le script de cet article est fourni à titre indicatif et ne doit pas être utilisé tel quel.

#!/bin/bash
#
#   Plug the production PDB in this environment
#
# check user
if [ "$USER" != "oracle" ]
then
   echo -e "\nPlease execute this script as oracle user.\n"
   exit 1
fi
# export variables
export ORACLE_HOME=/u01/app/oracle/product/12.1/dbhome_1
export PATH=${PATH}:${ORACLE_HOME}/bin
export ORACLE_SID1=ORADEV1
export ORACLE_SID2=ORADEV2
export ORACLE_SID=${ORACLE_SID1}
export ORAENV_ASK=NO
. /usr/local/bin/oraenv
export PDB_NAME=MYPDB
export PDB_USER=PDBUSER
export PDB_PASS=pass1
export PDB_PASS2=pass2
export ORADB_ROOT_PATH=/u01/app/oracle/oradata
export PDBS_ROOT_PATH=${ORADB_ROOT_PATH}/${ORACLE_SID1}
export ORA2_PDBS_ROOT_PATH=${ORADB_ROOT_PATH}/${ORACLE_SID2}
export NASPATH=/nas/backup/Standby_PDB
export XMLPATH=${NASPATH}/mypdb.xml
export SRC_PDB_NAME=MYPDB
export SRC_PDBS_ROOT_PATH=/u01/app/oracle/oradata/ORAPROD
export NEWPDBGUID=fakeguid
export refreshDEV2=y
# check PDB files freshness
DATAFRESHNESS=$((($(date +%s)-$(date -r ${XMLPATH} +%s))/3600))
if [ ${DATAFRESHNESS} -gt 20 ]
  then
    echo "Standby PDB files are too old, re-run the copy_PDB.sh script on the standby server."
    exit 1
fi
# Get GUID of the futur PDB
NEWPDBGUID=$(/usr/bin/xml2 < ${XMLPATH} | grep "/PDB/guid=" | cut -d "=" -f2)
for ORACLE_DB in ${ORACLE_SID1} ${ORACLE_SID2}
do
export ORACLE_SID=${ORACLE_DB}
# check if oracle instance is running
check_stat=`ps -ef|grep ${ORACLE_SID}|grep pmon|wc -l`;
oracle_num=`expr $check_stat`
if [ $oracle_num -lt 1 ]
  then
    echo -e "\nERROR : The oracle instance ${ORACLE_SID} is not running !\n"
    if [ "${ORACLE_SID}" == "${ORACLE_SID1}" ]
      then
       exit 1
      else
       refreshDEV2=n
    fi
  else
# Get GUID of the actual 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 = '${PDB_NAME}';
exit
EOF
)
#check if the PDB GUID is a 32 hexadecimal characters
if ! [[ ${PDBGUID} =~ ^[0-9A-F]{32}$ ]]
  then
    echo -e "\nERROR : The PDB GUID ${PDBGUID} is not valid !\n"
    exit 1
  else
    # drop the PDB
    sqlplus -s /nolog << EOF
conn / as sysdba
alter PLUGGABLE DATABASE ${PDB_NAME} close immediate;
drop PLUGGABLE DATABASE ${PDB_NAME} including datafiles;
shutdown immediate;
exit
EOF
   sleep 3
  sqlplus -s /nolog << EOF
conn / as sysdba
startup;
exit
EOF
   sleep 3
# drop the PDB's btrfs subvolume
sudo /usr/sbin/btrfs subvolume list "${ORADB_ROOT_PATH}/${ORACLE_SID}/${PDBGUID}" && sudo /usr/sbin/btrfs subvolume delete "${ORADB_ROOT_PATH}/${ORACLE_SID}/${PDBGUID}"
fi
fi
done
# create the PDB's btrfs subvolume for the first instance
sudo /usr/sbin/btrfs subvolume list "${PDBS_ROOT_PATH}/${NEWPDBGUID}" || sudo /usr/sbin/btrfs subvolume create "${PDBS_ROOT_PATH}/${NEWPDBGUID}"
sudo /usr/bin/chown oracle:oinstall "${PDBS_ROOT_PATH}/${NEWPDBGUID}"
# copy all datafiles from the filer for the first instance
cp -r ${NASPATH}/${SRC_PDB_NAME}/${NEWPDBGUID}/* ${PDBS_ROOT_PATH}/${NEWPDBGUID}/
# clone the btrfs subvolume for the second Oracle instance
if [ ${refreshDEV2} == "y" ]
  then
    sudo /usr/sbin/btrfs subvolume snapshot "${PDBS_ROOT_PATH}/${NEWPDBGUID}" "${ORA2_PDBS_ROOT_PATH}/${NEWPDBGUID}"
    sudo /usr/bin/chown oracle:oinstall "${ORA2_PDBS_ROOT_PATH}/${NEWPDBGUID}"
fi
# create the PDB on first instance ( wich is registred on the standard 1521 listener port )
export ORACLE_SID=${ORACLE_SID1}
sqlplus -s /nolog << EOF
conn / as sysdba
create pluggable database ${PDB_NAME} using '${XMLPATH}' SOURCE_FILE_NAME_CONVERT=('${SRC_PDBS_ROOT_PATH}','${PDBS_ROOT_PATH}') nocopy tempfile reuse;
alter pluggable database ${PDB_NAME} open;
exit
EOF
# set the password of this environment in the pdb of the first instance
sqlplus -s /nolog << EOF
conn / as sysdba
alter session set container = ${PDB_NAME};
alter user ${PDB_USER} identified by "${PDB_PASS}";
alter user ${PDB_USER} account unlock;
exit
EOF
# create the PDB on second instance wich is registred on a dedicated listener (port 1522)
if [ ${refreshDEV2} == "y" ]
  then
    export ORACLE_SID=${ORACLE_SID2}
    sqlplus -s /nolog << EOF
conn / as sysdba
create pluggable database ${PDB_NAME} using '${XMLPATH}' SOURCE_FILE_NAME_CONVERT=('${SRC_PDBS_ROOT_PATH}','${ORA2_PDBS_ROOT_PATH}') nocopy tempfile reuse;
alter pluggable database ${PDB_NAME} open;
exit
EOF
    # set the password of this environment in the pdb of the second instance
    sqlplus -s /nolog << EOF
conn / as sysdba
alter session set container = ${PDB_NAME};
alter user ${PDB_USER} identified by "${PDB_PASS2}";
alter user ${PDB_USER} account unlock;
exit
EOF
fi

Et voilà !
La création de la PDB de la deuxième instance se fait en quelques secondes grâce au clone BTRFS et comme peu de données sont modifiées dans chacune des PDBs des instances ORADEV1 et ORADEV2, le gain en espace disque est lui aussi considérable !

Alors, allez-vous passer du Côté Obscur de la Force ?

Ecrit par christophe LE ROUX - Architecte DBA chez Claranet France

10 ans d'expérience sur les technologies Oracle (RAC, Dataguard, multi-tenant, ...) Postgresql (Hot Standby, PGPool,..) ou encore MySQL (réplication, clusters,..), je m'intéresse particulièrement aux architectures haute disponibilité mono ou multi-sites. Mes hobbies tournent autour de l'électronique et la programmation de microcontrôleur.
Linkedin

Contactez-nous

Contactez-nous

Nous construisons des solutions sur mesure pour nos clients.
Les informations recueillies à partir de ce formulaire font l’objet d’un traitement informatique destiné à la société Claranet afin de nous permettre de traiter la demande pour laquelle vous nous sollicitez. Les destinataires des données sont les services marketing et commerciaux du groupe Claranet. Conformément à la loi « informatique et libertés » du 6 janvier 1978 modifiée, vous disposez d’un droit d’accès et de rectification aux informations qui vous concernent. Veuillez-vous rapportez à la section des mentions légales de notre site internet pour de plus amples informations sur les modalités d’exercice de ces droits. Vous pouvez également, pour des motifs légitimes, vous opposer au traitement des données vous concernant.
1 + 0 =
Trouvez la solution de ce problème mathématique simple et saisissez le résultat. Par exemple, pour 1 + 3, saisissez 4.

Pour contacter un commercial

N'hésitez pas à nous appeler au 0826 007 656

Besoin de contacter le support technique ?
Nos équipes sont disponibles en 24x7x365.

Support Virtual Data Centre au 0826 007 653 (Numéro indigo)
Support Infogérance applicative au 0810 278 385 (Numéro indigo)
Support Colocation au 0826 007 653 (Numéro indigo)
Support Cloud Public en envoyant un mail à support