Configurar en el cron el script de backup RMAN en RAC en todos los nodos

Photo by Trent Erwin on Unsplash

Configurar en el cron el script de backup RMAN en RAC en todos los nodos

Cuando trabajamos en un entorno de alta disponibilidad, donde tenemos un clúster con instancias levantadas en todos los nodos, o en nodos concretos, se complica la parte de configurar el backup cuando es gestionado mediante cron.

La idea es tener un script configurado que esté planificado en todos ellos, pero que solo se ejecute desde uno siguiendo un criterio. ¿Qué sentido tiene que se ejecute el backup de RMAN desde todos ellos a la vez?

Aquí entran en juego varias variables:

  • Quién es el master? Si no tenemos separación de roles (importante porque si lo tenemos el usuario en SO de Oracle no ejecutará comandos de clúster) podemos automatizar en el script que busque el MASTER NODE. La programación en cron estaría habilitada en todos los nodos, pero solo el nodo maestro ejecutará el script porque en una arquitectura de clúster, solo existirá un nodo maestro a la vez. Es tan simple como detectarlo y manejarlo con oclumon manage -get master.

  • Tengo separación de roles o quiero que solo dependa de la instancia de BBDD la evaluación de disponibilidad y ejecución del backup.

En mi caso trabajo con separación de roles. Oracle tiene su parcela y la grid tiene la suya. Qué quiere decir? que quiero que sean independientes, que no interactuen más allá de adminitración y comunicación propia de ambos.

Para ello he desarrollado un script, en el cual se han valorado las siguientes casuísticas:

  • Definir un nodo preferido en el que quiero que se ejecute prioritariamente. Como decimos en Galicia: se non se pode pois non se pode... malo será

  • El backup se conectará por un servicio dedicado a RMAN que yo controlaré. Aunque el script se ejecutase en el nodo 1 se ejecutará en las instancias donde el servicio esté levantado.

  • Si el nodo preferido no tiene la BBDD abierta se ejecutará desde la siguiente instancia que cumpla el requisito (estar abierta).

  • El script estará habilitado en todos los nodos del clúster, no queremos tener que habilitarlos o deshabilitarlos manualmente en tareas de operación o mantenimiento. Esto quiere decir que tiene que ejecutarse en todos los nodos pero realizar el backup solo desde uno.

Recopilando todas las casuísticas el script funciona de la siguiente manera:

  • Ejecuto el script en todos los nodos. Coincide que la instancia preferida está abierta en el nodo que ejecuta el script? Realizamos backup desde ese nodo

  • La instancia preferida no está Open en el nodo que lo ejecuta? Comprobamos la siguiente instancia. Está abierta en el nodo que lo ejecuta? Realizamos backup desde el nodo de la siguiente instancia.

Parece obvio, pero encaja cuando tenemos más de 2 nodos. La gestión entre dos es simple: ejecutas en un nodo o en el otro.

Os presento al script mágico.

#!/bin/bash
export PATH=$PATH:/usr/local/bin:/bin:/usr/bin

