¿Es seguro usar Servidor y embedded al mismo tiempo?

Deja un comentario

Sí, … pero con algunas condiciones.

En ocasiones podrías querer conectarte usando Servidor (es decir: Classic, SuperClassic, o SuperServer) a una Base de Datos y en ocasiones podrías querer conectarte usando embedded. Entonces … ¿puedes hacer algo así?

Sí, pero no puedes realizar la conexión al mismo tiempo.

Veamos:

  1. Conectarse a la Base de Datos A con Servidor y a la Base de Datos A con embedded. NO PERMITIDO
  2. Conectarse a la Base de Datos A con embedded y a la Base de Datos A con Servidor. NO PERMITIDO
  3. Conectarse a la Base de Datos A con Servidor y a la Base de Datos B con embedded. PERMITIDO
  4. Conectarse a la Base de Datos A con embedded y a la Base de Datos A con embedded. NO PERMITIDO

La diferencia entre el caso 1. y el caso 2. está en quien se conectó primero a la Base de Datos A, pero sin importar quien lo haya hecho, la segunda conexión no es permitida.

Como habrás notado al mirar los casos anteriores, si te conectas por embedded, lo haces de forma exclusiva. Ninguna otra conexión a esa misma Base de Datos es permitida.

Resumiendo:

Se puede conectar usando Servidor y usando embedded en la misma computadora, pero la condición es que se haga a bases de datos distintas.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Conexión a través de Internet

22 comentarios

En esta época es cada vez más frecuente que debamos conectarnos remotamente a las bases de datos. Y aunque hay varias formas de hacer eso, lo normal es que lo hagamos a través de Internet.

Entonces, ¿qué necesitamos para poder establecer una conexión exitosa?

ROUTER

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

En el Gráfico 1 podemos ver un caso típico: una computadora remota se conecta a Internet a través de un router, y nuestro Servidor se conecta a Internet a través de otro router. La computadora remota solamente conoce la IP pública o IP estática, pero no conoce (ni debería conocer jamás) la IP que nuestro Servidor tiene en la red local.

Como podemos ver en el Gráfico 1, nuestro router tiene dos IP, una pública, conocida por todo el mundo (que en este ejemplo es 120.130.140.150) y una privada, conocida solamente dentro de la red local (que en este ejemplo es 192.168.1.1)

La computadora donde tenemos instalado el Servidor del Firebird también tiene una IP privada (que en este ejemplo es 192.168.1.31).

¿Qué debemos hacer para que la conexión pueda ser establecida?

Decirle al router que toda la comunicación que se realice a través de Internet mediante un determinado puerto (para el caso de Firebird, generalmente es el 3050) se redirija a la computadora donde tenemos nuestro Servidor de Firebird.

O sea, si alguien envía datos a nuestro router usando la IP estática y el puerto que establecimos, el router enviará esos datos a la computadora donde tenemos el Servidor del Firebird.

Ejemplo de conexión:

A través de las siguientes capturas de pantalla veremos como debemos configurar nuestro router para que podamos conectarnos remotamente a una Base de Datos. Aquí, se usó un router de la marca Motorola, y por supuesto que si el router es de otra marca las capturas serán diferentes, pero en esencia es la misma cosa.

Router2

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

Router3

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

Router4

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

Router5

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

Resumen:

  1. Abrir el navegador (Internet Explorer, Firefox, Google Chrome, etc.)
  2. En la barra de direcciones escribir: 192.168.1.1 (esta es la IP privada del router)
  3. En Username escribir: AdminTHW (todo junto, sin espacios en blanco)
  4. En Password escribir: motorola
  5. Hacer clic sobre el botón Advanced
  6. Hacer clic sobre el botón Forwarding
  7. Escribir el IP de la computadora donde se encuentra el Servidor del Firebird. En este ejemplo es 192.168.1.31
  8. En Start Port y en End Port escribir 3050
  9. Hacer clic sobre el botón Apply

Conexión:

A partir de este momento ya podremos conectarnos a la Base de Datos remota con un comando como el siguiente:


CONNECT 120.130.140.150:D:\BASESDATOS\CONTA.FDB USER SYSDBA PASSWORD masterkey;

Problemas:

Si no puedes conectarte a la Base de Datos, verifica lo siguiente:

  • Que la IP pública pueda ser accedida. Eso lo harías con el comando PING. Abre una ventanita «Símbolo del sistema» y escribe: PING 120.130.140.150 (desde luego que aquí escribirías el PING que le corresponde a tu IP pública o estática, 120.130.140.150 es solamente un ejemplo)

Router6

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

Como puedes ver en la Captura 5, el IP 120.130.140.150 no puede ser accedido. Cuando la conexión puede realizarse sin problema todos los paquetes enviados deben ser recibidos y el porcentaje de perdidos debe ser 0%

