martes, 31 de marzo de 2009

EXPLICACION DEL "ITL ENQUEUE"

Buenos dias amigos.

En la entrega anterior veìamos un singular patron de bloqueo

SID SERIAL# TY OBJECT_NAM HELD REQUEST
----- ------- -- ---------- ---------- --------
36 8428 TX 0 4
36 8428 TM TAB1 3 0
52 29592 TM TAB1 3 0
52 29592 TX (Rollback=RBS1_6) 6 0

Que cuando se presenta podemos asegurar que se trata de un bloqueo ITL, la pregunta del millon ¿como deducimos esto a partir de la salida del script anterior?

- Para garantizar la consistencia de informacion frente a cualquier solicitud de operacion DML oracle inicia un bloqueo contra la tabla (TM) en modo row exclusive (3) para prevenir modificaciones estructurales sobre el segmento en cuestion. Es por ello que vemos que ambas transacciones (36 y 52) que desean modificar datasets sobre la tabla (TAB1) mantienen un bloqueo TM (nivel de tabla) y de tipo row exclusive.

- Una vez que se bloquea el segmento de modo que no se pueda modificar la estructura del mismo, entonces se reserva un slot en el segmento de rollback, identificando asi el segmento de rollback que se encargara de mantener toda la informacion de UNDO necesaria para las lecturas consistentes de la tabla y para recuperar la informacion anterior a el cambio en caso de un posible rollback.

- Una vez que el plan de ejecucion identifica los bloques a ser cambiados por la sentencia DML, entonces la(s) transaccion(es) que desean realizar la operacion DML sobre el dataset reservan slots ITL en la cabecera de los bloques pertenecientes a dicho dataset, si encuentran ITL's libres, entonces la transaccion marca al ITL con un puntero hacia el segmento de rollback usado para reversar la transaccion, segmento de rollback que reservamos en el paso anterior, es por ello que vemos una reserva de tipo TX (fila) de modo 6 (EXCLUSIVE) en el segmento 6 de rollback (ese segmento es el que servira para almacenar la informacion de UNDO de la transaccion en cuestion).

- Posteriormente con los bloques identificados y el (los) ITL reservado(s) entonces se proceden a marcar los row directories de las cabeceras de bloques colocando el LOCK BYTE de modo que apunte a el ITL correspondiente a la transaccion que tomo el bloqueo.

- La transaccion que no encuentra ITL libre ya sea por falta de espacion en el BLOQUE o por un valor demasiado bajo en MAXTRANS, entonces queda imposibilitado de marcar los row directories para que apunten a el ITL (que no pudieron reservar), entonces quedaran en standby solicitando un bloqueo a nivel de fila (TX) de modo 4 (share), , hasta que se libere un slot ITL para que dicho bloqueo entre en accion y se pueda proceder con el proceso de bloqueo normalmente, es por ello que vemos la una transaccion de la sesion con el sid 36 esperando por ese tipo de bloqueo en la salida del query anterior.

Espero que la explicacion sirva para que cuando corramos el script del post anterior y observemos una salida con el patron anteriormente expuesto sepamos el por que ese patron hace referencia a un bloqueo de encolamiento ITL


Ha sido un gusto compartir este razonamiento con ustedes, nos vemos en la proxima entrega.

Query para verificar que un evento "enqueue" hace referencia un enqueue ITL

Buenos dias amigos,

