Usando Firebird durante 24/7/365

5 comentarios

Algunas aplicaciones requieren acceso a las bases de datos durante 24/7/365, o sea durante las 24 horas del día, los 7 días de la semana y los 365 días del año. En otras palabras: sin interrupción, por ningún motivo.

Algunos ejemplos típicos son:

  • Sanatorios, hospitales, centros de salud
  • Farmacias que trabajan las 24 horas
  • Estaciones de servicio (expendio de combustibles)
  • Policía
  • Fuerzas Armadas
  • etc.

Una aplicación desarrollada para ser utilizada por ellos tiene la obligación de poder funcionar sin interrupción en cualquier momento del día. No le puedes decir al Director de un hospital que entre las 22:00 y las 23:00 no pueden registrarse los datos de los pacientes porque hay que hacerle un mantenimiento a la Base de Datos. Ni decirle a un General que si mañana el país es atacado por el enemigo entre las 02:00 y las 03:00 entonces no podrá usar la Base de Datos porque ya tiene mucha basura y que hiciste un proceso para que elimine esa basura pero requieres que nadie esté conectado a la Base de Datos.

¿Y cuál es el problema?

El problema radica en que a las bases de datos de Firebird debe hacérsele una tarea de mantenimiento llamada sweep de vez en cuando. El sweep (barrido, en castellano) tiene como finalidad eliminar a todas las versiones inútiles de las filas que fueron modificadas o borradas. Cada vez que una fila es modificada o borrada se crea una versión de esa fila llamada delta. La parte positiva de esto es que puede realizarse un ROLLBACK y dejar a la fila como se encontraba anteriormente si el usuario cambió de idea. La parte negativa es que se va acumulando basura y todas las operaciones se van volviendo más lentas y por lo tanto esa basura debe ser eliminada alguna vez.

 Y el sweep puede demorar mucho tiempo.

¿Cuándo se inicia el sweep?

El sweep puede iniciarse automáticamente (que es su valor por defecto) cuando la diferencia entre la OST (Oldest Snapshot Transaction) y la OAT (Oldest Active Transaction) es mayor que el intervalo predefinido del sweep. Ese intervalo es de 20.000 por defecto pero puede modificarse.

Si el intervalo del sweep es de 0, entonces el sweep nunca se iniciará automáticamente. Eso implica que hay que iniciarlo manualmente. Para ello se usa el programa GFIX con la opción –sweep. En este caso lo recomendable es que nadie esté usando la Base de Datos mientras se realiza el sweep.

 ¿Qué ocurre cuándo se inicia el sweep?

Que la transacción que hizo iniciar al sweep no empezará hasta que el sweep finalice. Supongamos que el intervalo del sweep es de 20.000, entonces el desafortunado usuario que quiso iniciar una transacción cuando OST – OAT fue de 20.001 tendrá que esperar hasta que finalice el sweep antes de que su transacción pueda empezar. A quienes iniciaron sus transacciones antes que él no les afectará, pero a él sí. Y si justo es un General de muy malas pulgas, entonces…

 ¿Se puede evitar que se inicie el sweep sin perjudicar el rendimiento de la Base de Datos?

Sí.

La buena noticia es que si las aplicaciones que usan la Base de Datos están correctamente diseñadas entonces nunca será necesario realizar el sweep.

La basura que se encuentra dentro de una Base de Datos puede deberse a los siguientes motivos:

  • Una operación de UPDATE que finalizó con un COMMIT
  • Una operación de DELETE que finalizó con un COMMIT
  • Una operación de UPDATE que finalizó con un ROLLBACK
  • Una operación de DELETE que finalizó con un ROLLBACK

La basura dejada por las transacciones que finalizaron con un COMMIT es recolectada (garbage collection) automáticamente cuando se hace un SELECT a esas filas. Por lo tanto, para eliminar toda la basura de una tabla que fue dejada por los COMMIT se puede escribir un simple comando: SELECT * FROM MiTabla y listo: esa tabla ya no tendrá basura dejada por los COMMIT.

