miércoles, 16 de julio de 2014

Migración de Base de Datos Oracle desde AIX, HP-UX o Solaris hacia Linux con mínima indisponibilidad de servicio

       Cuando se requiere migrar una base hacia una plataforma con distinto endian (ej: desde Solaris SPARC a Linux X64) la única alternativa es usar XTTS (Transportable Tablespaces con conversión). Para realizar dicho procedimiento se necesita tener los tablespaces en modo read only durante la transferencia de los datafiles al nuevo servidor. Esto provoca una indisponibilidad parcial, ya que se pueden realizar consultas pero no cambios sobre los tablespaces involucrados. El tiempo de indisponibilidad será directamente proporcional al volumen a copiar y este tiempo en muchos casos es inviable para el negocio.

       A partir de 11.2.0.4 y en adelante se puede usar backups incrementales con conversión de endian para reducir el tiempo de indisponibilidad al mínimo posible. El procedimiento es un tanto mas complejo que el tradicional pero Oracle provee los scripts para realizarlo en forma mas sencilla. 

       Es importante aclarar que este procedimiento es recomendable solo para migraciones hacia distinto endian, y en general se da cuando se quiere pasar a Linux desde AIX, Solaris y HP-UX. Es el método elegido para migrar a Exadata. Cuando no se requiere conversión en la migración el método sugerido es DATA GUARD.


Pasos para migrar usando el método Tradicional

Los pasos son en general los siguientes:
  1. Setear los tablespaces en origen en READ ONLY
  2. Transferir los datafiles de los tablespaces puesto en RO al nuevo servidor
  3. Convertir los datafiles en destino al nuevo endian (también puede convertir a nivel tablespace en origen).
  4. Exportar la metadata de los tablespaces en la base de datos origen (expdp)
  5. Importar la metadata de los tablespaces en la base destino (impdp)
  6. Setear los tablespaces en origen en READ WRITE

Pasos para migrar usando XTTS con backups incrementales

Fase de Preparación
  1.           Transferir los datafiles a destino
  2.           Convertir los datafiles al endian del servidor destino

Fase de Roll-Forward (repetir los pasos de esta fase tantas veces sea necesario para mantener los datafiles actualizados respecto a los originales)
  1.           Crear backup incrementales en origen
  2.           Transferir los backups incrementales a destino
  3.           Convertir los backups incrementales al endian de destino y aplicar el backup     los  datafiles en destino

Fase de Transporte
  1.           Setear los tablespaces en orgen como READ ONLY
  2.           Repetir la fase de Roll-Forward por ultima vez.
  3.           Exportar la metadata de los tablespaces en la base de datos origen (expdp)
  4.           Importar la metadata de los tablespaces en la base destino (impdp)
  5.           Setear los tablespaces en origen en READ WRITE

Ahora voy a mostrar un ejemplo paso a paso de como realizar la migración. En los procesos tomo en cuenta que puedan existir datafiles con el mismo nombre (con distinto path) y por lo tanto agrego algunos pasos extra (creación de links simbolicos, cambio temporal de nombres de datafiles para hacerlos únicos, etc)

Descripción del Paso a Paso

Etapa 1: Preparación

1 .1 Generar Script para Crear los link simbólicos temporales 

