Correction de l'erreur de dépassement de max_prepared_stmt_count dans MySQL avec une application Golang

Un projet Golang récemment déployé en environnement de production a rencontré l'erreur "Can't create more than max_prepared_stmt_count statements (current value: 16382)" après une période d'exécution, bloquant l'accès à la base de données backend. L'analyse a révélé que des statements préparés non fermés causaient le dépassement de la limite par défaut.

Diagnostic initial

L'erreur de statement dans le backend a conduit à l'identification d'un excès de statements préparés non libérés, atteignant la valeur maximale configurée.

Vérification de la base de données

Connexion à MySQL via une interface client, par exemple :

mysql -h localhost -u administrateur -p

Pour obtenir la limite actuelle des statements préparés, exécuter :

SHOW VARIABLES LIKE '%max_prepared_stmt_count%';

La sortie confirme une valeur de 16382 par défaut.

Ensuite, inspecter les compteurs globaux avec :

SHOW GLOBAL STATUS LIKE 'com_stmt%';

La différence entre Com_stmt_prepare et Com_stmt_close indique des fuites. Après un redémarrage de la base, l'écart est minimal, mais il croît avec le temps jusqu'à provoquer l'erreur lors d'opérations de préparatoin uniquement.

Examen du code source

Une révision du code Golang a montré l'absence de fermeture systématique des statements préparés. La correction consiste à appeler Close() après chaque Prepare(), comme illustré ci-dessous avec des noms de variables modifiés :

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

// Établir la connexion
connection, errConnect := sql.Open("mysql", dataSourceName+"/base?charset=utf8")
if errConnect != nil {
    return errConnect
}

// Préparer le statement
preparedStmt, errPrepare := connection.Prepare(requeteSQL)
if errPrepare != nil {
    return errPrepare
}
// Fermeture différée pour garantir la libération des ressources
defer preparedStmt.Close()

L'utilisation de defer assure la fermeture automatique en fin de fonction. Après modification, les statistiques MySQL montrent un écart nul entre les opérations de préparation et de fermeture, résolvant le problème durablement.

Solution de contournement temporaire

Dans un environnement de production où un redémarrage de la base est impossible, la limite peut être augmentée dynamiquement :

SET GLOBAL max_prepared_stmt_count=32764;

Cette mesure est palliative car la limite sera atteinte à nouveau si les fuites persistent. La valeur maximale autorisée est 1048576. Un redémarrage de la base réinitialise les compteurs et constitue une alternative rapide mais non toujours viable en production.

Il est essentiel de noter que, dans les applications Golang, tous les objets tels que *sql.DB, *sql.Rows et *sql.Stmt doivent être explicitement fermés pour éviter des problèmes de ressources ou de connexions.

Étiquettes: MySQL golang prepared statements database administration connection pooling

Publié le 17 juin à 16h12