La basura dejada por el ROLLBACK sin embargo, solamente puede ser eliminada con un sweep.

Por lo tanto la solución es muy simple y muy sencilla: No usar ROLLBACK.

¿Y cómo se puede evitar usar ROLLBACK?

Hay varias alternativas posibles, una posible solución sería esta:

  • Haces un SELECT a la fila que te interesa, por supuesto finalizando ese SELECT con un COMMIT. El resultado de ese SELECT lo guardas en una tabla temporal que no es de Firebird, por ejemplo en una tabla .DBF
  • Le muestras la fila de la tabla .DBF al usuario
  • Le permites que cambie los campos o que borre la fila
  • Si decide Guardar los cambios, entonces haces un UPDATE a la tabla de Firebird con los valores que se ven en la pantalla y luego el COMMIT correspondiente
  • Si decide Cancelar los cambios, entonces allí termina todo, no tocas la tabla de Firebird para nada

Como ves, en estos casos se trabaja un poco más pero te aseguras que todas las transacciones terminen con un COMMIT.

Recolectando la basura

Adicionalmente, en tu aplicación deberías tener un proceso que se encargue de hacer un SELECT * a todas las tablas de tu Base de Datos. Cuando el usuario ejecuta ese proceso entonces se hace un SELECT * FROM MiTabla1, SELECT * FROM MiTabla2, SELECT * FROM MiTabla3, etc.

Recordatorio:

La técnica mostrada en este artículo es necesaria solamente para las bases de datos que deben estar activas durante 24/7/365. En los demás casos se puede seguir el procedimiento normal de hacer el sweep automáticamente o manualmente.

Conclusión:

Las bases de datos de Firebird pueden perfectamente ser usadas en entornos que las requieren abiertas durante las 24 horas, los 7 días de la semana y los 365 días del año. Lo que debemos tener en cuenta en esos casos es que deberíamos evitar el sweep porque el sweep puede demorar mucho tiempo en bases de datos muy grandes. La forma de evitar el sweep es nunca terminar las transacciones con ROLLBACK porque las transacciones que terminan con ROLLBACK dejan basura que solamente puede ser eliminada con un sweep, en cambio la basura dejada por las transacciones que terminan con un COMMIT puede ser eliminada con un comando SELECT * FROM MiTabla.

 Entonces, el problema es causado por la forma en que Firebird actúa cuando se hace un UPDATE o un DELETE que finalizaron con un ROLLBACK pero puede ser solucionado si la aplicación finaliza todas las transacciones con un COMMIT.

Artículos relacionados:

La arquitectura MGA

Entendiendo a las transacciones

Entendiendo a los identificadores de las transacciones

Entendiendo sweep y garbage collection

El índice del blog Firebird21

El foro del blog Firebird21

 

Anuncios

La Next Transaction después de un ciclo backup/restore

Deja un comentario

Como recordarás, al Firebird hay unas cuantas transacciones que le interesan, ellas son:

  • Oldest Transaction, representada por las letras OIT que significan Oldest Interesting Transaction
  • Oldest Active Transaction, representada por las letras OAT
  • Oldest Snapshot Transaction, representada por las letras OST
  • Next Transaction, representada por las letras NT

 Puedes leer más sobre ellas en este artículo:

Entendiendo los identificadores de las transacciones

Los números de las transacciones siempre van en aumento, hasta que se realiza un ciclo backup/restore.

¿Qué sucede cuándo se realiza un ciclo backup/restore?

 Que en la Base de Datos restaurada (no en la original, sino en la restaurada), el identificador de todas las transacciones que finalizaron con un COMMIT es puesto en 1.

¿Y por qué el número de la Next Transaction no es 2, ó 3, ó un número muy cercano a ellos?

Después de todo, podrías pensar que si todas las transacciones que finalizaron con un COMMIT tienen el identificador 1, la Next Transaction debería tener el número 2. O si el programa GBAK abre alguna transacción más, entonces un número muy cercano al 2. Pero no es así, la Next Transaction puede estar muy alejada del número 2.

