web-dev-qa-db-fra.com

Quels sont les inconvénients de l'utilisation d'une connexion persistante dans PDO

Dans PDO, une connexion peut être établie de manière persistante à l'aide de la commande PDO::ATTR_PERSISTENT attribut. Selon le manuel php -

Les connexions persistantes ne sont pas fermées à la fin du script, mais sont mises en cache et réutilisées lorsqu'un autre script demande une connexion utilisant les mêmes informations d'identification. Le cache de connexion persistante vous permet d'éviter la surcharge d'établir une nouvelle connexion à chaque fois qu'un script doit parler à une base de données, ce qui permet une application Web plus rapide.

Le manuel recommande également de ne pas utiliser de connexion persistante lors de l'utilisation du pilote PDO ODBC), car cela pourrait entraver le processus ODBC de mise en pool des connexions.

Donc, apparemment, l'utilisation d'une connexion persistante dans PDO ne semble présenter aucun inconvénient, sauf dans le dernier cas. Cependant, j'aimerais savoir s'il existe d'autres inconvénients à utiliser ce mécanisme, c'est-à-dire une situation dans laquelle ce mécanisme entraîne une dégradation des performances ou quelque chose du genre.

171
MD Sayem Ahmed

Assurez-vous de lire cette réponse ci-dessous , qui détaille les moyens d'atténuer les problèmes décrits ici.


Les mêmes inconvénients existent en utilisant PDO et avec tout autre PHP qui fait des connexions persistantes: si votre script se termine de manière inattendue au milieu d'opérations de base de données, la prochaine requête qui obtient la connexion restante choisira La connexion est maintenue ouverte au niveau du gestionnaire de processus (Apache pour mod_php, le processus FastCGI actuel si vous utilisez FastCGI, etc.), pas au PHP level, et PHP n'indique pas au processus parent de laisser la connexion mourir lorsque le script se termine anormalement.

Si les tables verrouillées par le script mort sont verrouillées, ces tables le resteront jusqu'à la fin de la connexion ou jusqu'à ce que le prochain script obtenant la connexion déverrouille les tables.

Si le script mort était au milieu d'une transaction, cela peut bloquer une multitude de tables jusqu'à ce que le délai d'interblocage se déclenche, et même dans ce cas, le temporisateur d'interblocage peut tuer la demande la plus récente au lieu de la demande la plus ancienne à l'origine du problème.

Si le script mort était au milieu d'une transaction, le script suivant qui obtient cette connexion obtient également l'état de la transaction. Il est très possible (en fonction de la conception de votre application) que le prochain script ne tente pas réellement de valider la transaction existante, ou qu'il commette quand il ne devrait pas l'avoir ou qu'il annule alors qu'il ne l'aurait pas dû.

C'est la partie visible de l'iceberg. Tout peut être atténué dans une certaine mesure en essayant toujours de nettoyer après une connexion fictive sur chaque requête de script, mais cela peut être difficile en fonction de la base de données. Sauf si vous avez identifié la création de connexions de base de données comme étant la seule chose qui constitue un goulot d'étranglement dans votre script (cela signifie que vous avez créé le profilage de code à l'aide de xdebug et/ou - xhprof ), vous devriez pas considérer les connexions persistantes comme une solution à tout.

En outre, la plupart des bases de données modernes (y compris PostgreSQL) ont leurs propres méthodes préférées pour réaliser le regroupement de connexions qui ne présentent pas les inconvénients immédiats des connexions persistantes basées sur PHP de Vanilla.


Pour clarifier un point, nous utilisons des connexions persistantes sur mon lieu de travail, mais pas par choix. Nous rencontrions le comportement de connexion bizarre, où la connexion initiale de notre serveur d'applications à notre serveur de base de données prenait exactement trois secondes, alors qu'elle aurait dû prendre une fraction d'une fraction de seconde. Nous pensons que c'est un bug du noyau. Nous avons cessé d'essayer de le résoudre car cela se produisait de manière aléatoire et ne pouvait pas être reproduit à la demande, et notre service informatique externalisé n'avait pas la capacité concrète de le localiser.

Quoi qu'il en soit, lorsque les employés de l'entrepôt traitent quelques centaines de pièces entrantes et que chaque pièce prend trois secondes et demie au lieu d'une demi-seconde, nous avons dû prendre des mesures avant de nous avoir tous kidnappés et obligés de les aider. Nous avons donc mis un peu de valeur dans notre monstruosité ERP/CRM/CMS locale et expérimenté toutes les horreurs des connexions persistantes. Il nous a fallu semaines pour repérer tous les petits problèmes subtils et les comportements bizarres qui se sont produits apparemment au hasard. Il s’est avéré que ces erreurs fatales une fois par semaine que nos utilisateurs ont soigneusement effacées de notre application laissaient des tables verrouillées, des transactions abandonnées et d’autres États malheureux et malheureux.

