Creando una estrategia de seguridad incremental con image copies

Hoy vamos a ver como plantear una estrategia de seguridad distinta a la clásica estrategia de RMAN backupsets , esta nueva estrategia se va a basar en image copies y nos va a requerir mucho mas espacio en disco ( el mismo que la base de datos),pero lo que nos permitirá es por el contrario un tiempo de recuperación muchisimo menor.

Nos aseguramos que tenemos suficiente espacio en la FRA (Flash Recovery Area) para albergar nuestra base de de datos entera.

Vemos que tenemos 15,4 Gb libres en la FRA,  la ocupación de nuestra base de datos la calcularemos desde el sistema operativo con el comando

[oracle@test] du -sh oradata/orcl/
5.5G    oradata/orcl/

Ahora haremos un backup de toda nuestra base de datos  al que llamaremos incremental en copias

Nos conectamos a nuestra base de datos y al catálogo de RMAN y ejecutaremos el comando:

run {
1> recover copy of database with tag 'incremental en copias';
2 > backup incremental level 1 for recover of copy with tag 'incremental en copias' database;
}

Viendo el texto de nuestro bloque RUN, lo primero que os estareis preguntando es :
¿por que hacemos un recover si lo que queremos hacer es un backup?
veamos que hacen las  dos lineas del script de backup, pero vamos a verlo en orden inverso.

2> La línea backup incremental level 1 for recover of copy with tag ‘incremental en copias’ database; nos va ha hacer un backup image copy de los ficheros de la base de datos, en caso de no encontrar alguna copia anterior con el tag ‘incremental en copias’  hará una imagecopy completa del datafile, pero , si encontrara una imagecopy anterior con ese tag, lo que hará es copiar solamente los cambios incrementales de esa imagecopy.

1> El comando recover copy of database with tag ‘incremental en copias’; no va ha hacer un recovery de los ficheros de la base de datos, lo que va ha hacer es, recuperar sobre la image copy ‘incremental en copias’ los cambios incrementales que encuentre creados por la línea  2> .

Esto que a priori puede ser muy lioso, se ve claramente si ejecutamos nuestros bloque de rman varias veces.

Vamos a ejecutar nuestros script de backup para comprobar que lo dicho anteriormente es cierto


Veamos la salida del comando en la primera ejecucion

Vemos la linea 1 del script  no ha hecho nada, y nuestra linea 2  es similar a la que saldría haciendo un simple backup  basado encopias de todos los datafiles de la base de datos.

Ejecucion 1
Starting recover at 23/08/12
using channel ORA_DISK_1
no copy of datafile 1 found to recover
no copy of datafile 2 found to recover
no copy of datafile 3 found to recover
no copy of datafile 4 found to recover
no copy of datafile 5 found to recover
Finished recover at 23/08/12

Starting backup at 23/08/12
using channel ORA_DISK_1
no parent backup or copy of datafile 3 found
no parent backup or copy of datafile 1 found
no parent backup or copy of datafile 2 found
no parent backup or copy of datafile 4 found
no parent backup or copy of datafile 5 found
channel ORA_DISK_1: starting datafile copy
input datafile file number=00003 name=/opt/oracle/oradata/orcl/undotbs01.dbf
output file name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_undotbs1_83dn40z2_.dbf tag=INCREMENTAL EN COPIAS RECID=94 STAMP=792092958
channel ORA_DISK_1: datafile copy complete, elapsed time: 00:02:18
channel ORA_DISK_1: starting datafile copy
input datafile file number=00001 name=/opt/oracle/oradata/orcl/system01.dbf
output file name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_system_83dn8gv0_.dbf tag=INCREMENTAL EN COPIAS RECID=95 STAMP=792093020
channel ORA_DISK_1: datafile copy complete, elapsed time: 00:00:55
channel ORA_DISK_1: starting datafile copy
input datafile file number=00002 name=/opt/oracle/oradata/orcl/sysaux01.dbf
output file name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_sysaux_83dnb5vv_.dbf tag=INCREMENTAL EN COPIAS RECID=96 STAMP=792093064
channel ORA_DISK_1: datafile copy complete, elapsed time: 00:00:45
channel ORA_DISK_1: starting datafile copy
input datafile file number=00004 name=/opt/oracle/oradata/orcl/users01.dbf
output file name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_users_83dnclot_.dbf tag=INCREMENTAL EN COPIAS RECID=97 STAMP=792093085
channel ORA_DISK_1: datafile copy complete, elapsed time: 00:00:15
channel ORA_DISK_1: starting datafile copy
input datafile file number=00005 name=/opt/oracle/oradata/orcl/example01.dbf
output file name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_example_83dnd1yn_.dbf tag=INCREMENTAL EN COPIAS RECID=98 STAMP=792093093
channel ORA_DISK_1: datafile copy complete, elapsed time: 00:00:07
Finished backup at 23/08/12