Importante: Tú no debes escribir 120.130.140.150 sino el IP público (o estático) que tiene tu router.

  • Que el firewall no esté bloqueando el puerto que usas para conectarte. En nuestro ejemplo usamos el puerto 3050, ese puerto debe estar abierto o nada podrá enviarse o recibirse a través de él.
  • Que la computadora donde se encuentra el Servidor del Firebird sea visible para las otras computadoras de la red local. Eso también puedes averiguarlo con el comando PING y luego poniendo la IP privada, en nuestro ejemplo sería: PING 192.168.1.31
  • Que te conectes a la Base de Datos usando el mismo puerto que le dijiste al router que redirigiera al Servidor del Firebird. Por defecto, con Firebird se usa el puerto 3050, si quieres usar otro puerto puedes hacerlo pero en tu string de conexión debes indicarlo, porque el Firebird no puede adivinar que estás usando otro puerto. Así que se lo debes indicar:
CONNECT 120.130.140.150/3152:D:\BASESDATOS\CONTA.FDB USER SYSDBA PASSWORD masterkey;

En este ejemplo usamos el puerto 3152 para la conexión, por lo tanto es ese puerto el que debes redirigir en el router (y para que el Firebird use el puerto 3152 debes indicárselo en el archivo FIREBIRD.CONF, en la entrada RemoteServicePort).

Seguridad:

Internet es una red pública y por lo tanto todo lo que se envíe a través de esa red es pasible de ser interceptado y leído por personas no autorizadas. Para disminuir el riesgo existen programas (como el Zebedee, por ejemplo) que comprimen y encriptan los datos, haciendo por lo tanto la tarea de los hackers mucho más dificultosa. Firebird envía los datos sin encriptarlos entonces si son interceptados podrán ser leídos bastante fácilmente. Al usar Zebedee conseguiremos dos cosas: 1) como los datos se comprimen entonces la velocidad de transmisión será más alta, 2) como los datos se encriptan entonces la posibilidad de ser leídos por personas no autorizadas es nula o casi nula.

Por lo tanto, es altamente recomendable usar Zebedee (o algún programa similar) si la Base de Datos podrá ser accedida a través de Internet.

Conclusión:

Para que podamos conectarnos remotamente a una Base de Datos, los datos enviados a nuestra IP pública usando el puerto 3050 (o el que especifiquemos) deben ser redirigidos a la computadora donde se encuentra el Servidor del Firebird.

Para ello, debemos configurar el router, porque de lo contrario jamás podremos realizar la conexión. Al router se le indica que todos los datos que lleguen a través del puerto 3050 (o el que deseemos) se envíen a la computadora cuya IP privada se especifique.

Como Internet es una red pública, es recomendable que se use algún programa (como el Zebedee) para encriptar los datos que se envían entre computadoras.

Artículos relacionados:

Proteger a las bases de datos visibles en Internet

Usando Zebedee con Firebird

Usando Zebedee con Firebird. Parte 2

Ejemplos del uso de Zebedee con Firebird

El índice del blog Firebird21

El foro del blog Firebird21

Cantidad de conexiones concurrentes

5 comentarios

Cuando usamos Firebird lo normal es que varios usuarios estén conectados a la misma Base de Datos y al mismo tiempo. Hay excepciones, por supuesto, que pueden ser por diseño: estamos usando la versión embedded, o porque casi todos se fueron a su casa y uno solo se quedó trabajando.

Entonces la pregunta es: ¿cuántos usuarios pueden estar conectados concurrentemente a una Base de Datos?

Concurrentemente significa «al mismo tiempo».

Pues bien, eso depende de la versión del Firebird y de la arquitectura que estemos usando.

SuperServer, hasta la versión 2.5.2, 1024 usuarios concurrentes. Desde la versión 2.5.3, 2048 usuarios concurrentes.

SuperClassic, hasta la versión 2.5.2, 1024 usuarios concurrentes. Desde la versión 2.5.3, 2048 usuarios concurrentes.

Classic, no tiene límites. Depende solamente de la memoria RAM disponible.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

 

Conectando por XNET o por TCP/IP

Deja un comentario

Cuando queremos conectarnos a una Base de Datos local típicamente tenemos dos formas de hacerlo:

1. Usando XNET, por ejemplo:

C:\MiBaseDatos.FDB

2. Usando TCP/IP, por ejemplo:

localhost:C:\MiBaseDatos.FDB

Ambas tienen sus ventajas y sus desventajas. Si nos conectamos de la forma 1., o sea usando XNET la conexión será más rápida pero el problema es que si se «cuelga» la aplicación entonces el proceso FB_INET_SERVER (usado por la arquitectura Classic) permanecerá en la memoria. El problema es con Classic, ya que SuperServer y SuperClassic no tienen este problema.

Desde luego que lo correcto es que la aplicación no se «cuelgue» pero si por algún motivo eso llegara a ocurrir entonces tendremos en la memoria un proceso (o muchos procesos si se colgó muchas veces) que no debería/n estar ahí.

Entonces, si usamos la arquitectura Classic debemos tener bien presente que un «cuelgue» de la aplicación no eliminará al proceso FB_INET_SERVER de la memoria.

Este es un error que se espera sea subsanado dentro de poco tiempo, pero mientras tanto hay que recordarlo.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

 