Cette histoire de sanglot a un point: Elle a cassé des choses que nous ne pensions jamais briser, au nom de la performance. Le compromis n'en valait pas la peine et nous attendons avec impatience le jour où nous pourrons revenir aux connexions normales sans émeute de la part de nos utilisateurs.

274
Charles

En réponse au problème de Charles ci-dessus,

De: http://www.php.net/manual/en/mysqli.quickstart.connections.php -

Une plainte commune à propos des connexions persistantes est que leur état n'est pas réinitialisé avant leur réutilisation. Par exemple, les transactions ouvertes et non finies ne sont pas automatiquement annulées. Toutefois, les modifications d'autorisation intervenues entre le moment où la connexion a été établie et la réutilisation ne sont pas prises en compte. Cela peut être considéré comme un effet secondaire indésirable. Au contraire, le nom persistant peut être compris comme une promesse que l'état est persistant.

L'extension mysqli prend en charge les interprétations d'une connexion persistante: état persistant et réinitialisation d'état avant réutilisation. La valeur par défaut est réinitialisée. Avant qu'une connexion persistante ne soit réutilisée, l'extension mysqli appelle implicitement mysqli_change_user() pour réinitialiser l'état. La connexion persistante apparaît à l'utilisateur comme si elle venait juste d'être ouverte. Aucun artefact des utilisations précédentes n'est visible.

La fonction mysqli_change_user() est une opération coûteuse. Pour de meilleures performances, les utilisateurs peuvent souhaiter recompiler l'extension avec l'indicateur de compilation MYSQLI_NO_CHANGE_USER_ON_PCONNECT étant réglé.

Il appartient à l'utilisateur de choisir entre un comportement sûr et de meilleures performances. Les deux sont des objectifs d'optimisation valides. Pour des raisons de facilité d'utilisation, le comportement sécurisé a été défini par défaut au détriment des performances maximales.

42
Prashant

Les connexions persistantes ne sont une bonne idée que lorsque la connexion à votre base de données prend (relativement) longtemps. De nos jours ce n'est presque jamais le cas. Le plus gros inconvénient des connexions persistantes est qu’elles limitent le nombre d’utilisateurs que vous pouvez consulter sur votre site: si MySQL est configuré pour autoriser seulement 10 connexions simultanées, il ne fonctionnera pas si une onzième personne tente de naviguer sur votre site. .

PDO ne gère pas la persistance. Le pilote MySQL fait. Il réutilise les connexions lorsqu'elles sont disponibles et que l'hôte/l'utilisateur/le mot de passe/la base de données correspondent. En cas de changement, la connexion ne sera pas réutilisée. Le meilleur effet net est que ces connexions que vous avez seront démarrées et arrêtées si souvent parce que vous avez différents utilisateurs sur le site et que les rendre persistants ne fait aucun bien.

L’essentiel pour comprendre les connexions persistantes est que vous ne devez PAS les utiliser dans la plupart des applications Web. Ils semblent séduisants mais ils sont dangereux et pratiquement inutiles.

Je suis sûr qu'il existe d'autres threads à ce sujet, mais une connexion persistante est dangereuse car elle persiste entre les demandes. Si, par exemple, vous verrouillez une table lors d'une demande et ne parvenez pas à le déverrouiller, cette table reste verrouillée indéfiniment. Les connexions persistantes sont également pratiquement inutiles pour 99% de vos applications, car vous ne pouvez pas savoir si la même connexion sera utilisée entre différentes demandes. Chaque fil Web aura son propre ensemble de connexions persistantes et vous ne pouvez pas contrôler quel fil traitera quelles demandes.

La bibliothèque procédurale mysql de PHP a une fonctionnalité en vertu de laquelle les appels ultérieurs à mysql_connect renverront le même lien, plutôt que d'ouvrir une connexion différente (comme on pouvait s'y attendre). Cela n'a rien à voir avec les connexions persistantes et est spécifique à la bibliothèque mysql. PDO ne présente pas un tel comportement


Lien de ressource: lien

En général, vous pouvez utiliser cela comme un "ensemble de règles" approximatif:

[~ # ~] yes [~ # ~] , utilisez des connexions persistantes si:

  • Il n’ya que peu d’applications/d’utilisateurs accédant à la base de données, c’est-à-dire que vous ne créerez pas 200 connexions ouvertes (mais probablement inactives) car il existe 200 utilisateurs différents partagés sur le même hôte.
  • La base de données s'exécute sur un autre serveur auquel vous accédez via le réseau.

  • Une (une) application accède très souvent à la base de données

[~ # ~] no [~ # ~] , n'utilisez pas de connexions persistantes, si:

  • Votre application doit uniquement accéder à la base de données 100 fois par heure.

  • De nombreux serveurs Web accèdent à un serveur de base de données.

L'utilisation de connexions persistantes est considérablement plus rapide, en particulier si vous accédez à la base de données via un réseau. Cela ne fait pas beaucoup de différence si la base de données est exécutée sur la même machine, mais cela reste un peu plus rapide. Toutefois, comme son nom l’indique, la connexion est persistante, c’est-à-dire qu’elle reste ouverte, même si elle n’est pas utilisée.

Le problème est que, dans la "configuration par défaut", MySQL n'autorise que 1000 "canaux ouverts" parallèles. Après cela, les nouvelles connexions sont refusées (vous pouvez modifier ce paramètre). Donc, si vous avez - disons - 20 serveurs Web avec 100 clients sur chacun, et que chacun d'entre eux n'a qu'un accès d'une page par heure, un calcul simple vous montrera qu'il vous faudra 2 000 connexions parallèles à la base de données. Ça ne marchera pas.

Ergo: utilisez-le uniquement pour les applications avec beaucoup de demandes.

12
Jhonathan H.

Lors de mes tests, le temps de connexion à mon localhost était supérieur à une seconde, si bien que je devrais utiliser une connexion persistante. D'autres tests ont montré que c'était un problème avec 'localhost':

Résultats du test en secondes (mesurés en php microtime):

  • site Web hébergé: connectDB: 0.0038912296295166
  • localhost: connectDB: 1.0214691162109 (plus d'une seconde: n'utilisez pas localhost!)
  • 127.0.0.1: connectDB: 0.00097203254699707

Fait intéressant: Le code suivant est aussi rapide que d'utiliser 127.0.0.1:

$Host = gethostbyname('localhost');
// echo "<p>$Host</p>";
$db = new PDO("mysql:Host=$Host;dbname=" . DATABASE . ';charset=utf8', $username, $password,
    array(PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
12
Gunnar Bernstein

Les connexions persistantes devraient améliorer considérablement les performances. Je ne suis pas d'accord avec l'assertion que vous devriez "éviter" la persistance ..

Il semble que les plaintes ci-dessus soient motivées par une personne utilisant les tables MyIASM et piratant leurs propres versions de transactions en saisissant des verrous de table. Bien sûr, vous allez vous retrouver dans une impasse! Utilisez beginTransaction () de PDO et déplacez vos tables vers InnoDB.

6
Stephen

me semble avoir une connexion persistante consommerait plus de ressources système. Peut-être un montant trivial, mais quand même ...

2
Crayon Violent

L’explication de l’utilisation de connexions persistantes est évidemment de réduire le nombre de connexions plutôt coûteuses, alors qu’elles sont beaucoup plus rapides avec MySQL que d’autres bases de données.

Le tout premier problème avec des connexions persistantes ...

Si vous créez 1 000 connexions par seconde, vous ne vous assurez généralement pas qu'il reste ouvert très longtemps, contrairement à Système d'exploitation. Basé sur le protocole TCP/IP, les ports ne peuvent pas être recyclés instantanément et doivent également investir un certain temps dans l’étape "FIN" avant de pouvoir être recyclés.

Le 2ème problème ... utilise beaucoup de connexions au serveur MySQL.

Beaucoup de gens ne réalisent tout simplement pas que vous êtes en mesure d'augmenter la variable * max_connections * et d'obtenir plus de 100 connexions simultanées avec MySQL. D'autres ont été dépassées par des problèmes plus anciens liés à l'impossibilité de transmettre plus de 1024 connexions avec MySQL.

Permet de parler maintenant de la raison pour laquelle les connexions persistantes ont été désactivées dans l'extension mysqli. Malgré le fait que vous pouvez abuser des connexions persistantes et obtenir des performances médiocres, ce n’est pas la raison principale. La raison réelle est - vous pouvez avoir beaucoup plus de problèmes avec cela.

Des connexions persistantes ont été mises dans PHP tout au long de MySQL 3.22/3.23 lorsque MySQL n’était pas si difficile, ce qui signifie que vous pouvez facilement recycler les connexions sans aucun problème. Si vous recyclez les connexions avec des configurations de jeu de caractères personnalisées, vous êtes à nouveau en danger, ainsi que sur des variables éventuellement transformées par session.

Un problème avec l'utilisation de connexions persistantes est que cela ne s'adapte pas vraiment bien. Pour ceux qui ont 5000 personnes connectées, vous aurez besoin de 5000 connexions persistantes. Pour éviter l'exigence de persistance, vous pouvez être en mesure de servir 10 000 personnes avec le même nombre de connexions, car elles sont en mesure de partager des connexions individuelles lorsqu'elles ne sont pas avec elles.

1
Tony Stark

Je me demandais simplement si une solution partielle consisterait à créer un pool de connexions à utilisation unique. Vous pouvez passer du temps à créer un pool de connexions lorsque le système est peu utilisé, dans la limite d'une limite donnée, à les distribuer et à les tuer une fois qu'ils sont terminés ou qu'ils ont expiré. En arrière-plan, vous créez de nouvelles connexions au fur et à mesure qu'elles sont prises. Dans le pire des cas, cela devrait être aussi lent que la création de la connexion sans le pool, en supposant qu'établir la liaison est le facteur limitant?

0
James