Lo prometido es deuda, aqui tienen el query (extraido de la pagina: http://www.rampant-books.com/art_nanda_interested_tarnsaction_list_itl.htm) que ofreci en la entrega anterior, sirve para verificar si es que un evento "enqueue" es producido por una contencion en ITL

Select s.sid SID,
s.serial# Serial#,
l.type type,
' ' object_name,
lmode held,
request request
from v$lock l, v$session s, v$process p
where s.sid = l.sid and
s.username <> ' ' and
s.paddr = p.addr and
l.type <> 'TM' and
(l.type <> 'TX' or l.type = 'TX' and l.lmode <> 6)
union
select s.sid SID,
s.serial# Serial#,
l.type type,
object_name object_name,
lmode held,
request request
from v$lock l, v$session s, v$process p, sys.dba_objects o
where s.sid = l.sid and
o.object_id = l.id1 and
l.type = 'TM' and
s.username <> ' ' and
s.paddr = p.addr
union
select s.sid SID,
s.serial# Serial#,
l.type type,
'(Rollback='||rtrim(r.name)||')' object_name,
lmode held,
request request
from v$lock l, v$session s, v$process p, v$rollname r
where s.sid = l.sid and
l.type = 'TX' and
l.lmode = 6 and
trunc(l.id1/65536) = r.usn and
s.username <> ' ' and
s.paddr = p.addr
order by 5, 6
/

Salida de ejemplo del query anterior

SID SERIAL# TY OBJECT_NAM HELD REQUEST
----- ------- -- ---------- ---------- --------
36 8428 TX 0 4
36 8428 TM TAB1 3 0
52 29592 TM TAB1 3 0
52 29592 TX (Rollback=RBS1_6) 6 0


Note como la sesion 36 y 52 tienen un bloqueo de tipo 3 (transaction exclusive) TM (nivel de tabla) en TAB1, pero las sesion 52 tambien mantiene un bloqueo de tipo 6 (exclusive) TX (nivel de transaccion fila) en el segmento de rollback y la sesion y la sesion 36 esta esperando (HELD=0) por un bloqueo TX (nivel de fila) de nivel 4 (share).

Cuando tenemos esta particular combinacion de bloqueos podemos estar seguros que la sesion 36 esta esperando debido a un bloqueo de tipo ITL.

Vamos a deducir este singular patròn de bloqueos en la siguiente entrega cuando hablemos de BLOCK CLEANOUT.

Hasta pronto ....

lunes, 30 de marzo de 2009

Cambiar el poder de balanceo de una instancia ASM

Buenos dias amigos,


Esta vez vamos a aprender a cambiar el poder de balanceo de una instancia ASM. Como todos sabemos ASM es una tecnología relativamente nueva de almacenamiento físico que Oracle pone a nuestra disposicion para colocar ahi nuestros archivos de base de datos, este nuevo sistema de manejo de nuestro almacenamiento de datos trae consigo la ventaja de performance de un RAW DEVICE, mas las características de concurrencia de un CFS (Cluster Filesystem) y mas las ventajas de manejo de un filesystem comun de S/O.

Si es que nosotros agregamos o quitamos un disco a un diskgroup asm (un conjunto de discos ASM forman lo que se conoce como DISKGROUP, cuyo tamaño es logicamente la sumatoria de todos sus ASM DISKS), Oracle tiene que realizar un proceso de re-balanceo que no es mas que redistribuir la carga de informacion entre el resto de discos que conforman ese diskgroup, dicho proceso se lo puede ver haciendo un query a la vista v$asm_operation, ahora, debido a que es una operacion que demanda gran cantidad de I/O a nivel de disco, es recomendable que cuando realizemos este tipo de operaciones, durante el tiempo ocioso de nuestra instancia (por lo general noches o madrugadas) cambiemos el nivel de poder de rebalancing de el proceso, para ello debemos usar la sentencia: ALTER DISKGROUP nombre_del_diskgroup REBALANCE POWER XX; siendo XX el nivel de poder de rebalanceo que puede fluctuar entre 1 y 11 siendo 1 el valor por default y tambien el nivel mas lento de rebalanceo que existe (11 lógicamente es el mas veloz pero el que mas carga consume por lo tanto no debemos colocarlo durante horas en las que la B.D. de produccion este en pleno uso).

viernes, 6 de febrero de 2009

Standby database 10g en standard edition (SE ONE)

En esta entrada veremos como crear una standby database con una base de datos standard edition (o SE ONE), pero antes revisemos el concepto de standby database.

Standby database no es mas que una tecnica mediante la cual creamos un espejo de nuestra(s) base(s) de datos de produccion cuya sincronizacion se la realiza mediante el paso de archivelogs desde el sitio maestro (produccion) hacia el esclavo (standby), dicha base de datos se mantiene en un estado de recuperacion hasta que el usuario de la orden de que se active.

La activacion de la base de datos standby se la puede realizar de dos formas:

- Activacion en caso de fallo de produccion.
- Activacion por switchover o intercambio de estados (standby se vuelve produccion y produccion se vuelve standby) en caso de mantenimiento o problemas temporales en el servidor de produccion.

Ahora explicaremos la tecnica para crear este esquema SIN TENER QUE BAJAR LA BASE DE PRODUCCION si esta se encuentra ya en modo archivelog (caso contrario necesariamente debemos bajarla una sola vez para activar el archiving):

Cabe señalar que la tecnica que describiremos a continuacion funcionara siempre que nuestra base de datos se encuentre instalada en filesystems en lugar de ASM o RAW DEVICES. En la siguiente entrada del blog describiremos la metodologia para crear una standby database cuando ocupemos ASM o RAW DEVICES.

1) Instalamos o creamos una nueva instancia de base de datos oracle en un servidor remoto QUE DE PREFERENCIA TENGA LA MISMA ESTRUCTURA QUE NUESTRO SERVIDOR DE PRODUCCION A NIVEL DE FILESYSTEMS. Y colocamos nuestra base de produccion en modo archivelog (si no lo esta, dicho sea de paso toda base de datos de produccion deberia estar en modo archivelog) y forzamos la generacion de redo en toda nuestra base de datos mediante: alter database force logging (al fin y al cabo esta es la manera en la que garantizaremos una sincronizacion perfecta entre el sitio maestro y el sitio standby) y forzamos el logging mediante ALTER DATABASE FORCE LOGGING; .