Genera el script que deberá ejecutarse como etapa de preparación para poder realizar la aplicación de cambios incrementales. Es necesario dado que el script perl que realiza la generación y aplicación de backup incrementales solo puede definir un solo directorio.
SQL@ROPHOST1> select 'ln -s ' || file_name ||' /ROP/lnks/' || 
replace(ltrim(file_name,'/ROP/'),'/','_'from dba_data_files
where tablespace_name in ('TS_DATA','TS_INDEX')
El script generado es:  crear_links.sh que deberá ejecutarse desde shell en el sitio origen para que se creen los links de soporte a la migración

1.2 Verificar que los tablespaces a transferir estén autocontenidos

Ejecutar el siguiente sp:
SQL@ROPHOST1> begin
                dbms_tts.transport_set_check('TS_DATA','TS_INDEX',true,true);
             end;
             /
Chequear si hubieron inconsistencias o invalidaciones:
SQL@ROPHOST1> SELECT FROM transport_set_violations;

En base origen
SQL@ROPHOST1> create directory sourcedir as '/ROP/lnks'
En base destino
SQL@ROPHOST2> create directory destdir as '/ROP/lnks';
En base destino crear un dblink
SQL@ROPHOST2> create public database link ttslink connect to system 
identified by <password> using 'ROP.WORLD';

1.4 Descomprimir en $ORACLE_HOME/xtt el archivo rman-xttconvert.zip en origen y destino

Icon
[oracle@ROPHOST1 xtt]$ unzip rman_xttconvert_1.4.zip
Archive: rman_xttconvert_1.4.zip
inflating: xttcnvrtbkupdest.sql
inflating: xttdbopen.sql
inflating: xttdriver.pl
inflating: xttprep.tmpl
inflating: xtt.properties
inflating: xttstartupnomount.sql
[oracle@ROPHOST1 xtt]$pwd
/home/oracle/xtt

1.5 Crear directorios de almacenamiento temporal en origen y destino

[oracle@ROPHOST1]$ mkdir /home/oracle/xtt/tmp
[oracle@ROPHOST1]$ set TMPDIR=/home/oracle/xtt/tmp
[oracle@ROPHOST2]$ mkdir /home/oracle/xtt/tmp
[oracle@ROPHOST2]$ export TMPDIR=/home/oracle/xtt/tmp

1.6 Configurar el archivo de propiedades en el sitio origen  y destino

Editar el archivo de propiedades xtt.properties en el sitio origen y cambiar las siguientes lineas:
El archivo xtt.properties, luego de editarlo y adecuar los valores para ROP es: xtt.properties 
Icon

Linea 35:
tablespaces=TS_DATA,TS_INDEX

Linea 44:
## El id 6 corresponde a plataforma Solaris 64 (origen)
platformid=2

Linea 54:
srcdir=SOURCEDIR

Linea 60:
dstdir=DESTDIR

Linea 67:
srclink=TTSLINK

Linea 94:
## Path donde se alojaran los backups incrementales
backupformat=/RESTORE/RMANINC/ROP
Linea 115:
## Path donde se alojaran los backups incrementales para ser convertidos en destino
stageondest=/RESTORE/RMANINC/ROP

Linea 134:
## Path donde se
backupondest=/RESTORE/RMANINC/ROP


Copiar el archivo de propiedades al sitio destino
[oracle@ROPHOST1]$ scp /home/oracle/xtt/xtt.properties ROPHOST2:/home/oracle/xtt/.

1.7 Crear los directorios que deberán contener los backups incrementales intermedios en origen (stage_orig) y destino  (stage_dest)

[oracle@ROPHOST1]$ mkdir /RESTORE/RMANINC/ROP
[oracle@ROPHOST2]$ mkdir /RESTORE/RMANINC/ROP

Etapa 2: Pasaje de Datos Inicial

2.1 Verificación y Preparación en base origen

En este paso se verifica que los tablespaces a transportar (indicados en el archivo de propiedades) estén en modo READ WRITE y que no tengan datafiles offline. 
[oracle@ROPHOST1]$ cd /home/oracle/xtt
[oracle@ROPHOST1]$ perl xttdriver.pl -S
La salida para transportar los tablespaces debe ser similar a la siguiente:

Icon
Prepare source for Tablespaces:
'TS_DATA','TS_INDEX'/RESTORE/RMANINC/ROP
xttpreparesrc.sql for 'TS_DATA','TS_INDEX'started at Wed Jul 9 14:15:49 2014


[oracle@host1 xtt]$

Una vez finalizado el comando se generan los siguientes archivos en el directorio definido por la variable de entorno TMPDIR
  • xttnewdatafiles.txt
  • getfile.sql
  • xttplan.txt
  • xttprepare.cmd

2.2 Copiar los archivos xttnewdatafiles.txt y getfile.sql creados en la etapa anterior

[oracle@ROPHOST2]$ scp oracle@ROPHOST1:/home/oracle/xtt/tmp/xttnewdatafiles.txt   /home/oracle/xtt/tmp
[oracle@ROPHOST2]$ scp oracle@ROPHOST1:/home/oracle/xtt/tmp/getfile.sql /home/oracle/xtt/tmp

2.3 Adecuar los archivo xttnewdatafiles.txt y getfile.sql para que funcione con un solo directorio origen y destino

Copiar en /home/oracle/xtt y ejecutar en sqlplus en base origen el siguiente .sql: gen_replace_df_lnk_getfile.sql cuyo código se muestra a continuación:
gen_replace_df_lnk_getfile.sql
set pagesize 9999
set line 150
set heading off
set feedback off
set term off
spool /home/oracle/xtt/replace_df_lnks.sh
select 'sed -i ''s/' || regexp_substr(file_name,'[^/]*$') || '/' || replace(ltrim(file_name,'/ROP/'),'/','_')||'/g'' getfile.sql' from dba_data_files
where tablespace_name in
('TS_DATA',
'TS_INDEX')
/
spool off

Hacer lo mismo para el archivo xttnewdatafiles.txt usando el sql: replace_df_lnks_xttnewdf.sh

La ejecución del .sql anterior en origen permite adecuar la copia inicial de datafiles a destino permitiendo usar los links simbolicos. El resultado es spooleado en el archivo: replace_df_lnks.sh
SQL@ROPHOST1>@/home/oracle/xtt/gen_replace_df_lnks_ROP.sql

Copiar a destino el shell generado en el paso anterior. Dicho .sh adecuará el getfile.sql (original) copiado
[oracle@ROPHOST2]$ scp oracle@ROPHOST1:/home/oracle/xtt/replace_df_lnks.sh /home/oracle/xtt/
Por ultimo ejecutar el shell para que realice el reemplazo para que agregue el sufijo de directorio a los archivos que se alojaran temporalmente en /ROP/lnks del sitio destino
[oracle@ROPHOST2]$/home/oracle/xtt/replace_df_lnks.sh
La ejecución anterior dejará un getfile,sql (adecuado) que se usará para el próximo paso.

2.4 Transferir y Convertir los datafiles

oracle@ROPHOST2]$ cd /home/oracle/xtt
oracle@ROPHOST2]$ perl xttdriver.pl -G
 Una vez ejecutado el comando anterior deberían estar pasados y convertidos los datafiles en el directorio temporal /ROP/lnks. 
