En PDO, una conexión se puede hacer persistente utilizando el PDO::ATTR_PERSISTENT
atributo De acuerdo con el manual de php -
Las conexiones persistentes no se cierran al final del script, pero se almacenan en caché y se reutilizan cuando otro script solicita una conexión con las mismas credenciales. El caché de conexión persistente le permite evitar la sobrecarga de establecer una nueva conexión cada vez que un script necesita comunicarse con una base de datos, lo que resulta en una aplicación web más rápida.
El manual también recomienda no usar una conexión persistente mientras se usa el controlador PDO ODBC, ya que puede obstaculizar el proceso de agrupación de conexiones ODBC.
Así que aparentemente no parece haber inconvenientes en el uso de la conexión persistente en PDO, excepto en el último caso. Sin embargo, me gustaría saber si hay otras desventajas de usar este mecanismo, es decir, una situación en la que este mecanismo da como resultado una degradación del rendimiento o algo así.
Respuestas:
Asegúrese de leer esta respuesta a continuación , que detalla las formas de mitigar los problemas descritos aquí.
Existen los mismos inconvenientes con PDO que con cualquier otra interfaz de base de datos PHP que realice conexiones persistentes: si su script finaliza inesperadamente en medio de las operaciones de la base de datos, la siguiente solicitud que obtiene la conexión sobrante continuará donde quedó el script muerto. La conexión se mantiene abierta en el nivel del administrador de procesos (Apache para mod_php, el proceso actual FastCGI si está usando FastCGI, etc.), no en el nivel PHP, y PHP no le dice al proceso padre que deje que la conexión falle cuando el script termina de manera anormal.
Si el script muerto bloqueó las tablas, esas tablas permanecerán bloqueadas hasta que la conexión falle o el siguiente script que obtenga la conexión desbloquee las tablas en sí.
Si el script inactivo se encontraba en medio de una transacción, eso puede bloquear una multitud de tablas hasta que se active el temporizador de interbloqueo, e incluso entonces, el temporizador de interbloqueo puede eliminar la solicitud más nueva en lugar de la solicitud anterior que está causando el problema.
Si el script muerto estaba en medio de una transacción, el siguiente script que obtiene esa conexión también obtiene el estado de la transacción. Es muy posible (dependiendo del diseño de su aplicación) que el próximo script no intente realmente confirmar la transacción existente, o se comprometerá cuando no debería hacerlo, o retroceder cuando no debería.
Esta es solo la punta del iceberg. Todo se puede mitigar hasta cierto punto siempre tratando de limpiar después de una conexión sucia en cada solicitud de script, pero eso puede ser un problema dependiendo de la base de datos. A menos que haya identificado la creación de conexiones de bases de datos como la única cosa que es un cuello de botella en el script (esto significa que has hecho de perfiles de código usando Xdebug y / o xhprof ), debería no tener en cuenta las conexiones persistentes como una solución a nada.
Además, la mayoría de las bases de datos modernas (incluyendo PostgreSQL) tienen sus propias formas preferidas de realizar agrupaciones de conexiones que no tienen los inconvenientes inmediatos que tienen las conexiones persistentes basadas en PHP.
Para aclarar un punto, utilizamos conexiones persistentes en mi lugar de trabajo, pero no por elección. Nos encontramos con un comportamiento de conexión extraño , donde la conexión inicial de nuestro servidor de aplicaciones a nuestro servidor de base de datos tardaba exactamente tres segundos, cuando debería haber tomado una fracción de fracción de segundo. Creemos que es un error del kernel. Dejamos de tratar de solucionarlo porque sucedió al azar y no se podía reproducir a pedido, y nuestra TI tercerizada no tenía la capacidad concreta de rastrearlo.
En cualquier caso, cuando la gente del almacén procesa unos cientos de piezas entrantes, y cada parte tarda tres segundos y medio en lugar de medio segundo, tuvimos que tomar medidas antes de que nos secuestraran a todos y nos hicieran ayudarlos. Entonces, encendimos algunos bits en nuestra monstruosidad ERP / CRM / CMS local y experimentamos todos los horrores de las conexiones persistentes de primera mano. Nos llevó semanas rastrear todos los pequeños problemas sutiles y el comportamiento extraño que sucedió aparentemente al azar. Resultó que esos errores fatales de una vez a la semana que nuestros usuarios exprimían diligentemente de nuestra aplicación estaban dejando mesas bloqueadas, transacciones abandonadas y otros desafortunados estados inestables.
Esta historia de sollozo tiene un punto: rompió cosas que nunca esperábamos romper, todo en nombre del rendimiento. La compensación no valió la pena, y estamos esperando ansiosamente el día en que podamos volver a las conexiones normales sin disturbios por parte de nuestros usuarios.
fuente
SELECT orders.* FROM orders LEFT JOIN items USING(item_id)
register_shutdown_function()
. Si el proceso muere, la conexión también muere. Si no lo hace, la conexión se restablece a su estado limpio (por ejemplo, las transacciones abiertas se revierten). Si esto falla, la conexión se cierra y la próxima solicitud abrirá una nueva para el mismo proceso. No hay necesidad de demonizar las conexiones persistentes.mysqli_change_user
todavía es probablemente la mejor solución para las personas que tienen que hacer conexiones persistentes en una aplicación no diseñada para tratar problemas de estado.En respuesta al problema de Charles anterior,
De: http://www.php.net/manual/en/mysqli.quickstart.connections.php -
Una queja común sobre las conexiones persistentes es que su estado no se restablece antes de volver a usarlo. Por ejemplo, las transacciones abiertas y sin terminar no se revierten automáticamente. Pero también, los cambios de autorización que ocurrieron en el tiempo entre poner la conexión en el grupo y reutilizarla no se reflejan. Esto puede verse como un efecto secundario no deseado. Por el contrario, el nombre persistente puede entenderse como una promesa de que el estado persiste.
La extensión mysqli admite ambas interpretaciones de una conexión persistente: estado persistente y restablecimiento de estado antes de reutilizar. El valor predeterminado es restablecer. Antes de reutilizar una conexión persistente, la extensión mysqli llama implícitamente
mysqli_change_user()
para restablecer el estado. La conexión persistente le parece al usuario como si acabara de abrirse. No se ven artefactos de usos anteriores.La
mysqli_change_user()
función es una operación costosa. Para un mejor rendimiento, los usuarios pueden querer recompilar la extensión con el indicador de compilaciónMYSQLI_NO_CHANGE_USER_ON_PCONNECT
establecido.Se deja al usuario elegir entre un comportamiento seguro y el mejor rendimiento. Ambos son objetivos de optimización válidos. Para facilitar su uso, el comportamiento seguro se ha convertido en el predeterminado a expensas del máximo rendimiento.
fuente
Las conexiones persistentes son una buena idea solo cuando se tarda (relativamente) mucho tiempo en conectarse a su base de datos. Hoy en día ese casi nunca es el caso. El mayor inconveniente de las conexiones persistentes es que limita la cantidad de usuarios que puede tener navegando por su sitio: si MySQL está configurado para permitir solo 10 conexiones simultáneas a la vez, cuando una undécima persona intente navegar por su sitio, no funcionará para ellos. .
PDO no gestiona la persistencia. El controlador MySQL lo hace. Reutiliza las conexiones cuando a) están disponibles y el host / usuario / contraseña / base de datos coinciden. Si hay algún cambio, no reutilizará una conexión. El mejor efecto neto es que estas conexiones que tiene se iniciarán y detendrán tan a menudo porque tiene diferentes usuarios en el sitio y hacerlos persistentes no sirve de nada.
La clave para entender sobre las conexiones persistentes es que NO debe usarlas en la mayoría de las aplicaciones web. Suenan atractivos pero son peligrosos y prácticamente inútiles.
Estoy seguro de que hay otros hilos en esto, pero una conexión persistente es peligrosa porque persiste entre las solicitudes. Si, por ejemplo, bloquea una tabla durante una solicitud y luego no se desbloquea, esa tabla permanecerá bloqueada indefinidamente. Las conexiones persistentes también son prácticamente inútiles para el 99% de sus aplicaciones porque no tiene forma de saber si se usará la misma conexión entre diferentes solicitudes. Cada hilo web tendrá su propio conjunto de conexiones persistentes y no tiene forma de controlar qué hilo manejará qué solicitudes.
La biblioteca de MySQL procesal de PHP tiene una característica por la cual las llamadas posteriores a mysql_connect devolverán el mismo enlace, en lugar de abrir una conexión diferente (como cabría esperar). Esto no tiene nada que ver con conexiones persistentes y es específico de la biblioteca mysql. PDO no exhibe tal comportamiento
Enlace de recursos: enlace
En general, podría usar esto como un "conjunto de reglas" aproximado ::
SÍ , use conexiones persistentes, si:
La base de datos se ejecuta en otro servidor al que accede a través de la red
Una (una) aplicación accede a la base de datos muy a menudo
NO , no use conexiones persistentes, si:
Su aplicación solo necesita acceder a la base de datos 100 veces por hora.
Tienes muchos, muchos servidores web accediendo a un servidor de base de datos
El uso de conexiones persistentes es considerablemente más rápido, especialmente si está accediendo a la base de datos a través de una red. No hace mucha diferencia si la base de datos se ejecuta en la misma máquina, pero sigue siendo un poco más rápida. Sin embargo, como su nombre lo indica, la conexión es persistente, es decir, permanece abierta, incluso si no se usa.
El problema con eso es que, en la "configuración predeterminada", MySQL solo permite 1000 "canales abiertos" paralelos. Después de eso, se rechazan las nuevas conexiones (puede modificar esta configuración). Entonces, si tiene, digamos, 20 servidores web con cada 100 clientes en ellos, y cada uno de ellos tiene solo un acceso a la página por hora, las matemáticas simples le mostrarán que necesitará 2000 conexiones paralelas a la base de datos. Eso no funcionará.
Ergo: Úselo solo para aplicaciones con muchas solicitudes.
fuente
En mis pruebas, tuve un tiempo de conexión de más de un segundo con mi host local, por lo tanto, suponiendo que debería usar una conexión persistente. Otras pruebas mostraron que era un problema con 'localhost':
Resultados de la prueba en segundos (medidos por microtiempo php):
Curiosamente: el siguiente código es tan rápido como usar 127.0.0.1:
fuente
localhost
usa conexión de socket, la conexión de socket es famosa por ser mala en una gran cantidad de conexionesLas conexiones persistentes deberían aumentar considerablemente el rendimiento. No estoy de acuerdo con la afirmación de que debe "evitar" la persistencia.
Parece que las quejas anteriores son impulsadas por alguien que usa tablas MyIASM y piratea sus propias versiones de transacciones agarrando los bloqueos de la mesa ... ¡Bueno, por supuesto que vas a llegar a un punto muerto! Use beginTransaction () de PDO y mueva sus tablas a InnoDB ..
fuente
Me parece que tener una conexión persistente consumiría más recursos del sistema. Tal vez una cantidad trivial, pero aún así ...
fuente
La explicación para usar conexiones persistentes es obviamente reducir la cantidad de conexiones que son bastante costosas, a pesar del hecho de que son considerablemente más rápidas con MySQL en comparación con otras bases de datos.
El primer problema con conexiones persistentes ...
Si está creando miles de conexiones por segundo, normalmente no se asegura de que permanezca abierto durante mucho tiempo, pero el Sistema Operativo sí. Basado en el protocolo TCP / IP Los puertos no pueden reciclarse instantáneamente y también tienen que invertir un tiempo en la etapa "FIN" esperando antes de que puedan reciclarse.
El segundo problema ... usar muchas conexiones de servidor MySQL.
Muchas personas simplemente no se dan cuenta de que es capaz de aumentar la variable * max_ connections * y obtener más de 100 conexiones simultáneas con MySQL, otras fueron superadas por problemas anteriores de Linux de la incapacidad de transmitir más de 1024 conexiones con MySQL.
Permite hablar ahora sobre por qué las conexiones persistentes se deshabilitaron en la extensión mysqli. A pesar del hecho de que puede usar mal las conexiones persistentes y obtener un rendimiento deficiente, esa no fue la razón principal. La razón real es que puede tener muchos más problemas con él.
Las conexiones persistentes se pusieron en PHP en ocasiones de MySQL 3.22 / 3.23 cuando MySQL no era tan difícil, lo que significa que puede reciclar conexiones fácilmente sin problemas. En versiones posteriores, sin embargo, surgieron muchos problemas: si recicla la conexión que tiene transacciones no confirmadas, se mete en problemas. Si recicla conexiones con configuraciones de juegos de caracteres personalizados, corre peligro nuevamente, así como también sobre las variables posiblemente transformadas por sesión.
Un problema con el uso de conexiones persistentes es que realmente no escala tan bien. Para aquellos que tienen 5000 personas conectadas, necesitará 5000 conexiones persistentes. Para evitar el requisito de persistencia, es posible que tenga la capacidad de atender a 10000 personas con una cantidad similar de conexiones porque están en condiciones de compartir conexiones individuales cuando no están con ellas.
fuente
Me preguntaba si una solución parcial sería tener un grupo de conexiones de uso único. Podría dedicar tiempo a crear un grupo de conexiones cuando el sistema tenga poco uso, hasta un límite, distribuirlos y eliminarlos cuando se hayan completado o se haya agotado el tiempo de espera. En segundo plano, está creando nuevas conexiones a medida que se toman. En el peor de los casos, esto debería ser tan lento como crear la conexión sin el grupo, suponiendo que establecer el enlace es el factor limitante.
fuente