viernes, 22 de diciembre de 2017

ORA-10873

El otro día empecé el día con una BBDD caída por el error ORA-10873.

Mirando el fichero alert se ve como la BBDD está montada pero no se consigue abrir.

Wed Dec 20 00:10:12 2017
MMNL started with pid=16, OS id=2988 
Wed Dec 20 00:10:12 2017
starting up 1 dispatcher(s) for network address '(ADDRESS=(PARTIAL=YES)(PROTOCOL=TCP))'...
starting up 1 shared server(s) ...
ORACLE_BASE from environment = /u01
Wed Dec 20 00:10:16 2017
alter database mount exclusive
Successful mount of redo thread 1, with mount id 1972990760
Database mounted in Exclusive Mode
Lost write protection disabled
Completed: alter database mount exclusive
alter database open
Errors in file ..\orcl_ora_3104.trc:
ORA-10873: file 1 needs to be either taken out of backup mode or media recovered
ORA-01110: archivo de datos 1: '../JRB_.DBF'
ORA-10873 signalled during: alter database open...
Wed Dec 20 00:25:18 2017

Este error suele deberse a que se cierra la bdd de forma inesperada (normalmente reinicio de máquina)  mientras se realizan tareas de backup. 

Se comprueba a ver si ha quedado algún proceso activo
[oracle@ORCL ~]$ sqlplus / as sysdba
SQL> select * from v$backup;

     FILE# STATUS                CHANGE# TIME
---------- ------------------ ---------- ---------
         1 ACTIVE                1541869 20-DEC-17
         2 ACTIVE                1541869 20-DEC-17
         3 ACTIVE                1541869 20-DEC-17
         4 ACTIVE                1541869 20-DEC-17

         5 ACTIVE                1541869 20-DEC-17

Como vemos que siguen activos, vamos a proceder a finalizarlos
SQL> alter database end backup;


Como vemos que siguen activos, vamos a proceder a finalizarlos
SQL> alter database end backup;

Y comprobamos que se hayan acabado.
SQL> select * from v$backup;

     FILE# STATUS                CHANGE# TIME
---------- ------------------ ---------- ---------
         1 NOT ACTIVE            1541869 20-DEC-17
         2 NOT ACTIVE            1541869 20-DEC-17
         3 NOT ACTIVE            1541869 20-DEC-17
         4 NOT ACTIVE            1541869 20-DEC-17
         5 NOT ACTIVE            1541869 20-DEC-17
         6 NOT ACTIVE            1541869 20-DEC-17
         7 NOT ACTIVE            1541869 20-DEC-17
         8 NOT ACTIVE            1541869 20-DEC-17

Y podemos proceder a abrir la BBDD.  

SQL> alter database open;
Database altered.  

miércoles, 24 de mayo de 2017

Oracle Golden Gate

En esta entrada se mostrará un ejemplo sencillo de una réplica entre distintas BBDD 11g con Oracle Golden Gate.

Software a instalar:
- Oracle Golden Gate 12c
- Parche de OGG para la BBDD 12c p25445845_12201170221_Linux-x86-64.zip
- Parche de OGG para la BBDD 11g p25445840_12201170221_Linux-x86-64.zip

Le ponemos un path de acuerdo al origen y destino:
Origen:
 - Host: sorigen11g
 - Directorio: /db/R01_GG
Destino:
 - Host: sdestino11g
 - Directorio: /db/R01_GG

En las 2 BBDD's tiene que estar habilitado el parámetro para activar la réplica.

alter system set enable_goldengate_replication=true scope=both sid='*';

USUARIOS
Empezamos creando los usuarios en las BBDD.

Lanzar esto en la BBDD origen orcl_orig:
-- Crear Tablespace 
CREATE BIGFILE TABLESPACE R01_GG_DAT datafile '+DATA' SIZE 10M AUTOEXTEND ON;

-- Usuario
CREATE USER R01_GG IDENTIFIED BY R01_GG PROFILE DEFAULT
DEFAULT TABLESPACE R01_GG_DAT TEMPORARY TABLESPACE TEMP
ACCOUNT  UNLOCK;

-- Roles
execute DBMS_STREAMS_AUTH.GRANT_ADMIN_PRIVILEGE('R01_GG');

-- Privilegios del Sistema
GRANT SELECT ANY TRANSACTION TO R01_GG;
GRANT ALTER ANY RULE TO R01_GGWITH ADMIN OPTION;
GRANT CREATE EVALUATION CONTEXT TO R01_GGWITH ADMIN OPTION;
GRANT LOCK ANY TABLE TO R01_GG;
GRANT CREATE ANY RULE TO R01_GGW ITH ADMIN OPTION;
GRANT CREATE RULE TO R01_GG WITH ADMIN OPTION;
GRANT ALTER ANY RULE SET TO R01_GG WITH ADMIN OPTION;
GRANT EXECUTE ANY RULE TO R01_GG WITH ADMIN OPTION;
GRANT EXECUTE ANY RULE SET TO R01_GG WITH ADMIN OPTION;
GRANT ALTER ANY TABLE TO R01_GG;
GRANT CREATE RULE SET TO R01_GG WITH ADMIN OPTION;
GRANT CREATE ANY RULE SET TO R01_GG WITH ADMIN OPTION;
GRANT RESTRICTED SESSION TO R01_GG;
GRANT ENQUEUE ANY QUEUE TO R01_GG WITH ADMIN OPTION;
GRANT DEQUEUE ANY QUEUE TO R01_GG WITH ADMIN OPTION;
GRANT UNLIMITED TABLESPACE TO R01_GG;
GRANT ALTER SYSTEM TO R01_GG;
GRANT MANAGE ANY QUEUE TO R01_GG WITH ADMIN OPTION;

