Conexiones persistentes a bases de datos

Las conexiones persistentes son enlaces que no se cierran al finalizar la ejecución de un script. Cuando se solicita una conexión persistente, PHP comprueba si ya hay una idéntica (que ya estuviera abierta antes), utilizándola si existe. Si no, crea el enlace. Una conexión «idéntica» es una conexión que fue abierta por el mismo host, con el mismo usuario y la misma contraseña (donde sea aplicable).

Aquellos que no están plenamente familiarizados con la forma en que trabajan y distribuyen la carga los servidores web podrían confundir para qué sirven las conexiones persistentes. En particular, con ellas no se pueden abrir «sesiones de usuario» en un mismo enlace, no se puede construir una transacción eficiente y no hacen muchísimas otras cosas. De hecho, para ser sumamente precisos, las conexiones persistentes no proporcionan ninguna otra funcionalidad que no fuera posible realizar con sus hermanas no persistentes.

¿Por qué?

Esto tiene que ver con la manera en que los servidores web funcionan. Existen tres formas en las cuales un servidor web puede generar páginas web usando PHP.

El primer método es emplear PHP como una «envoltura» CGI. Cuando se ejecuta de esta forma, se crea y se destruye una instancia del intérprete de PHP por cada solicitud de página (para una página de PHP) al servidor web. Debido a que esta instancia se destruye después de cada solicitud, cualquier recurso que adquiera (tal como un enlace a un servidor de base de datos SQL) es cerrado en la destrucción de dicha instancia. En este caso, no se gana nada utilizando conexiones persistentes: simplemente no persisten.

El segundo método, y más popular, es ejecutar PHP como módulo en un servidor web multiproceso, lo que actualmente solo incluye a Apache. Un servidor multiproceso normalmente tiene un proceso (el padre) que coordina un grupo de procesos (sus hijos) los cuales son los que realmente hacen el trabajo de servir páginas web. Cuando una solicitud proviene de un cliente, esta es cedida a uno de los hijos que no esté ya sirviendo a otro cliente. Esto significa que cuando el mismo cliente hace una segunda solicitud al servidor, esta podría ser servida por un proceso hijo diferente a la primera vez. Cuando se abre una conexión persistente, cada página que solicite servicios SQL puede reusar la misma conexión establecida al servidor SQL.

El último método es utilizar PHP como complemento para un servidor web multihilo. Actualmente, PHP 4 tiene soporte para ISAPI, WSAPI, y NSAPI (en Windows), las cuales permiten usar PHP como un complemento en servidores multihilo como Nestcape FastTrack (iPlanet), Microsoft Internet Information Server (IIS), y O'Reilly's WebSite Pro. El comportamiento es esencialmente el mismo para el modelo multiproceso descrito antes.

Si las conexiones persistentes no tienen ninguna funcionalidad adicional, ¿para que son útiles?

La respuesta es extremadamente simple: Eficacia. Las conexiones persistentes son buenas si la sobrecarga para crear enlaces al servidor SQL es alta. Que esta sobrecarga sea realmente alta o no depende de muchos factores, como el tipo de base de datos que se emplea, si esta se encuentra en la misma computadora en la que está el servidor web, la carga de la máquina donde está el servidor SQL, etc. En resumidas cuentas, si la sobrecarga de una conexión es alta, las conexiones persistentes ayudan considerablemente, haciendo que un proceso hijo únicamente se conecte una vez durante su vida útil, en lugar de hacerlo cada vez que procese una página que requiera una conexión al servidor SQL. Esto significa que cada hijo que abra una conexión persistente tendrá su propia conexión persistente abierta al servidor. Por ejemplo, si se tienen 20 procesos hijos diferentes que ejecutan un script que realiza una conexión persistente al servidor SQL, se tendrán 20 conexiones diferentes al servidor SQL, una por cada hijo.

Observe, sin embargo, que esto puede tener algunos inconvenientes si se está usando una base de datos con un limite de conexiones que sea excedido por las conexiones persistentes hijas. Si la base de datos tiene un limite de 16 conexiones simultáneas, y en el curso de una sesión de un servidor ocupado 17 hilos hijos intentan conectarse, uno de ellos no será capaz de hacerlo. Si un script contiene errores que impidan el cierre de las conexiones (como un bucle infinito), la mencionada base de datos con solamente 16 conexiones podría saturarse rápidamente. Compruebe la documentación de su base de datos para obtener información sobre el manejo conexiones abandonadas o inactivas.

Advertencia

Hay un par de advertencias más a tener en cuenta cuando se utilizan conexiones persistentes. Una es que cuando se usan bloqueos de tablas con una conexión persistente, si el script por alguna razón no puede liberar el bloqueo, los scripts subsiguientes que empleen la misma conexión quedarán en espera indefinidamente, puediendo ser necesario reiniciar el servidor httpd o el servidor de la base de datos. Otra cosa es que cuando se usan transacciones, un bloque de las mismas también acarrearía al siguiente script que utiliza la conexión si la ejecución del script termina antes de que el bloque lo haga. En cualquier caso, se puede usar register_shutdown_function() para registrar una función de limpieza para desbloquear las tablas o deshacer las transacciones. Mejor aún, evitar este problema por completo no usando conexiones persistentes en scripts que utilicen bloqueos de tablas o transacciones (aún se pueden usar en otros lugares).

Un resumen importante. Las conexiones persistentes fueron diseñadas para tener una correspondencia uno a uno con las conexiones normales. Esto significa que siempre se pueden reemplazar las conexiones persistentes por conexiones no persistentes, no cambiando así la forma de funcionar un script. Esto podría (y probablemente lo hará) cambiar la eficacia del script, aunque no su funcionamiento.

Véanse también fbsql_pconnect(), ibase_pconnect(), ifx_pconnect(), ingres_pconnect(), msql_pconnect(), mssql_pconnect(), mysql_pconnect(), ociplogon(), odbc_pconnect(), oci_pconnect(), pfsockopen(), pg_pconnect() y sybase_pconnect().