Si se requiere reprocesar, los datafiles no deben existir en destino, de lo contrario el comando fallará. También podría ser necesario eliminar el siguiente archivo /home/oracle/xtt/tmp/TESTFAILED.

2.5 Verificar que se haya realizado la transferencia de todos los datafiles

Verificar que no exista el archivo que se genera cuando hay errores
oracle@ROPHOST2]$ ls -l /home/oracle/xtt/tmp/TESTFAILED

Chequear que se haya pasado todos los datafiles
oracle@ROPHOST2]$ ls /ROP/lnks wc -l
[oracle@ROPHOST1]$ ls /ROP/lnks wc -l
Las dos salidas deben retornar el mismo número (326). 

FASE 3: Aplicación Incremental de Cambios

3.1 Crear el backup incremental de los tablespaces transportados


[oracle@ROPHOST1]$ perl xttdriver.pl -i
El comando crea los siguientes archivos, con información de lo que se tiene que aplicar
  • tsbkupmap.txt
  • incrbackups.txt

3.2 Transferir el backup incremental a destino

Se copian los archivos de backup incremental generado con RMAN al ejecutar el comando de 3.1
[oracle@ROPHOST1]$ scp `cat /home/oracle/xtt/tmp/incrbackups.txt` oracle@ROPHOST2:/RESTORE/RMANINC/ROP

3.3 Convertir los backup incrementales y aplicar los cambios a los datafiles copiados en el sitio destino


oracle@ROPHOST2]$ scp oracle@ROPHOST1:/home/oracle/xtt/tmp/xttplan.txt  /home/oracle/xtt/tmp
oracle@ROPHOST2]$ scp oracle@ROPHOST1:/home/oracle/xtt/tmp/tsbkupmap.txt /home/oracle/xtt/tmp