Starting Control File and SPFILE Autobackup at 23/08/12
piece handle=/opt/oracle/flash_recovery_area/ORCL/autobackup/2012_08_23/o1_mf_s_792093100_83dndg0h_.bkp comment=NONE
Finished Control File and SPFILE Autobackup at 23/08/12

 

Si lo ejecutamos por segunda vez, el comando recover copy of database with tag ‘incremental en copias’  (línea 1) seguirá sin encontrar un backup llamado asi, con lo que no aplicará nada, pero el comando backup incremental level 1 for recover of copy with tag ‘incremental en copias’ database; (línea 2)  si que encontrará cambios en la base de datos, con lo que si que debería de copiar nuevos datos.
Veamos que ocurre si lo ejecutamos de nuevo

Ejecucion 2
RMAN> run {
recover copy of database with tag 'incremental en copias';
backup incremental level 1 for recover of copy with tag 'incremental en copias' database;
}2> 3> 4>

Starting recover at 23/08/12
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=149 device type=DISK
no copy of datafile 1 found to recover
no copy of datafile 2 found to recover
no copy of datafile 3 found to recover
no copy of datafile 4 found to recover
no copy of datafile 5 found to recover
Finished recover at 23/08/12

Starting backup at 23/08/12
using channel ORA_DISK_1
channel ORA_DISK_1: starting incremental level 1 datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00003 name=/opt/oracle/oradata/orcl/undotbs01.dbf
input datafile file number=00001 name=/opt/oracle/oradata/orcl/system01.dbf
input datafile file number=00002 name=/opt/oracle/oradata/orcl/sysaux01.dbf
input datafile file number=00004 name=/opt/oracle/oradata/orcl/users01.dbf
input datafile file number=00005 name=/opt/oracle/oradata/orcl/example01.dbf
channel ORA_DISK_1: starting piece 1 at 23/08/12
channel ORA_DISK_1: finished piece 1 at 23/08/12
piece handle=/opt/oracle/flash_recovery_area/ORCL/backupset/2012_08_23/o1_mf_nnnd1_INCREMENTAL_EN_COPIA_83dntqbk_.bkp tag=INCREMENTAL EN COPIAS comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:03:15
Finished backup at 23/08/12

Starting Control File and SPFILE Autobackup at 23/08/12
piece handle=/opt/oracle/flash_recovery_area/ORCL/autobackup/2012_08_23/o1_mf_s_792093756_83do0xlz_.bkp comment=NONE
Finished Control File and SPFILE Autobackup at 23/08/12

¿Que ocurrirá en la tercera ejecución?

El comando recover copy of database with tag ‘incremental en copias’ ya tiene que haber encontrado datos ya que tiene la primera copia,con lo que esta vez si que ejecutará en recover, pero no lo hará sobre los datafiles originales, sino que aplicará los cambios que hemos guardado en la ejecución 2 sobre las copias de la ejecución 1 y el incremental que hemos hecho antesvolverá a encontrar cambios en la base de datos, con lo que si que debería de volver a copiar nuevos datos.
Veamos la salida de esta tercera ejecución:

 Ejecucion 3
RMAN> run {
recover copy of database with tag 'incremental en copias';
backup incremental level 1 for recover of copy with tag 'incremental en copias' database;
}
2> 3> 4>
Starting recover at 23/08/12
using channel ORA_DISK_1
channel ORA_DISK_1: starting incremental datafile backup set restore
channel ORA_DISK_1: specifying datafile copies to recover
recovering datafile copy file number=00001 name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_system_83dn8gv0_.dbf
recovering datafile copy file number=00002 name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_sysaux_83dnb5vv_.dbf
recovering datafile copy file number=00003 name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_undotbs1_83dn40z2_.dbf
recovering datafile copy file number=00004 name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_users_83dnclot_.dbf
recovering datafile copy file number=00005 name=/opt/oracle/flash_recovery_area/ORCL/datafile/o1_mf_example_83dnd1yn_.dbf
channel ORA_DISK_1: reading from backup piece /opt/oracle/flash_recovery_area/ORCL/backupset/2012_08_23/o1_mf_nnnd1_INCREMENTAL_EN_COPIA_83dntqbk_.bkp
channel ORA_DISK_1: piece handle=/opt/oracle/flash_recovery_area/ORCL/backupset/2012_08_23/o1_mf_nnnd1_INCREMENTAL_EN_COPIA_83dntqbk_.bkp tag=INCREMENTAL EN COPIAS
channel ORA_DISK_1: restored backup piece 1
channel ORA_DISK_1: restore complete, elapsed time: 00:00:07
Finished recover at 23/08/12