GRANT DBA TO R01_GG;
GRANT SELECT_CATALOG_ROLE TO R01_GG;

ALTER USER R01_GG DEFAULT ROLE SELECT_CATALOG_ROLE,DBA;

Lanzar esto en la BBDD destino orcl_dest:

-- Crear Tablespace 
CREATE BIGFILE TABLESPACE R01_GG_DAT datafile '+DATA' SIZE 10M AUTOEXTEND ON;

-- Usuario
CREATE USER R01_GG IDENTIFIED BY R01_GG PROFILE DEFAULT 
DEFAULT TABLESPACE R01_GG_DAT TEMPORARY TABLESPACE TEMP
ACCOUNT  UNLOCK;

-- Rolesexecute 
DBMS_STREAMS_AUTH.GRANT_ADMIN_PRIVILEGE('R01_GG');

-- Privilegios del Sistema
GRANT SELECT ANY TRANSACTION TO R01_GG;
GRANT ALTER ANY RULE TO R01_GG WITH ADMIN OPTION;
GRANT CREATE EVALUATION CONTEXT TO R01_GG WITH ADMIN OPTION;
GRANT LOCK ANY TABLE TO R01_GG;
GRANT CREATE ANY RULE TO R01_GG WITH ADMIN OPTION;
GRANT CREATE RULE TO R01_GG WITH ADMIN OPTION;
GRANT ALTER ANY RULE SET TO R01_GG WITH ADMIN OPTION;
GRANT EXECUTE ANY RULE TO R01_GG WITH ADMIN OPTION;
GRANT EXECUTE ANY RULE SET TO R01_GG WITH ADMIN OPTION;
GRANT ALTER ANY TABLE TO R01_GG;
GRANT CREATE RULE SET TO R01_GG WITH ADMIN OPTION;
GRANT CREATE ANY RULE SET TO R01_GG WITH ADMIN OPTION;
GRANT RESTRICTED SESSION TO R01_GG;
GRANT ENQUEUE ANY QUEUE TO R01_GG WITH ADMIN OPTION;
GRANT DEQUEUE ANY QUEUE TO R01_GG WITH ADMIN OPTION;
GRANT UNLIMITED TABLESPACE TO R01_GG;
GRANT ALTER SYSTEM TO R01_GG;
GRANT MANAGE ANY QUEUE TO R01_GGWITH ADMIN OPTION;

GRANT INSERT, UPDATE, DELETE ON ESQUEMA.TABLA1 TO R01_GG;
GRANT INSERT, UPDATE, DELETE ON ESQUEMA.TABLA2 TO R01_GG;
GRANT INSERT, UPDATE, DELETE ON ESQUEMA.TABLA3 TO R01_GG;
...

GRANT DBA TO R01_GG;
GRANT SELECT_CATALOG_ROLE TO R01_GG;

ALTER USER G58_GG DEFAULT ROLE CONEXION,SELECT_CATALOG_ROLE,DBA,ESQUEMA;

PROFILES
Se crean los ficheros para cargar las variables  de entorno para conexión a GG.

En el Host Origen (sorigen11g). El fichero lo llamaremos .profile_R01_GG
export ORACLE_HOME=/u01/app/oracle/product/11.2.0.4/dbhome
export OGG_HOME=/db/R01_GG
export PATH=/u02/app/11.2.0/grid/bin:$OGG_HOME:$PATH
export LD_LIBRARY_PATH=/u01/app/oracle/product/11.2.0.4/dbhome/lib:$OGG_HOME:$LD_LIBRARY_PATH
cd $OGG_HOME

alias ggsci="rlwrap ./ggsci"

En el Host Destino (sdestino11g)
export ORACLE_HOME=/u01/app/oracle/product/11.2.0.4/dbhome
export OGG_HOME=/db/R01_GG
export PATH=/u02/app/11.2.0/grid/bin:$OGG_HOME:$PATH
export LD_LIBRARY_PATH=/u01/app/oracle/product/11.2.0.4/dbhome/lib:$OGG_HOME:$LD_LIBRARY_PATH
cd $OGG_HOME

alias ggsci="rlwrap ./ggsci"


ALIAS
Para no tener que identificarse en todo momento creamos los alias.

En el Host Origen (sorigen11g)
[oracle@sorigen11g]$ . .profile_R01_GG
[oracle@sorigen11g R01_GG]$ ggsci