oracle@ROPHOST2]$ perl xttdriver.pl -r
La salida esperada del comando debería ser similar  a la siguiente:

Icon
Start rollforward
End of rollforward phase

3.4 Determinar el nuevo SCN para usar en FROM_SCN registrado en el archivo xttplan.txt

En el sitio origen obtener el próximo SCN para saber desde donde aplicar los nuevos cambios 

[oracle@ROPHOST1]$ perl xttdriver.pl -s

3.5 Repetir la Fase 3 o pasar directamente a la Fase 4

Si se quiere mantener los datafiles copiados en destino lo mas cercano a los datafiles originales se pueden repetir los pasos anteriores (desde 3.1 en adelante), de lo contrario se puede pasar a la ultima etapa (Fase 4)

FASE 4: Fase de Transporte

4.1 Setear en solo lectura (READ ONLY) los tablespaces a migrar 


SQL@ROPHOST1> alter tablespace TS_DATA read only;
SQL@ROPHOST1> alter tablespace TS_INDEX read only;


4.2 Crear el backup incremental final, transferir, convertir y aplicar en destino


[oracle@ROPHOST1]$ perl xttdriver.pl -i
[oracle@ROPHOST1]$ scp `cat incrbackups.txt` oracle@ROPHOST1:/RESTORE/RMANINC/ROP
oracle@ROPHOST2]$ scp oracle@ROPHOST1:/home/oracle/xtt/tmp/xttplan.txt /home/oracle/xtt/tmp
oracle@ROPHOST2]$ scp oracle@ROPHOST1:/home/oracle/xtt/tmp/tsbkupmap.txt /home/oracle/xtt/tmp
oracle@ROPHOST2]$ perl xttdriver.pl -r

4.3  Importar la metadata en la base destino

En el sitio destino conectado con oracle ejecutar:

oracle@ROPHOST2]$ perl xttdriver.pl -e
El comando genera el archivo  xttplugin.txt  con el comando para importar los datos desde origen usando el dblink creado en al Fase 1 (ttslink) usando el modo network_link de Oracle Data Pump
Luego ejecutar copiar el siguiente sh en el destino (ROPHOST2) en la carpeta /home/oracle/xtts/tmp/  rename_final_dest.sh . El mismo realiza el renombrado de los datafiles a su ruta final y también adecua el archivo xttplugin.txt .
#directorio base a partir del cual se mueven los archivos
BASE_PATH=/ROP
#directorio donde están los dbf convertidos
SOURCE_PATH=/ROP/lnks
#SH_FILE=change_impdp_xttplugin.sh
###MAIN
#>change_impdp_xttplugin.sh
for i in `ls $SOURCE_PATH | grep dbf`
do
    DIR=`echo $i | sed  's/_/ /1' | awk '{ print $1 }'`
    DBNAME=`echo $i | sed  's/_/ /1' | awk '{ print $2 }'`
    echo "cp -p $SOURCE_PATH/$i $BASE_PATH/$DIR/$DBNAME"
    cp -p $SOURCE_PATH/$i $BASE_PATH/$DIR/$DBNAME
    echo "sed -i 's?${SOURCE_PATH}/${DBNAME}?${BASE_PATH}/$DIR/$DBNAME?g' xttplugin.txt"
    sed -i 's?'${SOURCE_PATH}'/'${DBNAME}'?'${BASE_PATH}'/'$DIR'/'$DBNAME'?g' xttplugin.txt
done
Luego de esto ejecutar el import dentro del archivo xttplugin.txt 


4.4 Setear en READ WRITE los tablespace en READ ONLY en Origen


SQL@ROPHOST1> alter tablespace TS_DATA read write;
SQL@ROPHOST1> alter tablespace TS_INDEX read write;


4.5 Validar los datos transportados y Setear en READ WRITE los tablespaces en destino (los tablespaces migrados)


RMAN@ROPHOST2> validate tablespace TS_DATA, TS_INDEX check logical

SQL@ROPHOST2> alter tablespace TS_DATA read write;
SQL@ROPHOST2> alter tablespace TS_INDEX read write;