Les erreurs passagères
Quelques clusters de bases de données utilisent les erreurs passagères. Une erreur passagère est une erreur temporaire qui normalement doit disparaître rapidement. Par définition, il est sécurisé pour un client d'ignorer une erreur passagère et de re-tenter l'opération en échec sur le même serveur de base de données. La nouvelle tentative n'a aucun effet secondaire. Les clients ne sont pas obligés de stopper leurs travaux ou de basculer sur un autre serveur de base de données immédiatement. Ils doivent plutôt entrer dans une boucle de tentatives pour attendre que l'erreur disparaisse avant d'abandonner le serveur de base de données au profit d'un autre. Les erreurs passagères peuvent être observées, par exemple, lors de l'utilisation d'un cluster MySQL. Mais elles ne sont pas liées à une solution de clusters spécifique.
PECL/mysqlnd_ms peut lancer une boucle de tentatives automatiquement dans le cas d'erreurs passagères. Ce mécanisme permet de rendre encore plus transparent la distribution, et ainsi, rend simple la migration d'une application fonctionnant sur un seul serveur de base de données sur un cluster de serveurs de bases de données sans avoir à changer le source de l'application.
La boucle de tentatives automatique va répéter l'opération demandée autant de fois que le nombre configuré, et effectuera une pause entre les tentatives pendant une durée configurée. Si l'erreur disparaît pendant la boucle, l'application ne la verra jamais. Sinon, l'erreur sera envoyée à l'application afin qu'elle la gère.
Dans l'exemple ci-dessous, une erreur concernant une clé dupliquée est provoquée pour que le plugin entre dans un cycle de deux nouvelles tentatives avant de passer l'erreur à l'application. Entre les deux tentatives, le plugin va attendre 100 millisecondes.
Exemple #1 Provoque une erreur passagère
mysqlnd_ms.enable=1 mysqlnd_ms.collect_statistics=1
{ "myapp": { "master": { "master_0": { "host": "localhost" } }, "slave": { "slave_0": { "host": "192.168.78.136", "port": "3306" } }, "transient_error": { "mysql_error_codes": [ 1062 ], "max_retries": 2, "usleep_retry": 100 } } }
Exemple #2 Boucle de tentative pour une erreur passagère
<?php
$mysqli = new mysqli("myapp", "username", "password", "database");
if (mysqli_connect_errno())
/* Bien évidemment, votre gestionnaire d'erreurs est bien meilleur... */
die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
!$mysqli->query("CREATE TABLE test(id INT PRIMARY KEY)") ||
!$mysqli->query("INSERT INTO test(id) VALUES (1))")) {
printf("[%d] %s\n", $mysqli->errno, $mysqli->error);
}
/* La boucle de tentatives est totalement transparente.
La vérification des statistiques est la seule façon de
voir les tentatives implicites */
$stats = mysqlnd_ms_get_stats();
printf("Tentatives sur l'erreur passagère avant de lancer l'erreur : %d\n", $stats['transient_error_retries']);
/* Provoque une erreur concernant une clé dupliquée pour voir les statistiques changer */
if (!$mysqli->query("INSERT INTO test(id) VALUES (1))")) {
printf("[%d] %s\n", $mysqli->errno, $mysqli->error);
}
$stats = mysqlnd_ms_get_stats();
printf("Tentatives sur l'erreur passagère après le lancement de l'erreur : %d\n", $stats['transient_error_retries']);
$mysqli->close();
?>
L'exemple ci-dessus va afficher quelque chose de similaire à :
Tentatives sur l'erreur passagère avant de lancer l'erreur : 0 [1062] Duplicate entry '1' for key 'PRIMARY' Tentatives sur l'erreur passagère après le lancement de l'erreur : 2
En raison du fait de l'exécution transparente d'un point de vue utilisateur de la boucle de tentatives, l'exemple vérifie les statistiques fournies par le plugin pour en savoir plus.
Comme l'exemple le montre, le plugin peut considérer toutes les erreurs
comme passagères au regard de la sémantique des erreurs des serveurs
de base de données. La seule erreur que le serveur MySQL considère comme
temporaire est l'erreur code 1297
. Lorsque vous configurez
d'autres codes erreurs autre que la 1297
, assurez-vous
que votre configuration reflète la sémantique des codes erreurs de votre cluster.
Les appels mysqlnd C API suivants sont surveillés par le plugin pour vérifier les erreurs passagères : query(), change_user(), select_db(), set_charset(), set_server_option() prepare(), execute(), set_autocommit(), tx_begin(), tx_commit(), tx_rollback(), tx_commit_or_rollback(). Les appels API utilisateur ont des noms similaires.
La durée d'attente du plugin entre plusieurs tentatives dans la boucle dépend de la fonction en question. Dans une boucle de tentative pour query(), prepare() ou execute(), la durée d'attente sera max_retries * usleep_retry millisecondes.
Cependant, les fonctions qui contrôle le statut de la connexion sont dispatchées pour toutes les connexions. La configuration de la boucle de tentative est appliquée à chaque connexion sur laquelle la commande est exécutée. Aussi, une fonction peut interrompre l'exécution du programme plus longtemps qu'une fonction qui est exécutée sur un seul serveur. Par exemple, set_autocommit() est dispatché sur l'ensemble des connexions, et peut attendre (max_retries * usleep_retry) * nombre_de_connexions_ouvertes) millisecondes. Veuillez garder cela à l'esprit lorsque vous définissez une durée élevée ainsi qu'un grand nombre de tentatives. L'utilisation de la configuration par défaut (max_retries=1, usleep_retry=100 et lazy_connections=1) est vivement conseillé, car vous n'aurez jamais de délai supérieur à 1 seconde.
Document créé le 30/01/2003, dernière modification le 26/10/2018
Source du document imprimé : https://www.gaudry.be/php-rf-mysqlnd-ms.transient_errors.html
L'infobrol est un site personnel dont le contenu n'engage que moi. Le texte est mis à disposition sous licence CreativeCommons(BY-NC-SA). Plus d'info sur les conditions d'utilisation et sur l'auteur.
Références
Ces références et liens indiquent des documents consultés lors de la rédaction de cette page, ou qui peuvent apporter un complément d'information, mais les auteurs de ces sources ne peuvent être tenus responsables du contenu de cette page.
L'auteur de ce site est seul responsable de la manière dont sont présentés ici les différents concepts, et des libertés qui sont prises avec les ouvrages de référence. N'oubliez pas que vous devez croiser les informations de sources multiples afin de diminuer les risques d'erreurs.