Evitando que un usuario se conecte más de una vez (método mejorado)

12 comentarios

En este artículo ya habíamos visto un método para evitar que los usuarios se conecten más de una vez a la Base de Datos:

Evitando que un usuario se conecte más de una vez a la Base de Datos

pero allí podríamos tener un pequeño problema si la computadora donde se encuentra el Servidor del Firebird se apaga incorrectamente, dejando por lo tanto nombres de usuarios en la tabla CONECTADOS. Esos usuarios evidentemente cuando se reinicia el Servidor no estarán conectados pero en la tabla CONECTADOS dirá que sí lo están. Una solución sería que un usuario quien no estaba conectado borre todas las filas de esos usuarios en la tabla CONECTADOS. Funcionará bien, pero, hmmmmmmm, no es profesional, ¿verdad?

Aquí hay otro método para borrar a esos usuarios «fantasmas». Son «fantasmas» porque la tabla CONECTADOS nos indica que están conectados a la Base de Datos pero la realidad es que no lo están.

Lo que haremos será agregarle una columna a la tabla CONECTADOS y en esa columna guardaremos el identificador de la conexión. Luego, en nuestro trigger antes de intentar la inserción borraremos a todos los usuarios cuyos identificadores de conexión no se encuentren en la tabla CONECTADOS y también en la tabla MON$ATTACHMENTS.

En la tabla del sistema MON$ATTACHMENTS se guardan los datos de todas y cada una de las conexiones actuales. Uno de esos datos es el identificador de la conexión.

Entonces, la estructura de nuestra tabla CONECTADOS ahora sería la siguiente:

CONECTADOS1

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

Como puedes ver en la Captura 1. a la tabla CONECTADOS se le agregó la columna CON_IDECON, para guardar en esa columna el identificador de la conexión (ese identificador lo encontraremos en la tabla MON$ATTACHMENTS y para la conexión actual siempre será igual a CURRENT_CONNECTION).

El trigger para insertar un usuario a la tabla CONECTADOS

Nuestro trigger ahora cambiará un poco, quedará así:

Listado 1.

CREATE TRIGGER INSERTAR_CONECTADO
   ACTIVE ON CONNECT
   POSITION 2
AS
BEGIN

   -- Primero, se borran las filas de los usuarios que no están conectados
   -- pero aparecen como conectados

   DELETE FROM
      CONECTADOS
   WHERE
      CON_IDECON NOT IN (SELECT MON$ATTACHMENT_ID FROM MON$ATTACHMENTS);

   -- Segundo, se trata de insertar una fila a la tabla CONECTADOS.
   -- Como la tabla CONECTADOS tiene una restricción UNIQUE KEY, un usuario
   -- no se podrá conectar más de una vez al mismo tiempo

   INSERT INTO CONECTADOS
              (CON_IDENTI, CON_IDECON , CON_NOMBRE , CON_TIMEST)
       VALUES (0 , CURRENT_CONNECTION, CURRENT_USER, CURRENT_TIMESTAMP);

END;

¿Qué hace este trigger?

Primero, borrará todas las filas de la tabla CONECTADOS cuyo valor de CON_IDECON no coincida con algún valor de ATTACHMENT_ID de la tabla ATTACHMENTS. En otras palabras, en la tabla CONECTADOS quedarán solamente los nombres de los usuarios que efectivamente están conectados a la Base de Datos, no tendrá filas «fantasmas».

Segundo, intentará insertar una fila a la tabla CONECTADOS. Si el nombre del usuario que intenta la conexión no existe en esa tabla entonces podrá continuar pero si existe entonces ocurrirá una excepción y se evitará la conexión.

El trigger para borrar un usuario de la tabla CONECTADOS

Este trigger quedará exactamente igual al que habíamos visto en el artículo anterior, no tiene por qué cambiar.

Listado 2.

CREATE TRIGGER BORRAR_CONECTADO
   ACTIVE ON DISCONNECT
   POSITION 3
AS
BEGIN

   DELETE FROM
      CONECTADOS
   WHERE
      CON_NOMBRE = CURRENT_USER;

END;

Conclusión:

Para evitar que un apagado anormal del Servidor del Firebird deje usuarios «fantasmas» en la tabla CONECTADOS podemos tener en esa tabla una columna que nos indique cual es el identificador de cada conexión. Así, antes de intentar insertar los datos de un usuario en la tabla CONECTADOS borramos las filas de esa tabla que no tengan una conexión activa. Lo que conseguiremos será que la tabla CONECTADOS siempre nos muestre los nombres de los usuarios que efectivamente se encuentran conectados.

Artículos relacionados:

Limitando la cantidad de usuarios conectados

Evitando que un usuario se conecte más de una vez a la Base de Datos

El índice del blog Firebird21

El foro del blog Firebird21

Evitando que un usuario se conecte más de una vez a la Base de Datos

17 comentarios

A veces quieres que un usuario no pueda conectarse desde más de una computadora al mismo tiempo, o desde la misma computadora más de una vez. Eso es especialmente importante en las aplicaciones de seguridad o donde se maneja dinero. Entonces, ¿cómo evitamos que lo haga?