La respuesta es que el programa GBAK puede abrir muchas transacciones cuando restaura una Base de Datos.

Ejemplo:

En la ventanita “Símbolo del sistema” escribimos el comando GSTAT -h para conocer los identificadores de las transacciones de una Base de Datos.

NT1

Captura 1. Si haces clic en la imagen la verás más grande

Se hace el ciclo backup/restore con la opción -v[erbose] y luego se ejecuta el comando GSTAT -h en la Base de Datos restaurada, obteniendo estos valores:

NT2

Captura 2. Si haces clic en la imagen la verás más grande

En la Captura 1. podemos ver los identificadores originales de las transacciones y en la Captura 2. podemos ver los valores de los identificadores en la Base de Datos restaurada. Y lo que llama la atención es que la Next Transaction es 304, un número aparentemente muy alto, muy alejado del 3 que uno podría esperar. ¿Por qué?

Porque el programa GBAK abre varias transacciones:

  • Al iniciar la restauración de la Base de Datos, la Next Transaction es puesta en 1
  • Luego, para restaurar los metadatos puede abrir nuevas transacciones
  • Si se usó la opción -o[nce] se iniciará una transacción por cada tabla restaurada
  • Si se usó la opción -v[erbose] se iniciará una transacción por cada índice restaurado

Entonces, ahora sí ya tiene sentido del por qué la Next Transaction está tan alejada del número 1. Es que el programa GBAK abre varias transacciones al restaurar un backup.

Fíjate en un detalle interesante. Como la Base de Datos restaurada aún no ha sido utilizada entonces no importa que los identificadores de las otras transacciones (OIT, OAT, OST) estén desfasados. En este momento nada significan y por lo tanto el número que tengan es irrelevante.

Sin embargo, si te conectas a la Base de Datos e inicias una transacción cuando te desconectes esos números sí ya estarán actualizados. Por ejemplo:

NT3

Captura 3. Si haces clic en la imagen la verás más grande

Aquí, usando el programa ISQL nos conectamos a la Base de Datos restaurada, salimos con un EXIT (al salir con un EXIT de ISQL se ejecuta automáticamente un COMMIT, si se sale con un QUIT entonces se ejecuta automáticamente un ROLLBACK) y volvemos a verificar los identificadores de las transacciones ¿y con qué nos encontramos?

Conque los identificadores OIT, OAT y OST se han actualizado.

Estos nuevos valores sí son los correctos. Los anteriores no tenían importancia porque aún no se había usado la Base de Datos, entonces eran irrelevantes sus valores.

Para verificar que la opción -v[erbose] realmente inicia varias transacciones se restauró la misma Base de Datos pero sin esa opción, y este fue el resultado obtenido:

NT4

Captura 4. Si haces clic en la imagen la verás más grande

Como puedes ver ahora la Next Transaction es solamente 84, entonces se comprobó que usando la opción -v[erbose] el programa GBAK inicia varias transacciones. Usando esa opción, Next Transaction fue 304, sin usarla fue 84. Desde luego que esos números variarán en tu caso porque dependen de la cantidad de índices que hayas definido.

Conclusión:

Al hacer un ciclo backup/restore con el programa GBAK, en la nueva Base de Datos el valor de la Next Transaction empieza con 1 pero como el programa GBAK abre varias transacciones para poder realizar sus tareas, entonces al finalizar la restauración el valor de la Next Transaction puede estar bastante alejado del 1, dependiendo de la cantidad de transacciones que el programa GBAK tuvo que abrir.

No importa cuales son los valores de los identificadores OIT, OAT, y OST al finalizar la restauración porque aún no han sido utilizados. Solamente después de finalizar la primera transacción sus valores serán actualizados y estarán muy próximos al de la Next Transaction.

Artículos relacionados:

Entendiendo los identificadores de las transacciones

El índice del blog Firebird21

El foro del blog Firebird21