Skip to main content

Command Palette

Search for a command to run...

Monitorizando Dataguard en Bash

Updated
4 min read
Monitorizando Dataguard en Bash
C

Mi nombre es Carla y me defino como una apasionada de conocer, compartir ideas, divertirme y aprender todo lo relacionado con Oracle.

Alegre y creativa, con un alto grado de autoexigencia, que busca, incluso sin querer, una forma diferente de ver un mismo problema o solución. Defensora del trabajo en equipo en todas las facetas de la vida y de disfrutar todo lo que haces, siempre con humildad.

Actualmente cuento con más de 15 años de experiencia como administradora de Oracle, habiendo ocupado previamente posiciones como desarrolladora en la rama de Inteligencia de Negocios. Fue en ese momento que me di cuenta de que no quería centrarme en el desarrollo, sino participar en todas las capas que involucraban los datos, desde el despliegue de la base de datos hasta su explotación final.

Siempre estoy dispuesta a ayudar y compartir conocimientos. Creo firmemente que con la tecnología hay que divertirse y no verla como una competencia. La persona con la que tienes que ser el mejor es contigo mismo.

Cuántas veces nos hemos encontrado con una integración de monitorización cuando entra en juego DG?

Pues lo voy a poner fácil. Lo hacemos en un script con las recomendaciones de Oracle. La versión con la que trabajo es 19c, importante.

En este caso está planificado en nagios, pero sería perfectamente válido para otras plataformas como zabbix. Al final lo que importa es la salida ( Ok, Warning, Critical) y/o el exit code.

La idea es que pasándole el SID pueda distinguir si es Primaria o Standby y poder planificar el script para Standby y Primaria y que solo salte cuando se cumpla el rol para el chequeo.

Las alertas query_apply_lag y query_transport_lag están parametrizadas para saltar a los 5 minutos, es ajustable al entorno.

Os presento uno de los Carli-scripts que os facilitará la vida. Empezamos?

check_dg.sh
check_dg.sh <ORACLE_SID> <query_archive_dest|query_gaps|query_errors|query_loging|query_apply_lag|query_transport_lag|query_datafiles_offline|query_mrp

Tiene buena pinta verdad? Espera que invoquemos con el SID y el chequeo concreto.

En qué me baso?

Monitoring Oracle Data Guard Configuration Health Using SQL 19c

Para ello he desarollado el siguiente script:

[nagios@rac-prueba-001 ~]$ cat /home/oracle/check_dg.sh
#!/bin/bash
# Verificar que se haya pasado ORACLE_SID como argumento
if [ "$#" -ne 2 ]; then
    echo "Uso: $0 <ORACLE_SID> <query_archive_dest|query_gaps|query_errors|query_loging|query_apply_lag|query_transport_lag|query_datafiles_offline|query_mrp>"
    exit 1
fi


#Variables entorno de BBDD
ORACLE_SID=$1
ORAENV_ASK=NO
. oraenv -s

#Variable chequeo
OPCION_CHECK=$2

# Configuración de conexión
dbname=$ORACLE_SID  # El nombre de la base de datos será el mismo que ORACLE_SID
dbuser='system'
dbpass='Temporal01'

# Función para ejecutar un comando SQL y devolver los resultados
ejecutar_sqlplus() {
    local sql=$1
    $ORACLE_HOME/bin/sqlplus -s "$dbuser/$dbpass@$dbname" <<EOF
    SET PAGESIZE 0
    SET FEEDBACK OFF
    SET VERIFY OFF
    SET HEADING OFF
    SET ECHO OFF
    $sql
    EXIT;
EOF
}


# Verificar si la base de datos es primaria
query_role=$(cat <<EOF
SELECT DATABASE_ROLE FROM v\$database;
EOF
)

#################### STANDBY ##########################

# Consulta de chequeo lag apply
query_apply_lag=$(cat <<EOF
        SELECT name || ': ' || max(value)
        FROM gv\$dataguard_stats
        WHERE   name = 'apply lag'
                AND TO_DSINTERVAL(value) > NUMTODSINTERVAL(15,'MINUTE')
        GROUP BY NAME;
EOF
    )

# Consulta de chequeo lag transport
query_transport_lag=$(cat <<EOF
        SELECT name || ': ' || max(value)
        FROM gv\$dataguard_stats
        WHERE   name = 'transport lag'
                AND TO_DSINTERVAL(value) > NUMTODSINTERVAL(15,'MINUTE')
        GROUP BY NAME;
EOF
    )


# Data file check (offline files or files that are not accessible)
query_datafiles_offline=$(cat <<EOF
    select 'Hay ' || count(*) || ' datafiles en estado offline'
     from v\$datafile_header
     where     status ='OFFLINE'
         or ERROR is not null
        having count(*)>0;
EOF
    )

# Verify that the Media Recovery Process is currently running. Tiene que devolver fila
query_mrp=$(cat <<EOF
    select count(*)
     from gv\$managed_standby
     where process like 'MRP%'
        having count(*)>0;
EOF
    )

#################### PRIMARIA ########################