En nuestra ayuda vienen los triggers de las bases de datos. Estos se disparan cuando alguien se conecta o se desconecta de la Base de Datos. Lo que podemos hacer es crear una tabla, la llamamos por ejemplo CONECTADOS y cada vez que alguien se conecta insertamos una fila a esta tabla, y cada vez que se desconecta borramos la fila que le corresponde.

CONECTADOS1

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

La columna CON_NOMBRE se encuentra en una restricción Unique Key, como podemos ver en su DDL:

ALTER TABLE CONECTADOS ADD CONSTRAINT UQ_CONECTADOS UNIQUE (CON_NOMBRE);

¿Por qué?

Porque de esa manera no tendremos que verificar nosotros que un usuario no se conecte más de una vez, el Firebird hará esa tarea por nosotros.

Si no tuviéramos esa restricción Unique Key entonces tendríamos que buscar el nombre del usuario en la tabla CONECTADOS y si existe allí entonces lanzar una excepción para evitar que se conecte. Pero al tener la restricción no es necesario que hagamos eso, ya que el mismo Firebird lanzará automáticamente la excepción. O sea, nos ahorramos trabajo.

En un trigger de la Base de Datos que se dispara cuando alguien se conecta haríamos el intento de insertar una fila en la tabla CONECTADOS, algo como:

CREATE TRIGGER INSERTAR_CONECTADO
   ACTIVE ON CONNECT
   POSITION 2
AS
BEGIN

   INSERT INTO CONECTADOS
              (CON_IDENTI, CON_NOMBRE , CON_TIMEST)
       VALUES (0 , CURRENT_USER, CURRENT_TIMESTAMP);

END;

Si el nombre del usuario no existe en la tabla CONECTADOS entonces se conectará sin problemas, pero si existe entonces el Firebird lanzará una excepción «violation of PRIMAY or UNIQUE KEY constraint …»

Y como lanzó una excepción el usuario no podrá conectarse.

No debemos olvidarnos de crear otro trigger de la Base de Datos, el que se encargará de borrar la fila que le corresponde al usuario de la tabla CONECTADOS, sería algo como:

CREATE TRIGGER BORRAR_CONECTADO
   ACTIVE ON DISCONNECT
   POSITION 3
AS
BEGIN

   DELETE FROM
      CONECTADOS
   WHERE
      CON_NOMBRE = CURRENT_USER;

END;

Entonces, cuando el usuario se desconecta la fila con su nombre será borrada de la tabla CONECTADOS.

¿Y qué ocurre si se apagó anormalmente la computadora donde se encuentra el Servidor del Firebird?

Si las cosas se hacen bien y como corresponde entonces la computadora donde se encuentra el Servidor del Firebird jamás debería apagarse intempestivamente, debería tener sí o sí una UPS en buen estado y nunca se apagaría esa computadora si hay alguien conectado a la Base de Datos.

Pero sabemos que no siempre las cosas se hacen correctamente. En ese caso los usuarios que hubieran estado conectados a la Base de Datos no podrán volver a conectarse y se requerirá que otro usuario, alguien que no estaba conectado, borre los nombres de dichos usuarios de la tabla CONECTADOS.

Luego de eso ya podrán conectarse nuevamente.

Ventaja adicional:

Este método además de evitar que un usuario se conecte más de una vez también tiene la ventaja de que siempre podremos saber quienes son TODOS los usuarios conectados.

CONECTADOS2

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

Como podemos ver en la Captura 2. un simple SELECT nos dirá los nombres de cada usuario conectado y también la fecha y hora de su conexión.

Conclusión:

Si queremos evitar que un usuario se conecte más de una vez a la Base de Datos y al mismo tiempo entonces podemos crear una tabla y dos triggers: uno que se disparará cuando intenta conectarse y el otro que se disparará cuando se desconecta.

De esta manera solamente podrá conectarse una vez. Tendrá que desconectarse para luego volver a conectarse.

Adicionalmente este método tiene la ventaja de que en cualquier momento podremos saber quienes son los usuarios conectados y cuando se conectaron.

Artículos relacionados:

Como evitar que se conecten a una Base de Datos

Impidiendo la conexión a una Base de Datos

El índice del blog Firebird21

El foro del blog Firebird21

Conectándose con ADO a las bases de datos

6 comentarios

Como seguramente sabes, para conectarte a una Base de Datos de Firebird puedes utilizar varios métodos, uno de ellos es ADO (ActiveX Data Objects). Fue desarrollado por Microsoft y por lo tanto se usa principalmente con Windows.

Con ADO se pueden crear tablas, borrar tablas, insertar filas, modificar filas, borrar filas, consultar filas, etc., todas las operaciones normales.

El método más usado para conectarse a bases de datos de Firebird creo que es ODBC pero he leído que ADO es más rápido. No lo puedo afirmar ni negar porque aún no he realizado pruebas intensivas ni he encontrado alguna página donde las hayan hecho y muestren los resultados.