2) Colocamos a nuestros tablespaces read write en modo backup para ello:
alter tablespace nombre_del_tablespace begin backup. No es necesario poner en modo backup a nuestros tablespaces read only por que su SCN no necesita sincronizacion con el controlfile.

3) Una vez que tenemos nuestros tablespaces en modo backup (no se incrementa el SCN de los datafile) podemos crear nuestro standby controlfile mediate: alter database create standby controlfile as 'ruta_y_nombre_de_archivo';

4) Copiamos nuestros redo logs, datafiles, STANDBY CONTROLFILE(s) y spfile (o pfile) a las mismas ubicaciones en el servidor remoto mediante cualquier comando del sistema operativo ( por ejemplo copy (windows), cp o scp (unix)).

5) En la consola del servidor remoto iniciamos nuestra base de datos en modo nomount mediante: startup nomount;

6) Colocamos a nuestra base de datos en modo mount standby mediante: alter database mount standby database;

Este momento nuesta base de datos leera nuestro standby controlfile y automaticamente se colocara en modo recovery razon por la cual debemos enviar sistematicamente nuestros archivelogs desde nuestro sitio de produccion hacia nuestro sitio standby (mas adelante veremos las tecnicas para realizar esta tarea) para que sean aplicados.

7) Para aplicar los archivelogs que llegan desde nuestra base de produccion utilizamos el comando: recover automatic standby database; y colocamos AUTO cuando nos pida ingresar el modo de recuperacion (manual, AUTO, cancel).

Este momento la base de datos aplicara todos los archivelogs y nos pedira el siguiente, por lo que, cada vez que enviemos archivelogs hacia el sitio standby debemos realizar la accion descrita en el punto anterior.

En este punto si todo salio bien debemos tener nuestra standby database totalmente funcional.

El ciclo de vida de nuestra standby database consta de 5 partes:

- Generacion de archives en nuestra BD de produccion.
- Envio de archivelogs desde produccion hacia standby.
- Aplicar archives en standby.
- Eliminar archivelogs que ya fueron aplicados en standby.
- Respaldo de archivelogs de produccion.

A continuacion describiremos las tecnicas para alcanzar los 5 puntos del ciclo de vida de nuestra standby database.

1) GENERACION: Como deciamos anteriormente es sumamente necesario que nuestra base de datos de produccion se encuentre en modo archivelog y que force la generacion de redo para asegurar que nuestra base de datos standby sea una copia fiel de nuestra base de produccion, para lo cual debemos hacer lo siguiente.