Starting backup at 23/08/12
using channel ORA_DISK_1
channel ORA_DISK_1: starting incremental level 1 datafile backup set
channel ORA_DISK_1: specifying datafile(s) in backup set
input datafile file number=00003 name=/opt/oracle/oradata/orcl/undotbs01.dbf
input datafile file number=00001 name=/opt/oracle/oradata/orcl/system01.dbf
input datafile file number=00002 name=/opt/oracle/oradata/orcl/sysaux01.dbf
input datafile file number=00004 name=/opt/oracle/oradata/orcl/users01.dbf
input datafile file number=00005 name=/opt/oracle/oradata/orcl/example01.dbf
channel ORA_DISK_1: starting piece 1 at 23/08/12
channel ORA_DISK_1: finished piece 1 at 23/08/12
piece handle=/opt/oracle/flash_recovery_area/ORCL/backupset/2012_08_23/o1_mf_nnnd1_INCREMENTAL_EN_COPIA_83do2ztw_.bkp tag=INCREMENTAL EN COPIAS comment=NONE
channel ORA_DISK_1: backup set complete, elapsed time: 00:02:26
Finished backup at 23/08/12

Starting Control File and SPFILE Autobackup at 23/08/12
piece handle=/opt/oracle/flash_recovery_area/ORCL/autobackup/2012_08_23/o1_mf_s_792093966_83do7h1p_.bkp comment=NONE
Finished Control File and SPFILE Autobackup at 23/08/12

Así pues vemos como vamos teniendo un juego de image copies de la base de datos que se van actualizando diariamente.

Alguna de las características de este backup son.

  1. Menor tiempo de recuperacion: El tiempo de recuperacion de uno de estos datafiles  será mas corto que el tiempo que empleariamos en restaurarlo desde un backuppiece ya que el level 0 es un backup image copy
  2. Alta ocupacion en disco: Estos ficheros son un image copy,lo que significa que estamos copiando todo el fichero a la FRA, este la ocupación del datafile al 10% o al 100%

 

 

Gestor de recursos. A la caza del bloqueo I

Hoy  vamos a abordar los problemas de bloqueos desde otro punto de vista.

A pesar de que los bloqueos sonun problema propio de  la aplicación y debe de ser desde esta donde se solucione el evitar sesiones bloqueantes, un código de  aplicacion defectuoso  puede llegar a tirar abajo nuestra instancia , con lo que deberemos de acabar con este tipo de sesiones antes de que afecten a la disponibilidad del sistema.

Oracle nos da la opcion de limitar el tiempo en el que un usuario está IDLE a la vez que  bloquea otra sesion con el parámetro NEW_MAX_IDLE_BLOCKER.

Esta es la primera de un grupo de entradas en las que utilizaremos el gestor de recursos de Oracle para llevar acabo workarrounds que nos solucionen este problema.

Lo primero que haremos es crear un plan al que llamaremos «NO_LOCKS», para ello lo mas sencilllo es copiar el DEFAULT_PLAN desde el EM, si por el contrario queremos hacerlo desde linea de sqlplus tenemos que:

  1. Crear una pending area (si lo hacemos desde sqlplus)
  2. Crear el plan de recursos
  3. Validar el pending area
  4. Enviar/presentar  (submit) esta pending area
BEGIN
dbms_resource_manager.clear_pending_area();
dbms_resource_manager.create_pending_area();
dbms_resource_manager.create_plan( plan => 'NO_LOCKS',
 comment => 'Plan para eliminar bloqueos desde el gestor de recursos, copiado de DEFAULT_PLAN'
);
dbms_resource_manager.create_plan_directive(
    plan => 'NO_LOCKS',
    group_or_subplan => 'SYS_GROUP',   
    comment => 'Asignamos 75% de cpu al grupo SYS ',
    mgmt_p1 => 75
);
dbms_resource_manager.create_plan_directive(
    plan => 'NO_LOCKS',
    group_or_subplan => 'DEFAULT-CONSUMER_GROUP',   
    comment => 'Asignaremos el 90% de CPU al grupo de consumidores por defecto ',
    mgmt_p2 => 90
);
dbms_resource_manager.create_plan_directive(
    plan => 'NO_LOCKS',
    group_or_subplan => 'OTHER_GROUPS',   
    comment => 'Este grupo debe de aparecer ',
    mgmt_p2 => 5
);
dbms_resource_manager.create_plan_directive(
    plan => 'NO_LOCKS',
    group_or_subplan => 'ORA$DIAGNOSTICS',   
    comment => 'Asignamos 5% de cpu al grupo ORA$DIAGNOSTICS en el segundo nivel ',
    mgmt_p2 => 5
 );
 DBMS_RESOURCE_MANAGER.VALIDATE_PENDING_AREA();
DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA();
END;

Con esto tenemos  un nuevo plan llamado «NO_LOCKS» que es similar al DEFAULT_PLAN.

Lo que vamos ha hacer ahora es modificar el subplan que se aplica a todos los usuarios (DEEFAULT_CONSUMER_GROUP) para que no los deje bloquear recursos mas de 5 segundos.

BEGIN
dbms_resource_manager.clear_pending_area();
dbms_resource_manager.create_pending_area();
dbms_resource_manager.update_plan_directive(
    plan => 'NO_LOCKS',
    group_or_subplan => 'DEFAULT_CONSUMER_GROUP',   
    new_comment => 'Subplan para bloqueadores, similar a DEFAULT_CONSUMER_GROUP pero  limitado',
    new_max_idle_blocker_time=>5
    );
DBMS_RESOURCE_MANAGER.VALIDATE_PENDING_AREA;
DBMS_RESOURCE_MANAGER.SUBMIT_PENDING_AREA;
END;

Si miramos los cambios desde el EM podremos ver como   esta el parámetro

Plan NO_LOCK

Ahora solamente nos quedará activar el nuevo plan y probarlo

Esto lo comprobamos con

SQL>ALTER SYSTEM SET RESOURCE_MANAGER_PLAN = 'NO_LOCKS';

SQL> SELECT VALUE FROM V$PARAMETER  WHERE name = 'resource_manager_plan';

VALUE
--------------------------------------------------------------------
NO_LOCKS

Ahora vamos ha hacer la prueba de que funciona

Veamos en que grupo de consumidores está el usuario HR

SQL> select initial_rsrc_consumer_group from dba_users where username='HR';

INITIAL_RSRC_CONSUMER_GROUP
------------------------------
DEFAULT_CONSUMER_GROUP

 

Nos conectamos con el usuario HR y bloquearemos la tabla REGIONS

SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'HH24:MI:SS';
Session altered.
SQL>  select sysdate from dual;
SYSDATE
--------
12:08:13
SQL> select * from  regions where  REGION_ID=1 for update;
 REGION_ID REGION_NAME
---------- -------------------------
         1 Europe
SQL>  select sysdate from dual;
SYSDATE
--------
12:30:18

En el segundo select sysdate vemos como,  pesar de que la tabla esta bloqueada, y que han pasado 15 segundos el gestor de recursos no nos ha hechado.¿habremos hecho algo mal?

La respuesta es que no hemos hecho nada mal, lo que está ocurriendo es que la consulta que hemos ejecutado esta bloqueando algo, pero no esta bloqueando  a nadie .

Que ocurre si intentamos ejecutar una consulta en otra sesion que  se vea bloqueada por esta?

En el momento en l que el gestor de recursos detecta que nuestra primera sesion esta bloqueando a otra empieza a contar los segundos que nuestra primera consulta esta «idle».Al llegar a los 5 segundos matará nuestra consulta bloqueante y liberará sus recursos.

Si tras esos 5 segundos  volvemos a recargar la ventana del EM  veremos que no hay bloqueos, y  si nos vamos a la ventana donde hemos ejecutado nuestra consulta bloquante nos encontraremos con el error:

ORA-02396: ha excedido el tiempo máximo de inactividad, vuelva a conectarse

Con lo que , de manera algo brusca y desde la base de datos hemos conseguido acabar con todos los bloqueos de usuario que estén inactivas mas de 5 segundos.

 


LLegados a este punto tenemos a TODOS los usuarios de la base de datos sin poder llevar a cabo un bloqueo de mas de 5 segundos en cualquier hora del día.

Esto nos va a generar muchos problemas a la hora de los procesos batch e incluso en alguna transaccion pesada, con lo que lo mejor que podemos hacer el volverlo atrás .

El único valor de esta entrada es como ejercicio didactico, asi que, mas nos valdría volver a activar en la base de datos el DEFAULT_PLAN o el INTERNAL_PLAN