Lo primero que debes hacer si quieres conectarte por ADO es conseguir un proveedor, aquí encontrarás uno de ellos:

http://www.ibprovider.com/eng/documentation/firebird_interbase_odbc_drivers.html

ADO1

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

Después de descargarlo e instalarlo ya estará listo para ser usado.

Gracias a la colaboración de Jaume (ver los comentarios más abajo) también disponemos del IBOLE.DLL el cual dicen que es muy bueno. Puedes descargarlo desde:

http://www.mediafire.com/download/7hpf8ppyudpnn4k/IBOLE.dll

¿Cómo se utiliza ADO?

Primero, debes conectarte a la Base de Datos

Segundo, debes obtener un RecordSet, o sea un conjunto resultado con los datos que te interesan

Tercero, puedes manipular esos datos como desees

Cuarto, debes cerrar el RecordSet

Quinto, debes cerrar la conexión

Ejemplo. Mostrar los nombres de los clientes

En nuestra Base de Datos tenemos una tabla llamada CLIENTES y queremos obtener los nombres de los mismos, este pequeño programita desarrollado con Visual FoxPro cumplirá esa  tarea:

CLEAR

CLOSE ALL

CLEAR ALL

Private oSQL, oRecordSet

*--- Primero, se conecta a la Base de Datos

oSQL = CreateObject("ADODB.Connection")

with oSQL
   .Provider = "LCPI.IBProvider.3.Lite"
   .ConnectionString = "User=SYSDBA;password=masterkey;Data Source=E:\SQL\DATABASES\BLOG_DB.FDB;auto_commit=true"
   .Open()
endwith

*--- Segundo, se crea un RecordSet

oRecordSet = CreateObject("ADODB.RecordSet")

*--- Tercero, se obtienen los datos que nos interesan

oRecordSet.Open("Select * From CLIENTES",oSQL)

*--- Cuarto, se procesan los datos obtenidos

do while !oRecordSet.EOF
   ? oRecordSet.Fields.Item("CLI_NOMBRE").Value
   oRecordSet.MoveNext()
enddo

*--- Quinto, se cierran y se eliminan los objetos que se habían creado

oRecordSet.Close()

oSQL.Close()

Release oRecordSet, oSQL

Después de ejecutarlo el resultado obtenido será algo similar a esto:

ADO2

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

Como puedes ver, en la pantalla se mostraron los nombres de los 4 clientes cuyos datos estaban guardados en la tabla respectiva.

A diferencia de ODBC aquí no obtendrás un cursor para trabajar con él. Un cursor es una tabla .DBF temporal y desde mi punto de vista es más útil porque puede ser indexada, mostrada en un browse, etc. La forma de usar ADO me parece más antigua, más manual, aunque sobre gustos…

Desde luego que siempre puedes enviar el contenido de los recordsets a cursores o a tablas .DBF pero sería un trabajo adicional y ¿vale la pena? eso ya no lo sé porque dependerá de tus circunstancias.

Propiedades, métodos y eventos de ADO

ADO tiene muchísimas propiedades, métodos y eventos que puedes usar, en el ejemplo anterior se mostró solamente una pequeñísima parte de ellos. Si te interesa el tema hay varias páginas con información útil en Internet, una de ellas es la siguiente:

http://www.w3schools.com/ado/default.asp

Conclusión:

Si quieres, puedes usar ADO para conectarte a una Base de Datos pero yo hasta ahora no le he encontrado alguna ventaja. Quizás sea más rápido que ODBC y en ese caso sí podría justificarse conectarse mediante ADO, pero eso es algo que aún no he verificado.

Usar cursores es más rápido y más sencillo (para mí, claro) que estar obteniendo los datos fila por fila. Esto lo notarás principalmente cuando quieras imprimir informes porque mientras un cursor o una tabla .DBF ya están preparados para ser usados en informes, los recordsets no lo están y deberán prepararse previamente y habría que ver si vale la pena el esfuerzo.

De todas maneras, siempre es bueno tener varias alternativas para hacer cualquier cosa y disponer de ADO aumenta nuestras posibilidades de conexión a las bases de datos, así que bienvenido.

Descargas de archivos .DLL para usarlos como Proveedor de ADO

http://www.ibprovider.com/eng/documentation/firebird_interbase_odbc_drivers.html

http://www.mediafire.com/download/7hpf8ppyudpnn4k/IBOLE.dll

Artículos relacionados:

w3schools.com

El índice del blog Firebird21

Usando un «connection pool»

2 comentarios

Cuando la cantidad de usuarios es grande y los recursos del Servidor son pocos puedes utilizar un «connection pool» para que todos esos usuarios puedan estar conectados a pesar de los pocos recursos disponibles.

Esta es una técnica que hace años se utilizó bastante pero que está decayendo porque la memoria y las redes son relativamente baratas entonces suele ser más sencillo y más rápido invertir en hardware para aumentar los recursos del Servidor y de esa manera solucionar el problema.