Para activar el archiving (si tenemos nuestra base de datos en modo noarchivelog hacemos lo siguiente:
  • Definimos dos rutas en el disco en las cuales se crearan los archivelogs (calcular el espacio requerido en funcion del tamaño de los archivelogs que es igual al tamaño de los redos, al numero de switchs diarios de redologs que podemos extraer de la vista v$log_history y al tiempo de permanencia antes de respaldarlos y eliminarlos mediante RMAN).
  • Colocamos las ubicaciones de archving en los parametros log_archive_dest_1 y log_archive_dest_2 mediante ALTER SYSTEM SET LOG_ARCHIVE_DEST_1='LOCATION=RUTA1' SCOPE SPFILE; y ALTER SYSTEM SET LOG_ARCHIVE_DEST_2='LOCATION=RUTA2' SCOPE SPFILE;
  • Bajamos nuestra base de datos mediante SHUTDOWN IMMEDIATE;
  • La subimos inmediatamente en estado mount mediante STARTUP MOUNT;
  • Activamos el archiving mediante ALTER DATABASE ARCHIVELOG;
  • Abrimos la base mediante ALTER DATABASE OPEN;
Para activar el forzado de logging ingresamos ALTER DATABASE FORCE LOGGING;

Con esto completamos nuestro proceso de generacion de archivelog y forzado de logging.

2) ENVIO: Esta etapa se encarga de enviar los archivelogs generados hacia el servidor standby, para ello ocuparemos la segunda ubicacion de archivelogs, la primera la mantendremos para hacer backups de los archivelogs que contenga mediante RMAN. Dada la importancia de los archivelogs en un ambiente standby debemos protegerlos con copias de seguridad y mantenerlos por un tiempo prudencial.

Un script sencillo que puede servirnos para enviar los archivelogs desde la segunda ubicacion del servidor de produccion hacia la base standby podria ser:

enviar.sh

if [ -d /respaldo/jep/Scripts/standby/sem_v ] ; then