Oracle GoldenGate Command Interpreter for Oracle
Version 12.2.0.1.170221 OGGCORE_12.2.0.1.0OGGBP_PLATFORMS_170123.1033_FBO
Linux, x64, 64bit (optimized), Oracle 11g on Jan 23 2017 21:54:15
Operating system character set identified as UTF-8.

Copyright (C) 1995, 2017, Oracle and/or its affiliates. All rights reserved.

GGSCI (sorigen11g.localdomain) 1> add credentialstore
Credential store created in ./dircrd/.

GGSCI (sorigen11g.localdomain) 2> alter credentialstore add user R01_GG@ORCL_ORIG , password R01_GG alias R01_GG_EX;
Credential store in ./dircrd/ altered.

En el Host Destino (sdestino11g)
[oracle@sdestino11g]$ . .profile_R01_GG
[oracle@sdestino11g R01_GG]$ ggsci

Oracle GoldenGate Command Interpreter for Oracle
Version 12.2.0.1.170221 OGGCORE_12.2.0.1.0OGGBP_PLATFORMS_170123.1033_FBO
Linux, x64, 64bit (optimized), Oracle 11g on Jan 23 2017 21:54:15
Operating system character set identified as UTF-8.

Copyright (C) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
GGSCI (sdestino11g.localdomain) 1> add credentialstore
Credential store created in ./dircrd/.
GGSCI (sdestino11g.localdomain) 2> alter credentialstore add user R01_GG@ORCL_DEST, password R01_GG alias R01_GG_RP;
Credential store in ./dircrd/ altered.

SUPPLEMENTAL LOGGING
Creamos un fichero sh que se lanzarán en la BBDD origen (ORCL_ORIG)
[oracle@sdestino11g R01_GG]$ vi supplemental_logging.sh
ggsci <<EOF
dblogin useridalias R01_GG_EX

delete trandata ESQUEMA_ORIG.TABLA1 ALLCOLS
delete trandata ESQUEMA_ORIG.TABLA2 ALLCOLS
delete trandata ESQUEMA_ORIG.TABLA3 ALLCOLS
delete trandata ESQUEMA_ORIG.TABLA4 ALLCOLS
...
add trandata ESQUEMA_ORIG.TABLA1 , ALLCOLS
add trandata ESQUEMA_ORIG.TABLA2 , ALLCOLS
add trandata ESQUEMA_ORIG.TABLA3 , ALLCOLS
add trandata ESQUEMA_ORIG.TABLA4 , ALLCOLS
...
EOF

[oracle@sdestino11g R01_GG]$ chmod +x supplemental_logging.sh
[oracle@sdestino11g R01_GG]$ ./supplemental_logging.sh


PARAMETRIZACIÓN GLOBAL
Se procede a parametrizar los ficheros GLOBALS y MGR
En el Host Origen (sorigen11g)
[oracle@sorigen11g]$ . .profile_R01_GG
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (sorigen11g.localdomain) 1> EDIT PARAMS ./GLOBALS
-->metemos esto en el vi:
GGSCHEMA R01_GG
ENABLE_HEARTBEAT_TABLE
USE_TRAILDEFS
ENABLEMONITORING
-->guardamos y salimos del vi