Aunque claro, eso no siempre es posible, hay muchos casos en que usar un «connection pool» es la mejor alternativa. Por ejemplo si los usuarios que se conectan son miles o millones y lo hacen a través de Internet. Allí, tener un Servidor que pueda manejar esas miles o millones de conexiones puede ser demasiado costoso. Y entonces, un «connection pool» es la solución a los tres problemas típicos:

  1. La cantidad de conexiones que puede manejar el Servidor siempre es finita, es limitada
  2. Cada conexión demora en abrirse y en cerrarse, no es instantánea
  3. Cada conexión consume recursos (memoria) de la computadora donde se encuentra el Servidor

¿Qué es un «connection pool»?

Es una técnica para que un Servidor con pocos recursos pueda manejar muchísimas conexiones. De esta manera se solucionarían los tres problemas ennumerados arriba.

¿Cómo funciona?

Las aplicaciones (Contabilidad, Facturación, Sueldos, Ventas, etc.) envían sus solicitudes al «connection pool» y éste las envía al Servidor.

Lo normal es que las aplicaciones envíen sus solicitudes al Servidor. Pues aquí no ocurre así, sino que ocurre esto:

CONNECTION1

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

El «connection pool» mantiene varias conexiones abiertas permanentemente a la Base de Datos. Cuando una aplicación realiza una solicitud el programa verifica si alguna de esas conexiones está libre. Si lo está, la utiliza. Si no hay conexiones libres entonces realiza una nueva conexión.

Cuando una conexión ha estado inactiva mucho tiempo (digamos, 10 minutos) y es mayor que el número mínimo de conexiones entonces la cierra.

Ejemplo:

Una empresa tiene 1.000 usuarios que se conectan diariamente a su Base de Datos. En promedio cada día 950 de esos usuarios realizan 120 transacciones cada uno, cada una de esas transacciones demorando 100 milisegundos. Los restantes 50 usuarios realizan 40 transacciones diarias, cada una de esas transacciones demorando 900 milisegundos.

Entonces tenemos que:

950 * 120 * 100 / 1000 / 60 / 60 = 3 horas + 0,166666667 * 60= 3 horas y 10 minutos

50 * 40 * 900 / 1000 / 60 / 60 = 0, 50 * 60 = 30 minutos

Tiempo total = 3 horas y 10 minutos más 30 minutos = 3 horas y 40 minutos

El Servidor estuvo encendido durante 8 horas pero solamente estuvo activo 3 horas y 40 minutos.

El «connection pool» se configuró para mantener 50 conexiones abiertas. Si se necesitan más las abre pero cuando esas conexiones adicionales están inactivas durante más de 10 minutos, las cierra.

Entonces, cuando una aplicación envía una solicitud el «connection pool» verifica si hay alguna conexión inactiva. Si la hay, la utiliza. Si no la hay, abre una nueva conexión.

Después que el «connection pool» entregó el resultado de la solicitud a la aplicación no cierra la conexión sino que la deja libre para que pueda ser usada por otra solicitud.

De esta manera hay 50 conexiones abiertas permanentemente y quizás algunas más abiertas temporalmente. Cuando una aplicación realiza una solicitud el «connection pool» verifica si alguna de esas conexiones está inactiva. Si es así la utiliza, ahorrando tiempo y memoria, porque como ya estaba abierta no es necesario abrirla.

¿Cómo conectarse a la Base de Datos?

En este artículo habíamos visto tres formas de establecer conexión a la Base de Datos:

https://firebird21.wordpress.com/2013/12/23/sobre-conexiones-y-desconexiones/

cuando se usa un «connection pool» lo correcto es usar la opción número 3. es decir: abrir_la_conexión, realizar_la_tarea, cerrar_la_conexión

Conclusión:

Cuando los usuarios son muchos y los recursos del Servidor son pocos se puede invertir en hardware para aumentar esos recursos o utilizar un «connection pool». Este es un programa que se encarga de administrar las conexiones a la Base de Datos. Mantiene siempre una cierta cantidad de conexiones abiertas y así cuando alguna aplicación envía una solicitud trata de usar una de esas conexiones abiertas. Si no es posible porque todas están ocupadas entonces abre una nueva conexión. Cuando una conexión ha estado inactiva durante mucho tiempo, la cierra.

Las aplicaciones no se conectan a la Base de Datos sino que se conectan al «connection pool», el cual se encarga de enviar las solicitudes al Servidor y de recibir los resultados.

Para que esta técnica funcione las aplicaciones siempre deben abrir_la_conexión, realizar_la_tarea, cerrar_la_conexión porque si mantienen las conexiones abiertas esta técnica no funcionará.

Artículos relacionados:

Sobre conexiones y desconexiones

El índice del blog Firebird21

 

Sobre conexiones y desconexiones

7 comentarios

¿Cuándo conectarse y cuándo desconectarse de la Base de Datos?

Aquí tenemos varias posibilidades, analizaremos lo que implica cada una de ellas:

  1. Conectarse cuando la aplicación (Contabilidad, Facturación, Ventas, Sueldos, etc.) inicia y desconectarse cuando la aplicación finaliza
  2. Conectarse cuando el formulario se inicia y desconectarse cuando finaliza
  3. Conectarse para realizar una tarea y desconectarse cuando la tarea finaliza