# Definir función para ejecutar el script de RMAN
run_rman_script() {
        local INSTANCE_NAME=$1
        echo
    echo "Script RMAN ejecutando en instancia $INSTANCE_NAME"
        echo

    rman target *****/**************@${DB_NAME}_RMAN  @${RMAN_SCRIPT} using $RMAN_TAG log=${RMAN_LOG}/rman-BACKUP_${INSTANCE_NAME}_${FECHA}.out

        echo
        echo "***********************************************"
        echo "** Fin del Backup: $(date +"%Y-%m-%d %H:%M:%S")                             *"
        echo "***********************************************"
        echo
}

HOST_NAME=`hostname -s`

# Tag para backup de RMAN
export RMAN_TAG='RECOVERDIARIOINC'

# Definir la ruta del script de RMAN
RMAN_SCRIPT="/u01/scripts/admin/backup_diario.rman"

# Definir la ruta archivo de salida de RMAN
RMAN_LOG="/u01/scripts/admin/logs"

# Comprueba si se proporcionó el nombre de la base de datos como argumento
if [ $# -lt 2 ]; then
    echo "Error: Debes proporcionar el nombre de la base de datos y el nombre de la instancia activa como argumentos."
    echo "Uso: $0 <nombre_de_tu_base_de_datos> <nombre_de_tu_instancia_activa>"
    exit 1
fi

# Fecha
export FECHA=`date +'%y%m%d_%H%M'`

# Nombre de la base de datos
DB_NAME=$1

# Nombre de la instancia activa
ACTIVE_INSTANCE=$2

#Variables entorno de BBDD
ORACLE_SID=$DB_NAME
ORAENV_ASK=NO
. oraenv

LOGFILE=${RMAN_LOG}/rman-BACKUP_${HOST_NAME}_${FECHA}.out

exec < /dev/null
exec >>$LOGFILE
exec 2>&1

echo
echo "***********************************************"
echo "* Comenzando el backup                        *"
echo "***********************************************"
echo

echo
echo "* DB_NAME:         ${ORACLE_SID}              "
echo "* INSTANCIA_PREF:  ${ACTIVE_INSTANCE}         "
echo "* NODO:            ${HOST_NAME}               "
echo

echo "***********************************************"
echo "Fecha: $(date +"%Y-%m-%d %H:%M:%S")            "
echo "***********************************************"
echo

# Borrado logs antiguos
find ${RMAN_LOG} -type f -mtime +60 -name "rman-BACKUP_*.out" -exec rm {} \;

INSTANCE_INFO=$(srvctl status instance -d $DB_NAME -i $ACTIVE_INSTANCE -verbose)
INSTANCE_STATUS=$(echo "$INSTANCE_INFO" | awk -F 'Instance status: ' '{print $2}'| sed 's/.$//')
INSTANCE_NODE=$(echo "$INSTANCE_INFO" | awk '/Instance.*is running on node/ {print $7}')

# Si la instancia activa definida no está "Open" o "Open, Readonly", directamente buscamos la instancia siguiente abierta
if ! [[ "$INSTANCE_STATUS" =~ "Open" ]]; then

        echo
        echo "La instancia activa definida no está "Open", directamente buscamos la instancia siguiente abierta..."
        echo

    SIGUIENTE_INSTANCIA_INFO=$(srvctl status database -d $DB_NAME -verbose | grep -m 1 'Open' )
    SIGUIENTE_INSTANCIA_NOMBRE=$(echo "$SIGUIENTE_INSTANCIA_INFO" | grep "Instance $DB_NAME"  | awk '{print $2}')
    SIGUIENTE_INSTANCIA_NODE=$(echo "$SIGUIENTE_INSTANCIA_INFO" | awk '/Instance.*is running on node/ {print $7}')

        # Ejecutar el script de RMAN en la primera instancia activa que se encuentre si coincide con el hostname
        if  [ "$SIGUIENTE_INSTANCIA_NODE" = "$HOST_NAME" ]; then
            echo
            echo "Ejecutando script de RMAN en la instancia $SIGUIENTE_INSTANCIA_NOMBRE..."
            echo
            run_rman_script $SIGUIENTE_INSTANCIA_NOMBRE
            exit 0  # Salir después de ejecutar en la primera instancia activa
        fi

    echo
    echo "No se encontraron instancias activas para ejecutar el script de RMAN. $(date +"%Y-%m-%d %H:%M:%S")"
    echo "***********************************************"
    echo

    exit 1

else
    if [ "$INSTANCE_NODE" = "$HOST_NAME" ]; then
        echo
        echo "La instancia $ACTIVE_INSTANCE se está ejecutando en el nodo $INSTANCE_NODE, que coincide con el nodo actual $HOST_NAME. $(date +"%Y-%m-%d %H:%M:%S")"
        echo
        run_rman_script $ACTIVE_INSTANCE
        exit 0
    else
        echo
        echo "La instancia $ACTIVE_INSTANCE no se está ejecutando en el nodo actual $HOST_NAME. $(date +"%Y-%m-%d %H:%M:%S")"    
        echo "***********************************************"
        echo
    fi
fi

A tener en cuenta:

  •         RMAN_TAG=    <<--- TAG del Backup
            RMAN_SCRIPT= <<--- Script de RMAN custom. Ésta parte te la dejo a tí :)
            RMAN_LOG=    <<--- Directorio de logs de RMAN
            find ${RMAN_LOG} -type f -mtime +60 <<--- Gestión de histórico de logs. Al gusto
    

Y como lo invocamos?

[oracle@rac-prueba-001 admin]$ /u01/scripts/admin/script_rman.sh nombre_bbdd instancia_preferida

Siempre todo es mejorable, abierta a sugerencias!