Sin salir del ggsci
GGSCI (sorigen11g.localdomain) 2> EDIT PARAMS MGR
-->metemos esto en el vi: 
PORT 7812
DYNAMICPORTLIST 7840-8096
AUTOSTART ER *
AUTORESTART ER *, RETRIES 20, WAITMINUTES 1, RESETMINUTES 60
STARTUPVALIDATIONDELAY 5
PURGEOLDEXTRACTS /db/R01_GG/dirdat/*, USECHECKPOINTS, MINKEEPFILES 3
-->Guardamos y salimos del vi

En el Host Destino (sdestino11g)
[oracle@sdestino11g]$ . .profile_R01_GG
[oracle@sdestino11g R01_GG]$ ggsci
GGSCI (sdestino11g.localdomain) 1> EDIT PARAMS ./GLOBALS
-->metemos esto en el vi:
GGSCHEMA R01_GG
ENABLE_HEARTBEAT_TABLE
USE_TRAILDEFS
ENABLEMONITORING
-->guardamos y salimos del vi

Sin salir del ggsci seguimos con el manager
GGSCI (sdestino11g.localdomain) 2> EDIT PARAMS MGR
-->metemos esto en el vi: 
PORT 7812
DYNAMICPORTLIST 7840-8096
AUTOSTART ER *
AUTORESTART ER *, RETRIES 20, WAITMINUTES 1, RESETMINUTES 60
STARTUPVALIDATIONDELAY 5
PURGEOLDEXTRACTS /db/R01_GG/dirdat/*, USECHECKPOINTS, MINKEEPFILES 3
-->Guardamos y salimos del vi



CONFIGURACION DEL EXTRACT

En el Host Origen (sorigen11g)
[oracle@sorigen11g]$ . .profile_R01_GG
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (sorigen11g.localdomain) 1> EDIT PARAMS EXR01
-->metemos esto en el vi:
USERIDALIAS R01_GG_EX
EXTTRAIL /db/R01_GG/dirdat/vp
--TRANLOGOPTIONS HANDLEDFAILOVER (solo en presencia de standy)
--TRANLOGOPTIONS _FAILOVERTARGETDESTID 2 (solo en presencia de standby)
TRANLOGOPTIONS INCLUDEREGIONID excludetag 111
GETTRUNCATES
LOGALLSUPCOLS
UPDATERECORDFORMAT COMPACT
REPORTCOUNT EVERY 15 MINUTES, RATE
REPORTROLLOVER ON SUNDAY
DISCARDFILE /db/R01_GG/dirrpt/r1exdiscard.dsc, APPEND
DISCARDROLLOVER ON SUNDAY
WILDCARDRESOLVE DYNAMIC

OBEY /db/R01_GG/dirprm/obey_exr01
-->guardamos y salimos del vi

Obey
cd $OGG_HOME/dirprm
vi obey_exr01

-->metemos esto en el vi

TABLE ESQUEMA.TABLA1;
TABLE ESQUEMA.TABLA2;
TABLE ESQUEMA.TABLA3;
TABLE ESQUEMA.TABLA4;
...

-->guardamos y salimos de vi


CONFIGURACION DEL DATAPUMP
En el Host Origen (sorigen11g)
[oracle@sorigen11g]$ . .profile_R01_GG
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (sorigen11g.localdomain) 1> EDIT PARAMS DPR01
-->metemos esto en el vi:
EXTRACT DPR01
USERIDALIAS R01_GG_EX
RMTHOST sdestino11g, MGRPORT 7809 , PARAMS -f -B1048576, TCPBUFSIZE 1048576, TCPFLUSHBYTES 1048576
RMTTRAIL /u01/GG_R01/dirdat/vp
PASSTHRU

OBEY /db/R01_GG/dirprm/obey_exr01
-->guardamos y salimos del vi


CONFIGURACION DEL REPLICAT
En el Host destino (sdestino11g)
[oracle@sorigen11g]$ . .profile_R01_GG
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (sorigen11g.localdomain) 1> EDIT PARAMS RPR01
-->metemos esto en el vi:
REPLICAT RPR01
USERIDALIAS R01_GG_RP
WILDCARDRESOLVE DYNAMIC
GETTRUNCATES
DBOPTIONS INTEGRATEDPARAMS(disable_on_error Y)
DBOPTIONS INTEGRATEDPARAMS(parallelism 4)
ALLOWNOOPUPDATES
REPORTCOUNT EVERY 15 MINUTES, RATE
REPORTROLLOVER ON SUNDAY
DISCARDFILE /db/R01_GG/dirrpt/r01rpdiscard.dsc, APPEND
DISCARDROLLOVER ON SUNDAY

OBEY /db/R01_GG/dirprm/obey_rpr01
-->guardamos y salimos del vi

Obey
cd $OGG_HOME/dirprm
vi obey_rpr01

-->metemos esto en el vi

MAP ESQUEMA.TABLA1, TARGET ESQUEMA_DEST.TABLA_DEST1;
TABLE ESQUEMA.TABLA2, TARGET ESQUEMA_DEST.TABLA_DEST2,
COLMAP(CAMPO1 = CAMPO_DEST3,
       CAMPO2 = CAMPO_DEST1
       ...);
...
-- O Todas las tablas del Esquema
-- MAP ESQUEMA.*, TARGET ESQUEMA_DEST.*;


-->guardamos y salimos de vi


TABLA HEARTBEAT
Creamos la tabla HeartBeat que se encarga de monitorizar la réplica. Desde sorigen11g con el perfil . .profile_R01_GG cargado

[oracle@sorigen11g R01_GG]$ ggsci

Oracle GoldenGate Command Interpreter for Oracle
Version 12.2.0.1.170221 OGGCORE_12.2.0.1.0OGGBP_PLATFORMS_170123.1033_FBO
Linux, x64, 64bit (optimized), Oracle 11g on Jan 23 2017 21:54:15
Operating system character set identified as UTF-8.

Copyright (C) 1995, 2017, Oracle and/or its affiliates. All rights reserved.

GGSCI (nodo1siap.localdomain) 1> dblogin useridalias R01_GG_EX
Successfully logged into database.

GGSCI (nodo1siap.localdomain as G58_GG@erezeta1) 2> add heartbeattable

2017-08-16 13:12:40  INFO  OGG-14001 Successfully created heartbeat seed table ["GG_HEARTBEAT_SEED"].
2017-08-16 13:12:40  INFO  OGG-14032 Successfully added supplemental logging for heartbeat seed table ["GG_HEARTBEAT_SEED"].
2017-08-16 13:12:40  INFO  OGG-14000 Successfully created heartbeat table ["GG_HEARTBEAT"].
2017-08-16 13:12:40  INFO  OGG-14033 Successfully added supplemental logging for heartbeat table ["GG_HEARTBEAT"].
2017-08-16 13:12:40  INFO  OGG-14016 Successfully created heartbeat history table ["GG_HEARTBEAT_HISTORY"].
2017-08-16 13:12:40  INFO  OGG-14023 Successfully created heartbeat lag view ["GG_LAG"].
2017-08-16 13:12:40  INFO  OGG-14024 Successfully created heartbeat lag history view ["GG_LAG_HISTORY"].
2017-08-16 13:12:40  INFO  OGG-14003 Successfully populated heartbeat seed table with [].
2017-08-16 13:12:40  INFO  OGG-14004 Successfully created procedure ["GG_UPDATE_HB_TAB"] to update the heartbeat tables.
2017-08-16 13:12:40  INFO  OGG-14017 Successfully created procedure ["GG_PURGE_HB_TAB"] to purge the heartbeat history table.
2017-08-16 13:12:40  INFO  OGG-14005 Successfully created scheduler job ["GG_UPDATE_HEARTBEATS"] to update the heartbeat tables.
2017-08-16 13:12:40  INFO  OGG-14018 Successfully created scheduler job ["GG_PURGE_HEARTBEATS"] to purge the heartbeat history table.
-->guardamos y salimos del vi

Si se accede a la BBDD se verá que en el esquema R01_GG ha creado:
- 3 tablas que se encargan de la monitorización de la réplica: GG_HEARTBEAT, GG_HEARTBEAT_HISTORY, GG_HEARTBEAT_SEED.
- 2 Procedures encargados de borrar e historificar las tablas HeartBeat: GG_PURGE_HB_TAB, GG_UPDATE_HB_TAB.
- 2 Jobs para actualizar las tablas.


CREACION EXTRACT
En este punto vamos a crear de verdad los procesos de GG, por lo que el parámetro de BD enable_goldengate_replication debe estar a true.
Desde el sorigen11g, nos conectamos a la BBDD para obtener un SCN asociado al build. Ejecutamos la siguiente query:

SELECT DISTINCT FIRST_CHANGE#, NAME , FIRST_TIME  
FROM GV$ARCHIVED_LOG  
WHERE DICTIONARY_BEGIN = 'YES' 
ORDER BY 1 DESC;

Anotamos el SCN más alto del build que nos pinte en pantalla. Ahora Con el perfil de GG cargado lanzamos:
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (nodo1siap.localdomain) 1> dblogin useridalias R01_GG_EX
GGSCI (nodo1siap.localdomain) 2> register extract EXR01 with database scn <scn del build obtenido en el punto anterior>

Ahora lo creamos
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (sorigen11g.localdomain) 1> dblogin useridalias R01_GG_EX
GGSCI (sorigen11g.localdomain) 2> register extract EXR01 with database scn <scn del build obtenido en el punto anterior>


CREACION DATAPUMP
Con el profile cargado se ejecuta desde sorigen11g
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (sorigen11g.localdomain) 1> add extract DPR01, exttrailsource /db/R01_GG/dirdat/vp
GGSCI (sorigen11g.localdomain) 2> add rmttrail /db/R01_GG/dirdat/vp, extract DPR01


CREACION REPLICAT
Con el profile cargado se ejecuta desde sdestino11g
[oracle@sdestino11g R01_GG]$ ggsci
GGSCI (sdestino11g.localdomain) 1> dblogin useridalias R01_GG_RP
GGSCI (sdestino11g.localdomain) 2> add replicat RPR01, integrated, exttrail /db/R01_GG/dirdat/vp


ARRANQUE REPLICAT
Con el profile cargado se ejecuta desde sdestino11g
[oracle@sdestino11g R01_GG]$ ggsci
GGSCI (sdestino11g.localdomain) 1> alter replicat RPR01 extseqno 0 extrba 0
GGSCI (sdestino11g.localdomain) 2> start replicat RPR01, aftercsn <scn del build en el punto anterior>


ARRANQUE EXTRACT
Con el profile cargado se ejecuta desde sorigen11g
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (sorigen11g.localdomain) 1> start extract EXR01
GGSCI (sorigen11g.localdomain) 2> view report EXR01


ARRANQUE DATAPUMP
Con el profile cargado se ejecuta desde sorigen11g
[oracle@sorigen11g R01_GG]$ ggsci
GGSCI (sorigen11g.localdomain) 1> start extract DPR01
GGSCI (sorigen11g.localdomain) 2> view report DPR01


A partir de ahí ya debería replicar la info del origen al destino.

En las siguientes entradas pondré otros ejemplos de réplicas GG más complejas: Bidireccionales, con dml_handlers,...

miércoles, 29 de marzo de 2017

Liberar Espacio de Archivado


A veces, cuando se realizan cargas masivas se genera gran cantidad de archivado que puede llegar a llenarse el directorio que asignamos para dichos ficheros. Y al entrar en la BBDD nos podemos encontrar con el error ORA-00257 (en el alert podrías encontrar errores relacionados como ORA-19809, ORA-19804, ORA-16038).





Lo primero que hay que saber es en qué directorio se almacena el archivado y cuánto es el máximo que se permite.

SQL>  show parameter db_recovery

NAME                                   TYPE             VALUE
------------------------------------ -----------        ------------------------------
db_recovery_file_dest          string            +DATOS
db_recovery_file_dest_size big integer     30G

En nuestro caso se trata de una BBDD con almacenamiento ASM (en caso de no ser así vendría la ruta completa) y con una capacidad de 30Gb. Existen 2 posibilidades:

1.- Borrar el archivado obsoleto/expirado
2.- Ampliar el espacio asignado

1.- Lo que primero intentaría borrar el archivado obsoleto/expirado.

/home/oracle> rman target /
RMAN> crosscheck archivelog all;
using target database control file instead of recovery catalog
...
RMAN> delete expired archivelog all;
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
...
Do you really want to delete the above objects (enter YES or NO)? yes

/test01/archive/TEST01/archivelog/2011_06_10/o1_mf_1_26650_6z3q5vmm_.arc deleted.

Puede que no se libere y en ese caso podríamos aumentar el tamaño del directorio en las propiedades de la BBDD.

2.- Ampliar el espacio asignado
SQL> alter system set db_recovery_file_dest_size=50G scope=BOTH;
SQL>  show parameter db_recovery

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_recovery_file_dest                string      +DATOS
db_recovery_file_dest_size           big integer 50G

Este parámetro se cambia dinamicamente, no hace falta reiniciar. A continuación hacemos un switch del fichero para ver si ya se ha solucionado el problema.

SQL> alter system switch logfile;

Y ya debería funcionar, se podría volver a cambiar el tamaño del directorio. Pero si este problema se repite habitualmente, puede que se tenga que dejar el valor del parametro db_recovery_file_dest_size.

¿Como saber el tamaño ocupado del directorio?
Si tienes un entorno ASM, Debes hacer:
Cargar variables de entorno para ASM
/home/oracle> . .profile_asm
Entrar en la consola de ASM
/home/oracle> asmcmd
Saber espacio global de los discos
ASMCMD> lsdg


State    Type    Rebal  Sector  Block       AU  Total_MB  Free_MB  Req_mir_free_MB  Usable_file_MB  Offline_disks  Voting_files  Name
MOUNTED  EXTERN  N         512   4096  1048576   4544800   104783                0          104783              0             N  DATOS/

MOUNTED  EXTERN  N         512   4096  1048576     49152    44190                0           44190              0             N  CONTROL/
MOUNTED  EXTERN  N         512   4096  1048576     49152    44190                0           44190              0             Y  OCRVOT/


¿Como saber que ficheros de archivado hay en el directorio?
Cargar variables de entorno para ASM
/home/oracle> . .profile_asm
Entrar en la consola de ASM
/home/oracle> asmcmd
Saber espacio global de los discos
ASMCMD> cd /DATOS/NombreInstancia/DATAFILE
Para ver lo que contiene cada directorio
ASMCMD> ls
2017_01_01/
2017_01_02/
ASMCMD> cd 2017_01_01
ASMCMD> ls
thread_1_seq_104017.3677.99990003
thread_1_seq_104018.8532.99550003
...

miércoles, 8 de marzo de 2017

Pérdida/Recuperación del Current Redo Log

A veces si se tira/cae/apaga la BBDD de manenera inconsistente se pueden perder los redologs. En esta entrada simularemos que no tenemos backup. Al arrancar la BBDD se queda en estado mount y lanza mensajes de error:

SQL> startup
ORACLE instance started.

Total System Global Area ...
...
Database mounted.
ORA-00313: open failed for members of log group 3 of thread 1
ORA-00312: online log 3 thread 1: '/oracle/data/orcl/redo03.log'
ORA-27037: unable to obtain file status
Linux Error: 2: No such file or directory
Additional information: 3

La forma de levantar la instancia sería

SQL> CREATE PFILE FROM SPFILE;

Edit pfile and add parameter *._allow_resetlogs_corruption=true

SQL> STARTUP MOUNT PFILE='/oracle/product/11.2.0.4/dbhome_1/dbs/pfileorcl.ora'

SQL> ALTER DATABASE OPEN RESETLOGS;

SQL> SHUTDOWM IMEMDIATE

SQL> STARTUP

ORACLE instance started.

Total System Global Area ...
...
Database mounted.
Database opened.

jueves, 2 de febrero de 2017

Configuracion de una BBDD Standby en PostgreSQL

Esta entrada intentará explicar como configurar una BBDD de respaldo en PostgreSQL. Lo que incluyo en esta entrada es un ejemplo rápido de cómo lo he hecho yo. 

Lo primero de todo deberíamos tener 2 máquinas de similares características. En nuestro caso serán 2 máquinas con CentOS 7. Y en ambos deberíamos tener PostgreSQL instalado en cada máquina.
    Máquina1 - Producción - propsql (IP 192.168.159.152)
    Máquina2 - Producción - stbsql (IP 192.168.159.153)

Paso 1. Crear los directorios donde se van a ir copiando/moviendo los ficheros WAL (estos ficheros de REDO que guardan cambios realizados en la base de datos).

Producción
[postgres@propsql]$ mkdir -p /srv/redo
[postgres@propsql]$ mkdir -p /srv/wal_arch
[postgres@propsql]$ chmod -R 0700 /srv/redo
[postgres@propsql]$ chmod -R 0700 /srv/wal_arch

Standby
[postgres@stbsql]$ mkdir -p /srv/redo
[postgres@stbsql]$ mkdir -p /srv/wal_arch
[postgres@stbsql]$ mkdir -p /srv/wal_shipped
[postgres@stbsql]$ chmod -R 0700 /srv/redo
[postgres@stbsql]$ chmod -R 0700 /srv/wal_arch
[postgres@stbsql]$ chmod -R 0700 /srv/wal_shipped

Paso 2. Configuración del acceso mediante llaves SSH. Se crearán las llaves públicas para poder copiar los ficheros redos.
Producción
[postgres@propsql]$ ssh-keygen -t rsa

Generating public/private rsa key pair.
Enter file in which to save the key (/var/lib/pgsql/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/postgres/.ssh/id_rsa.
Your public key has been saved in /home/postgres/.ssh/id_rsa.pub.            


Standby 
[postgres@stbsql]$ ssh-keygen -t rsa

Generating public/private rsa key pair.
Enter file in which to save the key (/var/lib/pgsql/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/postgres/.ssh/id_rsa.
Your public key has been saved in /home/postgres/.ssh/id_rsa.pub.

Compartir las claves en las máquinas. Crear ficheros donde compartir la clave pública de cada máquina. Fijarse desde que máquina se lanza cada instrucción.

Permitir acceder de PRO a Standby. Copiar desde PRO el fichero con la clave pública a Standby.

[postgres@propsql]$ scp /var/lib/pgsql/.ssh/id_rsa.pub postgres@spropsql02.ibili.eus:~/claveProd.pub 

Y desde Standby, añadir la clave pública en el fichero de las claves autorizadas.

[postgres@stbsql]$ cat claveProd.pub >> /var/lib/pgsql/.ssh/authorized_keys

Por último añadir la dirección IP en el fichero /etc/hosts.allow.
[root@stbsql]$ vi /etc/hosts.allow
sshd: 192.168.159.152

Permitir acceder de Standby a PRO
Copiar desde Standby el fichero con la clave pública a PRO
[postgres@stbsql]$ scp /var/lib/pgsql/.ssh/id_rsa.pub postgres@spropsql01.ibili.eus:~/claveProd.pub 

Y desde PRO, añadir la clave pública en el fichero de las claves autorizadas.
[postgres@propsql]$ cat claveProd.pub >> /var/lib/pgsql/.ssh/authorized_keys

Por último añadir la dirección IP en el fichero /etc/hosts.allow.
[root@propsql]$ vi /etc/hosts.allow
sshd: 192.168.159.153

Paso3. Parametrizar el máquina de la BBDD Activa (Productivo).

Modificar el fichero de configuración.
Se deben cambiar algunos de los parámetros del fichero de configuración. El fichero es /srv/postgresql.conf.
wal_level = hot_standby - Este parámetro define cuanta información se grabará en los ficheros WAL generados. Se pueden utilizar tres valores, minimal, archive y hot_standby. En nuestro caso utilizamos el valor hot_standby, porque vamos a utilizar esta funcionalidad.
archive_mode = on - Con este parámetro activamos el archivo de ficheros WAL en el maestro.
archive_command = '/srv/archive_wal.sh -P %p -F %f' - Con el comando definido en este parámetro, copiamos los ficheros WAL a archivar al directorio /srv/wal_arch en el servidor maestro y transferimos los ficheros WAL archivados, al directorio /srv/wal_shipped en el servidor esclavo.
max_wal_senders = 3 - Con este parámetro definimos el número máximo de conexiones que se pueden realizar desde servidores esclavos al servidor maestro via SR
wal_keep_segments = 10 - Este parámetro define el número máximo de ficheros WAL que mantendremos sin reciclar en el servidor maestro.

Creación del fichero para copiar/mover redo. 
El siguiente paso es crear el fichero /srv/archive_wal.sh, que será el encargado de copiar los ficheros de redo en la máquina de Standby. El contenido del fichero sería:

#!/bin/bash
                       
CHMOD="/bin/chmod"
COPY="/bin/cp"
SCP="/usr/bin/scp"

# Directorio usado por PostgreSQL para generar los ficheros WAL
PG_XLOG_DIR="/srv/pg_xlog"

# Directorio usado por PostgreSQL para archivar los ficheros WAL
PG_WAL_ARCH_DIR="/srv/wal_arch"

# Servidor PostgreSQL Standby
STANDBY_SERVER="stbsql"

# Directorio en servidor esclavo donde transferimos los ficheros
# WAL archivados en el servidor maestro.
PG_WAL_SHIPPED="/srv/wal_shipped"

NO_ARGS=0
E_OPTERROR=65

# ########################################
# ########################################
#
# Function archive_wal()
#
# ########################################
# ########################################

archive_wal(){

    if  $COPY -dp $ABSOLUTE_PATH $PG_WAL_ARCH_DIR/$WAL_FILE
    then
        $CHMOD 400 $PG_WAL_ARCH_DIR/$WAL_FILE
        $SCP $PG_WAL_ARCH_DIR/$WAL_FILE $STANDBY_SERVER:$PG_WAL_SHIPPED
    else
        sleep 1
        exit 1
    fi
}

# ########################################
# ########################################
# Script invoked with no command-line args?
# ########################################
# ########################################
if [ $# -eq "$NO_ARGS" ]
then
    help
    exit $E_OPTERROR
fi


# ########################################
# ########################################
# Getting command options
# ########################################
# ########################################

while getopts "P:F:" Option
do
    case $Option in
        P)
            ABSOLUTE_PATH=$OPTARG;;

        F)
            WAL_FILE=$OPTARG;;

    esac
done
shift $(($OPTIND - 1))

# ########################################
# ########################################
# Sanity check
# ########################################
# ########################################

if [ -z $ABSOLUTE_PATH ]
then
    echo "Error: Absolute path not defined"
    echo
    exit $E_OPTERROR
fi

if [ -z $WAL_FILE ]
then
    echo "Error: WAL filename not defined"
    echo
    exit $E_OPTERROR
fi

archive_wal

exit 0

#
# EOF

Antes de arrancar la bbdd de Producción se tiene que definir también en el fichero /srv/pg_hba.conf del servidor maestro una línea que permita el acceso del proceso receptor WAL (WAL receiver) al servidor maestro.
host    replication all         192.168.159.153              trust

Ya se puede arrancar la bbdd de  Producción.
/usr/bin/pg_ctl -D /srv start


Paso 4. Crear copia de seguridad base
A continuación, restauraremos esta copia de seguridad 'base' en el servidor esclavo.
[postgres@propsql]$ cd $PGDATA
[postgres@propsql]$ psql template1 -c "SELECT pg_start_backup('copia base inicial')"
pg_start_backup
-----------------
0/1000020
(1 row)
[postgres@propsql]$ tar -cvf /srv/pg_base_backup.tar /srv/
[postgres@propsql]$ psql template1 -c "SELECT pg_stop_backup()"
pg_stop_backup
----------------
0/10000D8
(1 row)
[postgres@propsql]$ scp /srv/pg_base_backup.tar  spropsql02:~/tmp/
[postgres@propsql]$ ssh postgres@spropsql02 "cd / && tar -xvf /tmp/pg_base_backup.tar"
[postgres@propsql]$ ssh postgres@ spropsql02 "rm /srv/postmaster.pid"

Paso 5. Parametrización de STANDBY 

Ahora se procede a configurar la bbdd de Standby. Se deben cambiar algunos de los parámetros de los ficheros de configuración. 

Fichero /srv/postgresql.conf
hot_standby = on - Para definir que este servidor esclavo se podrá utilizar para realizar consultas de solo lectura. 

Fichero /srv/recovery.conf (en caso de no existir se copia el fichero /usr/share/pgsql/recovery.conf.sample)
standby_mode = 'on' - Este parámetro define que el servidor no saldrá del modo de recuperación y continuará probando la restauración continua de información WAL.
primary_conninfo = 'host=spropsql port=5432 user=postgres' - Este parámetro define el servidor maestro usado para recoger registros WAL.
trigger_file = '/srv/pg_failover_trigger' - Con este parámetro se define un fichero que en caso de crearse/existir sacará al servidor esclavo del modo "hot standby" y de recuperación continua.
restore_command = 'cp /srv/wal_shipped/%f %p' - Con este parámetro definimos el comando a utilizar, si es necesario, para restaurar los ficheros WAL que se encuentran en /srv/wal_shipped.


Una vez realizado estos cambios podemos arrancar postgreSQL en el servidor esclavo.
/usr/bin/pg_ctl -D /srv start

Paso 5. Monitorización de la réplica.

Para controlar la replicación se ha creado una bd llamada "monitorización_replica" que contiene una tabla de HEARTBEAT que se actualiza en el origen cada 5 minutos. 

Después de crear la tabla se crea una función que update el campo fecha.
CREATE OR REPLACE FUNCTION public.fnc_update_hb()
  RETURNS integer AS
$BODY$
declare nCount int;
BEGIN
select count(*) into nCount from heartbeat;
IF nCount = 0 then
insert into heartbeat values (now());
else 
update heartbeat set fecha=now();
END if;
return 1;
END;

Y finalmente se añade en el cron una tarea para que update la fecha/hora en la tabla HEARTBEAT. Se añade la siguiente línea
[postgres@propsql]$ crontab -e

#job para monitorizar la replicacion de standby
*/5 * * * * psql -d monitor_replica -c "select fnc_update_hb();"


Para saber si la replicación está al día basta con que logueemos en la máquina de standby (spropsql02) con el usuario postgres y lancemos esto:

[postgres@stbsql]$ psql -d monitor_replica -c "select * from heartbeat;"           

Que nos devolverá la fecha en la que se hizo la última réplica:

fecha           
---------------------------
 2016-04-12 16:20:01.13292
(1 fila)

Si no está al día es que está fallando la réplica.


Para una explicación detallada de lo que es una BBDD Standby os recomiendo esta entrada donde lo detallan mucho mejor https://e-mc2.net/es/hot-standby-y-streaming-replication