¿Cuál elegir?

En general y en casi todos los casos la mejor opción es la número 1. ¿Por qué? porque tener una conexión abierta no puede causarle daño a la Base de Datos y eso de estar abriendo y cerrando conexiones sin necesidad solamente acarreará pérdida de tiempo. Abrir una conexión o cerrar una conexión no es instantáneo, toma unos cuantos milisegundos hacerlo. Puede parecer muy poco pero si lo multiplicas por la cantidad de veces que un usuario lo hace en un día y a ese resultado lo multiplicas por la cantidad de usuarios y a ese resultado lo multiplicas por la cantidad de días laborables del mes puedes encontrarte con muchos minutos o inclusive muchas horas desperdiciadas por estar abriendo y cerrando conexiones sin necesidad.

Pero hay casos en los que sí es conveniente abrir_conexión, realizar_tarea, cerrar_conexión ¿cuáles son esos casos? cuando la señal es débil o es mala o siempre se realiza por Internet. Por ejemplo si alguien está viajando y se conecta al Servidor de la empresa desde su notebook (también llamada laptop) y sufre frecuentes cortes de Internet. O cuando la conexión siempre es a través de Internet (el caso de las aplicaciones «en la nube»).

Pero cuando se trata de una red local que funciona bien no tiene sentido eso de abrir_conexión, realizar_tarea, cerrar_conexión porque ningún beneficio se obtiene de ello y sí perjuicios: por un lado pérdida de tiempo como ya habíamos visto y por el otro que no se podrían usar tablas GTT de conexión, solamente se podrían usar tablas GTT de transacción.

Conclusión:

Si la conexión a la Base de Datos es a través de una red local entonces siempre lo más conveniente es usar la opción 1.

La opción 3 suele ser la más conveniente cuando los cortes de conexión son frecuentes, eso podría suceder cuando alguien está viajando y usando una notebook para conectarse a la Base de Datos que se encuentra en el local de la empresa.

También habría que usar la opción 3. cuando los usuarios siempre o mayormente se conectan por Internet a la Base de Datos.

Lo mejor técnica entonces es que desde tu aplicación el usuario pueda elegir el método de conexión. Aquellos usuarios que lo hacen a través de una red local deberían tener habilitada la opción 1. y aquellos que lo hacen a través de Internet deberían tener habilitada la opción 3. Y siempre deberían tener la posibilidad de cambiarse de la una a la otra.

Artículo relacionado:

El índice del blog Firebird21

Limitando la cantidad de usuarios conectados

11 comentarios

A veces, puede interesarnos limitar la cantidad de usuarios que se conectan a una Base de Datos usando nuestra aplicación. Por ejemplo, si le vendimos 5 licencias a un cliente queremos que solamente puedan conectarse desde 5 computadoras.

Fíjate que no le podemos limitar las conexiones a la Base de Datos a nuestro cliente, porque los datos son suyos, no nuestros. O sea que si él quiere conectarse usando ISQL.EXE, EMS SQL Manager, IBExpert, Flame Robin, o cualquier otro programa puede hacerlo, no se lo podemos impedir a no ser que él haya firmado un contrato donde está claramente establecido que tiene prohibido hacerlo.

En otras palabras, no le podemos impedir que se conecte, 10, 20, ó 590 veces concurrentemente desde afuera de nuestra aplicación.

Pero lo que sí podemos hacer es limitar la cantidad de usuarios que se conectan usando nuestra aplicación. Por ejemplo, podemos impedirle que se conecten más de 5 usuarios usando nuestro sistema de Contabilidad.

Para conseguir nuestro objetivo usaremos excepciones y triggers de la Base de Datos.

Ejemplo:

Tenemos una aplicación cuyo ejecutable se llama MIAPLICACION.EXE y queremos limitar a un máximo de 5 conexiones simultáneas.

CREATE EXCEPTION E_ACCESO_NO_PERMITIDO 'La cantidad de licencias ya alcanzó el límite';

Método 1

CREATE TRIGGER DB_TRIGGER_CONNECT_1
   ACTIVE ON CONNECT
   POSITION 0
AS
   DECLARE VARIABLE lnCantidadConexiones SMALLINT;
BEGIN

   lnCantidadConexiones = (SELECT
                              COUNT(*)
                           FROM
                              MON$ATTACHMENTS
                           WHERE
                              MON$REMOTE_PROCESS LIKE '%MIAPLICACION.EXE%');

   IF (lnCantidadConexiones > 5) THEN
      EXCEPTION E_ACCESO_NO_PERMITIDO;

END;

Esto funcionará perfectamente … siempre y cuando alguien no le cambie el nombre al archivo .EXE porque la verificación se hace tomando en cuenta el nombre del archivo .EXE

Método 2

En este caso creamos una tabla llamada CONEXIONES y cada vez que alguien se conecta a la Base de Datos usando nuestro programa le agregamos una fila a esa tabla  y cuando se desconecta le borramos esa fila. La tabla CONEXIONES tiene esta estructura:

CONEXION1

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

donde como puedes ver tres columnas tienen valores por defecto, eso significa que si no se especifican en el INSERT los valores de los campos CON_FECHOR,  CON_USUARI y CON_CONEXI el Firebird automáticamente colocará en esas columnas la fecha y hora actuales, el nombre del usuario, y la conexión, respectivamente. Desde luego que puedes agregarle más columnas a esta tabla si lo deseas.

En nuestra Base de Datos creamos un trigger de Base de Datos, como éste:

CREATE TRIGGER DB_TRIGGER_CONNECT_2
   ACTIVE ON CONNECT
   POSITION 1
AS
   DECLARE VARIABLE lnCantidadConexiones SMALLINT;
BEGIN

   lnCantidadConexiones = (SELECT COUNT(*) FROM CONEXIONES);

   IF (lnCantidadConexiones > 4) THEN
      EXCEPTION E_ACCESO_NO_PERMITIDO;

END

donde lo que hacemos es verificar que la cantidad de conexiones no sobrepase el límite que habíamos determinado. ¿Pero por qué ponemos 4 y no 5? Porque la inserción en la tabla CONEXIONES se hace después de haberse conectado a la Base de Datos y por lo tanto en la variable lnCantidadConexiones no se está contando la conexión actual, por ese motivo hay que colocar el número anterior al del límite. Si la cantidad de conexiones supera a 5 entonces se lanzará una excepción y se desconectará automáticamente de la Base de Datos.

Y cuando alguien ejecuta nuestro programa lo primero que hacemos es insertarle una fila a la tabla CONEXIONES, de esta manera:

INSERT INTO CONEXIONES
   (CON_IPXXXX)
   SELECT
      MON$REMOTE_ADDRESS
   FROM
      MON$ATTACHMENTS
   WHERE
      MON$ATTACHMENT_ID = CURRENT_CONNECTION

Y cuando alguien sale de nuestra aplicación eliminamos una fila de la tabla CONEXIONES, así:

DELETE FROM
   CONEXIONES
WHERE
   CON_CONEXI = CURRENT_CONNECTION
END

Entonces, lo que sucede es lo siguiente:

  • Usando nuestra aplicación se conectan a la Base de Datos
  • Verificamos si se sobrepasó el límite de conexiones permitidas. Si así fue, se desconecta de la Base de Datos
  • Desde nuestra aplicación le insertamos una fila a la tabla CONEXIONES
  • Cuando salen de nuestra aplicación borramos una fila de la tabla CONEXIONES

De esta manera conseguimos el objetivo que nos habíamos propuesto: que jamás usen nuestra aplicación más de 5 computadoras a la vez.

Sin embargo este método tiene un pequeño problema: si ocurre un corte de la energía eléctrica varias computadoras podrían haberse desconectado de la Base de Datos pero en la tabla CONEXIONES continuarán sus datos, como si estuvieran conectadas.

En el peor de los casos podríamos tener 5 computadoras desconectadas pero la tabla CONEXIONES nos dirá que las 5 están conectadas.

Para solucionar el problema podemos usar el método 3.

Método 3

En nuestro programa, antes de insertar la fila en la tabla CONEXIONES, borramos todas las filas de la tabla CONEXIONES cuyos datos no se encuentren en la tabla MON$ATTACHMENT.

De esa manera en la tabla CONEXIONES siempre tendremos conexiones actuales y nunca tendremos conexiones «fantasmas».

¿Por qué?

Porque en la tabla MON$ATTACHMENT siempre tenemos los datos de todas las conexiones actuales. Si en la tabla CONEXIONES tenemos una conexión que no existe en la tabla MON$ATTACHMENT entonces está mal y debemos borrarla.

DELETE FROM
   CONEXIONES
WHERE
   CON_CONEXI NOT IN (SELECT MON$ATTACHMENT_ID FROM MON$ATTACHMENTS)

Entonces, lo que sucedería es lo siguiente:

  • Usando nuestra aplicación se conectan a la Base de Datos
  • Verificamos si se sobrepasó el límite de conexiones permitidas. Si así fue, se desconecta de la Base de Datos
  • Desde nuestra aplicación borramos todas las filas de la tabla CONEXIONES que no se encuentren también en la tabla MON$ATTACHMENTS
  • Desde nuestra aplicación le insertamos una fila a la tabla CONEXIONES
  • Cuando salen de nuestra aplicación borramos una fila de la tabla CONEXIONES

Conclusión:

Si limitamos la cantidad de conexiones a la Base de Datos entonces tenemos una protección contra la piratería pues aunque consigan copiar nuestra aplicación en otra computadora no podrán realizar la conexión y de nada les servirá. Además, tenemos la posibilidad de instalar nuestra aplicación en muchas computadoras para que la revisen y la evalúen pero nos aseguramos que no la usen más usuarios de los que determinemos nosotros.

Artículos relacionados:

Los triggers de la Base de Datos

El índice del blog Firebird21

Older Entries