mv /respaldo/jep/Scripts/standby/sem_v /respaldo/jep/Scripts/standby/sem_r
ls /respaldo/jep/archivelogs > /respaldo/jep/Scripts/standby/archivos
contador=$(wc -l < /respaldo/jep/Scripts/standby/archivos)
contador1=1
while [ $contador1 -le $contador ]
do
linea=$(cat /respaldo/jep/Scripts/standby/archivos |head -$contador1
|tail -1)
existe=""
existe=$(echo $linea |grep gz)
echo $existe
if [ "$existe" != "" ] ; then
echo 'moviendo inicial'
mv -u /respaldo/jep/archivelogs/*.gz /standbyfra/ >> logfile1
else
echo 'comprimiendo ' $linea
comando='/usr/bin/gzip -9 /respaldo/jep/archivelogs/'$linea
$($comando) >> logfile1
mv -u /respaldo/jep/archivelogs/*.gz /standbyfra/ >> logfile1
fi
contador1=`expr $contador1 + 1`
done
echo 'moviendo final'
mv -u /respaldo/jep/archivelogs/*.gz /standbyfra/ >> logfile1

mv /respaldo/jep/Scripts/standby/sem_r /respaldo/jep/Scripts/standby/sem_v
echo 'ejecutado'
else
echo 'proceso ya esta en ejecucion'
fi

3) La eliminacion de los logs una vez aplicados en el standby podemos hacerlo desde un script que parta de un query a la vista v$log_history de la standby database, para ello no es necesario abrir la base standby, basta con que este en estado mount.

Espero que este procedimiento les sirva para implementar un sistema de alta disponibilidad con una base de datos standard, (OJO, LA BASE DE DATOS STANDBY TIENE QUE ESTAR TAMBIEN LICENCIADA).

Hasta una proxima oportunidad amigos.

jueves, 15 de enero de 2009

Interested Transaction List (ITL)

Como todos conocemos, todo motor de base de datos debe mantener algun mecanismo de bloqueo para evitar la concurrencia de mas de una transaccion a la vez sobre el mismo dataset, por ello, la primera transaccion que necesite trabajar sobre un dataset, debe bloquearla para que dicho dataset no sea modificado hasta que la transaccion que mantiene el bloqueo termine ya sea confirmando (commit) o anulando (rollback) la transaccion.

El nivel de granularidad con el que se bloquea un dataset depende de cada RDBMS, el sistema de bloqueo de el RDBMS de ORACLE es a nivel de fila, lo que quiere decir que la unidad mas pequeña con la que oracle puede bloquear un dataset es UNA FILA (un registro).

De la misma manera el mètodo que utilizan los diferentes motores de base de datos para registrar el bloqueo difiere unas de otras, por ejemplo existen RDBMS's que mantienen un manejador de bloqueo que es la estructura de informacion que registra, mantiene y controla todos los bloqueos que se dan dentro de la base de datos. Esto sin embargo resulta en un PUNTO DE BLOQUEO adicional debido a que en bases de datos con demasiada transaccionalidad el mismo Manejador de Bloqueo se convierte en el cuello de botella ya que al momento en el que alguna transaccion pide bloquar, liberar o consultar el bloqueo sobre un determinado dataset, lo debe hacer a travez de el manejador de bloqueo, serializando de este modo la concurrencia paralela de varias llamadas que se realizan al mismo tiempo sobre este manejador transaccional. Es por ello que Oracle mantiene el control de sus transacciones en los mismos bloques de datos en lugar de encargarlo a un ente que serialize el manejo de transacciones.

La estructura mediante la cual Oracle controla o registra los bloqueos de registros se encuentra en la cabecera de los bloques de datos y se la conoce como ITL (Interester Transaction List), cada nodo de esta lista enlazada se la conoce como slot y c/u contiene el ROWID y la TRANSACTION ADDRESS que esta solicitando el bloqueo, cuando la misma u otra transaccion quiere bloquear otra fila, entonces la ROWID de esa fila y la TRANSACTION ADDRESS de la transaccion interesada en el bloqueo (por ello el nombre de INTERESTED Transaction List) y asi sucesivamente. El nùmero de slots disponibles para que las transacciones registren su "interes" por un registro especifico de la tabla esta dado por los parametros INITTRANS y MAXTRANS. El parametro INITTRANS define cuantos SLOTS ITL se crearan conjuntamente con la creacion del segmento; una vez que la transaccion termina, el bloqueo de el registro es liberado y por ende tambien se libera el SLOT ocupado para registrar esa transaccion, para que otra transaccion lo ocupe posteriormente. Si es que en un momento dado todos los SLOTS definidos por INITTRANS estan llenos, nuevos SLOTS son añadidos conforme las transacciones los soliciten, hasta alcanzar el maximo numero de SLOTS dado por el parametro MAXTRANS.

Cabe señalar que si bien el parametro MAXTRANS define el maximo numero de slots disponibles, si es que el bloque de datos no tiene espacio para crear un nuevo SLOT, pece a que aun no se llegue aun al numero de transacciones dado por MAXTRANS, el SLOT NO PODRA SER CREADO hasta que se libere espacio en el bloque de datos, para evitar este efecto en tabas que tienen un nivel alto de transaccionalidad, podemos jugar con el parametro PCTFREE y PCTUSED para mantener siempre el espacio suficiente en nuestro bloque de datos para que el numero de slots dado por MAXTRANS siempre pueda ser alcanzado.

En el supuesto caso de que el bloque este lleno o que ya se ha alcanzado el numero de slots dado por MAXTRANS y todos esten ocupados por transacciones, entonces la transaccion que pide el boqueo se colocara en un estado de espera en el evento ITL WAIT mismo que se lo puede observar en vistas tales como v$session_wait con el nombre de "enqueue"

Sin embargo, el evento "enqueue" es un evento que abarca una gama muy grande de tipos de encolamiento (el encolamiento ITL es uno de los tantos que esta dentro de esa gama). En una proxima entrega les prometo colocar el SQL con el cual podemos confirmar si es que el encolamiento es efectivamente dado por ITL.

En proximas entregas veremos el SQL ofrecido y el proceso de limpieza de bloqueo que utiliza Oracle para encerar los registros ITL una vez que la transaccion finalize.

Hasta la proxima amigos.