# Consulta de chequeo errores arhive dest
query_archive_dest=$(cat <<EOF
    WITH AggregatedData AS (
            SELECT inst_id, substr(error,1,9) error
            from gv\$archive_dest_status
            where type='PHYSICAL'
        and status!='VALID'
    )
    SELECT 'Instancia: ' || LISTAGG(inst_id, ',') WITHIN GROUP (ORDER BY inst_id) || ' Errores: ' || LISTAGG(error, ',') WITHIN GROUP (ORDER BY error) AS result
    FROM AggregatedData
        HAVING COUNT(*) > 0;
EOF
    )

# Consulta de chequeo gaps
query_gaps=$(cat <<EOF
    select LISTAGG(inst_id, ',') WITHIN GROUP (ORDER BY inst_id) || ' ' ||  database_mode || ' ' || recovery_mode || ' ' || gap_status
     from gv\$archive_dest_status
     where     type='PHYSICAL'
         and gap_status !='NO GAP'
    group by database_mode,recovery_mode, gap_status;

EOF
    )

# severe Data Guard event occurred in the last day    
query_errors=$(cat <<EOF
    WITH AggregatedData AS (
      SELECT inst_id, COUNT(*) AS count
      FROM gv\$dataguard_status
      WHERE     severity IN ('Error', 'Fatal')
            AND timestamp > (sysdate - 1)
      GROUP BY inst_id
    )
    SELECT 'Instancia: ' || LISTAGG(inst_id, ',') WITHIN GROUP (ORDER BY inst_id) || ' Numero errores: ' || LISTAGG(count, ',') WITHIN GROUP (ORDER BY inst_id) AS result
    FROM AggregatedData
        HAVING COUNT(*) > 0;
EOF
    )

# Check if any NOLOGGING activity occurred on the primary database in the last day    
query_loging=$(cat <<EOF
    SELECT CASE
         WHEN COUNT(*) > 0 THEN 'Hay datafiles con NOLOGGING activity en el último día. File ID: ' ||
                                  LISTAGG(file#, ',') WITHIN GROUP (ORDER BY file#)
         ELSE NULL
           END AS result
    FROM v\$datafile
    WHERE unrecoverable_time > (sysdate - 1);
EOF
    )

role_output=$(ejecutar_sqlplus "$query_role")

if [ "$role_output" = "PRIMARY" ]; then

    case $OPCION_CHECK in
        query_archive_dest)
            check_output=$(ejecutar_sqlplus "$query_archive_dest")
            if [ -n "$check_output" ]; then
                echo "[CRITICAL] $check_output"
                        exit 2
            fi

            ;;
        query_gaps)
                check_output=$(ejecutar_sqlplus "$query_gaps")
                if [ -n "$check_output" ]; then
                        echo "[CRITICAL] $check_output"
                        exit 2
                fi

            ;;
        query_errors)
                check_output=$(ejecutar_sqlplus "$query_errors")
                if [ -n "$check_output" ]; then
                        echo "[CRITICAL] $check_output"
             exit 2
                fi

            ;;
        query_loging)
                check_output=$(ejecutar_sqlplus "$query_loging")
                if [ -n "$check_output" ]; then
                        echo "[WARNING] $check_output"
            exit 1
                fi

            ;;
        query_datafiles_offline)
                check_output=$(ejecutar_sqlplus "$query_datafiles_offline")
                if [ -n "$check_output" ]; then
                        echo "[WARNING] $check_output"
                        exit 1
                fi

            ;;
    esac
fi

if [ "$role_output" = "PHYSICAL STANDBY" ]; then
    case $OPCION_CHECK in
        query_apply_lag)
                check_output=$(ejecutar_sqlplus "$query_apply_lag")
                if [ -n "$check_output" ]; then
                        echo "[CRITICAL] $check_output"
            exit 2
                fi

            ;;
        query_transport_lag)
                check_output=$(ejecutar_sqlplus "$query_transport_lag")
                if [ -n "$check_output" ]; then
                        echo "[CRITICAL] $check_output"
            exit 2
                fi

            ;;
        query_datafiles_offline)
                check_output=$(ejecutar_sqlplus "$query_datafiles_offline")
                if [ -n "$check_output" ]; then
                        echo "[WARNING] $check_output"
            exit 1
                fi

            ;;
        query_mrp)
                check_output=$(ejecutar_sqlplus "$query_mrp")
                if [ -n "$check_output" ]; then
             echo "[OK]"
                        exit 0
                else
            echo "[CRITICAL]. No hay procesos activos de replicación."
            exit 2
                fi

            ;;

    esac

fi

echo "[OK]"
exit 0

Qué esperamos? Devolverá un OK si todo está en orden, WARNING o CRITICAL junto con la información asociada en una sola línea cuando no es así. Es totalmente customizable.

Lo pruebas y me cuentas?

[usuario_monitorizacion@rac-prueba-001 ~]$ /home/oracle/check_dg.sh cdbpro query_archive_dest
[OK]

More from this blog

Carla Muñoz López

65 posts

Soy DBA senior de bases de datos Oracle y me defino como una persona alegre y creativa. Apasionada por conocer, compartir ideas, divertirme y seguir aprendiendo todo lo relacionado con Oracle.