En las siguientes entradas afinaremos este plan NO_LOCKS para limitarlo por esquemas y por franja horaria, haciendo de la limitación NEW_MAX_IDLE_BLOCKER_TIME  algo util.

Sqlplus para dummies III ( Bloqueos )

Otra de las cosas que mas amenudo tenemos que hacer es el encontrar quien nos está bloqueando y que bloquea.

Para ello, la consulta mas sencilla que podemos hacer es:

SELECT
     a.session_id , username ,type , mode_held, mode_requested 
     lock_id1,lock_id2
FROM
     sys.v_$session b,
     sys.dba_blockers c,
     sys.dba_lock a
WHERE
     c.holding_session=a.session_id AND
     c.holding_session=b.sid

Pero,  seguramente queramos saber mas cosas, como que tipo de bloqueos y que objetos están implicados, para ello podemos usar esta consulta en la que aparecen  datos de la sesión, del proceso tanto en el server como en el cliente y de los objetos y tipo de bloqueo que lleva a cabo

 

SELECT 
substr(to_char(l.sid),1,4) "SID", 
s.serial# "SERIAL",
P.spid "Server  PID", 
s.USERNAME,
s.type, 
s.process "Client  PID", 
MACHINE, 
l.type, 
DECODE(L.TYPE,'MR','File_ID: '||L.ID1, 
'TM', LO.NAME, 
'TX','USN: '||to_char(TRUNC(L.ID1/65536))||' RWO: '||nvl(RWO.NAME,'None'),L.ID1) LOCK_ID1, 
decode(l.lmode, 
0, 'None', 
1, 'Null', 
2, 'Row-S (SS)', 
3, 'Row-X (SX)', 
4, 'Share', 
5, 'S/Row-X (SSX)', 
6, 'Exclusive', 
substr(to_char(l.lmode),1,13)) "Locked Mode", 
decode(l.request, 
0, 'None', 
1, 'Null', 
2, 'Row-S (SS)', 
3, 'Row-X (SX)', 
4, 'Share', 
5, 'S/Row-X (SSX)', 
6, 'Exclusive', 
substr(to_char(l.request),1,13)) "Requested", 
l.ctime, 
l.block ,
s.logon_time
FROM v$process P, 
v$session S, 
v$lock l, 
sys.obj$ lo, 
sys.obj$ rwo 
WHERE l.sid = S.sid (+) 
AND S.paddr = P.addr (+) 
AND LO.OBJ#(+) = L.ID1 
AND RWO.OBJ#(+) = S.ROW_WAIT_OBJ#
and S.type!='BACKGROUND'
order by SID;

Tablas que desaparecen en el export

Hola

Vamos hoy con un pequeño expediente X. tenemos una base de datos 11g de la que queremos mover los datos a una base de datos de test. Lo primero que se nos ocurre es hacer un export de la misma con el comando exp  y llevarla a el entorno de test.

Sinembargo, al llegar a allí nos damos cuenta de que faltan objetos.

¿como es posible que nuestro export de toda la vida no haya sacado todas las tablas del esquema?

La respuesta es sencilla : por haber usado nuestro export de toda la vida

Aunque muchas veces sea mas comodo el uso del exp que de el expdp  ( especialmente por no tener que crear un directorio en la instancia),  el uso del exdp debería de ser obligatorio en nuestro día a dia,  ya que nos salvará de quebraderos de cabeza como este.

Pero,  seguramente  os estaréis preguntando a que es debido este problema.

 

Oracle 11g viene con la nueva funcionalidad deferred_segment-creation=TRUE activada por defecto.  Esto provoca que, al crear los objetos del esquema de la aplicacion en la base de datos no cree todos los segmentos de los mismos, sino que solamente creee los segmentos que contienen datos.

Nuestro «export de toda la vida» no es capaz de detectar esto,  exportandonos «solamente» los segmentos exsistentes en la base de datos,  sin embargo,  el nuevo expdp es mas listo,  y es capaz de exportar todos los objetos,  independientemente de que contengan datos  o no.

¿Como saber si tengo este tipo de tablas?

Podemos ver que objetos no están creados con la columna SEGMENT_CREATED  de las vistas del USER_TABLES, USER_INDEXES o USER_LOBS.

pregunta a ver que tablas  no tienen segmentos, si estásen una 11g seguramente te lleves una sorpresa.

select * from user_TABLES where  SEGMENT_CREATED='N'

Y en lo que se refiere a esta nueva funcionalidad de la 11g, cuidadito con ella,  por que,   seguramente nos traera algún que otro susto mas.