Bonjour à tous,
J’ai aidé à plusieurs reprises quelques jeedomiens à régler des pbs de lenteurs sur leur Jeedom, essentiellement liés à une mauvaise gestion des archives.
En effet, une mauvaise gestion des archives peut aboutir à des écritures disque nombreuses → augmentation de la charge du système lorsqu’on sait que les écritures disques sont souvent le maillon faible de nos systèmes, et accessoirement à une explosion de la taille des backups.
un rappel sur les paramètres en jeu :
Prenons un équipement qui génère 1 valeur historisée toutes les 1 minutes, soit 60 par heure, 1440 / jour
Sans paramétrage spécifique, on obtient 525600 valeurs archivées /an
Avec un mode de lissage « moyenne » et une durée de paquets de 1h. Ca veux dire qu’au moment de l’archivage, Jeedom va prendre un paquet de données de 1h, soit un jeu de 60 données, faire la moyenne et archiver cette moyenne, donc on n’archives qu’une valeur au lieu de 60, et donc 24 valeurs dans la journée et 8640 valeurs sur 1an, ce qui n’est rien comparé aux 525600 valeurs archivées sans ce lissage.
Multiplié ceci par le nb de vos commandes historisées, vous comprendrez l’impact d’une mauvaise gestion
Bref, plutôt que de réduire la durée d’archivage (c’est dommage), on joue plutot sur le mode de lissage pour diminuer le volume de données « archivées », et là, on peut sans risque archiver des années …
Autre élément primordial … ON HISTORISE QUE CE QUI EST NECESSAIRE.
Les paramètres disponibles
- Au niveau général dans réglages >> système >> configuration >> équipements
- Délai avant archivage (en heures) : Indique le délai avant que Jeedom n’archive une donnée (24h par défaut). C’est-à-dire que les données historisées doivent avoir plus de 24h pour être archivées (pour rappel, l’archivage va soit moyenner, soit prendre le maximum ou le minimum de la donnée sur une période qui correspond à la taille des paquets).
- Archiver par paquet de (en heures) : Ce paramètre donne justement la taille des paquets (1h par défaut). Cela signifie par exemple que Jeedom va prendre des périodes de 1h, moyenner et stocker la nouvelle valeur calculée en supprimant les valeurs moyennées.
- Au niveau de la commande info d’un équipement
- Mode de lissage : moyenne, minimum, maximum ou aucun, fourmule utilisée pour traiter les « paquets » de données (cf « archiver par paquet de »)
- Purger historique : délai de rétention des archives
Voilà, une fois le décor planté, reste à analyser notre existant … Rien de plus simple, vous trouverez un bloc code ci-après qui vous analysera les tables les plus grosses de votre Jeedom et pour les tables historyArch et history vous fera une analyse éventuelle.
Evolution du 27/03/23 : rajout d’un check des tables historisées qui génèrent des valeurs alphanumériques, beaucoup plus gourmandes en stockage que des données numériques
Evolution du 31/10/24 : rappel des paramètres et meilleur formatage des résultats (merci @Noyax37)
Quelques paramétrages au tout début pour définir les seuils d’alertes qui vous conviennent.
… Et vous decouvrirez l’ampleur du pb chez vous
!! LE CODE N’EXECUTE AUCUNE ACTION EN BASE, IL LISTE JUSTE LES PBS !!
$version = '31/10/2024 07:00' ;
$scenario->setLog('┌──────────── Logs bloc code - version du '.$version);
$scenario->setLog('| ');
$seuilalert24h = 50 ; // Seuil d'alerte pour le nb de ligne générées /24h pour une commande : 50 par defaut
$seuilArch = 50000 ; // Seuil d'alerte pour le nb de ligne archivées pour une commande : 50000 par defaut
$topXCmd = 10 ; // Recupere seulement les X commandes les plus volumineuses : 10 par defaut
$seuilTailleTable = 200 ; // Seuil alerte en MB pour la taille d'une table : 200 MB par defaut
$seuilNbLigneTable = 2000000 ; // Seuil alerte pour le nb de lignes d'une table : 2 000 000 par defaut
$scenario->setLog('| -------- PARAMETRES');
$scenario->setLog('| ');
$scenario->setLog('| Seuil alerte 24h : '.$seuilalert24h);
$scenario->setLog('| Seuil nb lignes archivées : '.number_format($seuilArch,0,',',' '));
$scenario->setLog('| Seuil taille table : '.$seuilTailleTable.' MB');
$scenario->setLog('| Seuil nb lignes table : '.number_format($seuilNbLigneTable,0,',',' '));
$scenario->setLog('| Nb de commandes récupérées : '.$topXCmd);
$scenario->setLog('| ');
// ANALYSE DU CRON D'ARCHIVAGE :
$archCron = cron::byClassAndFunction('history','archive') ;
$scenario->setLog('| -------- TACHE D\'ARCHIVAGE');
$scenario->setLog('| ');
$scenario->setLog('| Actif : '.$archCron->getEnable());
if ( !$archCron->getEnable() ) $scenario->setLog('| /!\ Tache d\'archivage inactive, pensez à l\'activer') ;
$scenario->setLog('| Statut : '.$archCron->getState());
if ( $archCron->getState() == 'error' ) $scenario->setLog('| /!\ Tache d\'archivage en erreur') ;
$scenario->setLog('| Last run : '.$archCron->getLastRun());
$scenario->setLog('| ');
// RESUME
$sql_resume = "SELECT table_name AS `Table`, round(((data_length + index_length) / 1024 / 1024)) as `MB`,table_rows as `Ligne` FROM information_schema.TABLES WHERE table_schema='jeedom' ORDER BY MB DESC LIMIT 5" ;
$results_resume = DB::Prepare($sql_resume, NULL, DB::FETCH_TYPE_ALL);
$scenario->setLog('| -------- RESUME');
$scenario->setLog('| ');
foreach ($results_resume as $result_resume) {
$table = $result_resume['Table'];
$taille = $result_resume['MB'];
$nblign = $result_resume['Ligne'];
$scenario->setLog('| Table '.$table.' : Taille -> '.$taille.'MB , nb lignes -> '.number_format($nblign,0,',',' '));
if ( $taille >= $seuilTailleTable || $nblign >= $seuilNbLigneTable ) $scenario->setLog('| /!\ Table Anormalement grosse, taille superieure au seuil ('.$taille.'MB)') ;
if ( $nblign >= $seuilNbLigneTable ) $scenario->setLog('| /!\ Table Anormalement grosse, Nb de lignes superieur au seuil ('.number_format($nblign,0,',',' ').' lignes)') ;
}
// ANALYSE DES EQUIPEMENT
$scenario->setLog('| ');
$scenario->setLog('| -------- COMMANDES AVEC DONNEES VOLUMINEUSES');
$scenario->setLog('| ');
$sql = 'SELECT arch.cmd_id id, count(arch.value) as countarch FROM historyArch arch GROUP BY arch.cmd_id ORDER BY countarch DESC LIMIT '.$topXCmd;
$results = DB::Prepare($sql, NULL, DB::FETCH_TYPE_ALL);
foreach ($results as $result) {
$id = $result['id'];
$nb_arch = $result['countarch'];
$sql_cmddesc = 'SELECT cmd.id cmd_id, cmd.name cmd, eqLogic.name equipement,object.name objectname, cmd.eqType plugin, count(*) as counthist FROM cmd LEFT JOIN eqLogic ON cmd.eqLogic_id = eqLogic.id LEFT JOIN object ON eqLogic.object_id = object.id LEFT JOIN history ON cmd.id = history.cmd_id WHERE cmd.id = '.$id.' GROUP BY history.cmd_id ';
$results_cmd = DB::Prepare($sql_cmddesc, NULL, DB::FETCH_TYPE_ALL);
// recherche de la premiere date d'historique
$sql_firstHist = 'SELECT datetime FROM historyArch WHERE cmd_id = '.$id.' ORDER BY datetime ASC LIMIT 1' ;
$results_dateHist = DB::Prepare($sql_firstHist, NULL, DB::FETCH_TYPE_ALL);
foreach ($results_dateHist as $result_dateHist) {
$now_date = new DateTime("now");
$diff = time() - strtotime($result_dateHist['datetime']);
$diff_in_day = floor($diff / 86400);
$nb_valeurParJour = round($nb_arch / $diff_in_day);
}
foreach ($results_cmd as $result_cmd) {
$object = $result_cmd['objectname'] ;
$equipement = $result_cmd['equipement'] ;
$cmd = $result_cmd['cmd'] ;
$plugin = $result_cmd['plugin'] ;
$nb_hist = $result_cmd['counthist'] ;
if (date('H') <= 5 ) $timestamp_archivage = mktime(5, 0, 0, date("m") , date("d")-1, date("Y"));
else $timestamp_archivage = mktime(5, 0, 0, date("m") , date("d"), date("Y"));
// recup de la config de la commande
$conf_histo = cmd::byId($id)->getIsHistorized() ;
$conf_histoMode = cmd::byId($id)->getConfiguration('historizeMode') ;
if ( $conf_histoMode == '' || $conf_histoMode == 'none' ) $conf_histoMode = 'aucun' ;
$conf_histopurge = cmd::byId($id)->getConfiguration('historyPurge') ;
if ( $conf_histopurge == '' || $conf_histopurge == 'none' ) $conf_histopurge = 'aucun' ;
$nb_hist24h = round($nb_hist * 86400 / ( time() - $timestamp_archivage)) ;
$scenario->setLog('| '.$plugin.' -> #['. $object .']['.$equipement.']['.$cmd.']# (id : '.$id.')');
if ( $nb_hist24h >= $seuilalert24h && $conf_histoMode == 'aucun' && $conf_histopurge == 'aucun' ) $scenario->setLog('| /!\ PB DE PARAMETRAGE, nb de valeur par 24h important ('. number_format($nb_hist24h,0,',',' ').') et aucun lissage ni aucune purge paramétrés');
if ( $nb_arch >= $seuilArch ) $scenario->setLog('| /!\ PB DE PARAMETRAGE, nb de valeur archivéess trop importantes ('. number_format($nb_arch,0,',',' ').'), superieur à '.number_format($seuilArch,0,',',' '));
$scenario->setLog('| Configuration : historisé -> '.$conf_histo.' , lissage -> '. $conf_histoMode . ' , purge -> '. $conf_histopurge ) ;
$scenario->setLog('| Historique : '.$nb_hist.' valeurs (estimation sur 24h : '.$nb_hist24h.')' );
$scenario->setLog('| Archives : '.$nb_arch.' valeurs depuis '.$diff_in_day.' jours ('.$nb_valeurParJour.' valeurs par jour en moyenne)');
$scenario->setLog('|');
}
}
// ANALYSE DES EQUIPEMENT
$scenario->setLog('| -------- COMMANDES AVEC DONNEES ALPHANUMERIQUES');
$scenario->setLog('| ');
$sql = "SELECT cmd_id id, sum(LENGTH(value)) countarch FROM historyArch WHERE value REGEXP '[a-z;A-Z]' GROUP BY cmd_id ORDER BY countarch DESC LIMIT ".$topXCmd;
$results = DB::Prepare($sql, NULL, DB::FETCH_TYPE_ALL);
foreach ($results as $result) {
$id = $result['id'];
$nb_arch = $result['countarch'];
$sql_cmddesc = 'SELECT cmd.id cmd_id, cmd.name cmd, eqLogic.name equipement,object.name objectname, cmd.eqType plugin, sum(LENGTH(history.value)) as counthist FROM cmd LEFT JOIN eqLogic ON cmd.eqLogic_id = eqLogic.id LEFT JOIN object ON eqLogic.object_id = object.id LEFT JOIN history ON cmd.id = history.cmd_id WHERE cmd.id = '.$id.' GROUP BY history.cmd_id ';
$results_cmd = DB::Prepare($sql_cmddesc, NULL, DB::FETCH_TYPE_ALL);
// recherche de la premiere date d'historique
$sql_firstHist = 'SELECT datetime FROM historyArch WHERE cmd_id = '.$id.' ORDER BY datetime ASC LIMIT 1' ;
$results_dateHist = DB::Prepare($sql_firstHist, NULL, DB::FETCH_TYPE_ALL);
foreach ($results_dateHist as $result_dateHist) {
$now_date = new DateTime("now");
$diff = time() - strtotime($result_dateHist['datetime']);
$diff_in_day = floor($diff / 86400);
$nb_valeurParJour = round($nb_arch / $diff_in_day);
}
foreach ($results_cmd as $result_cmd) {
$object = $result_cmd['objectname'] ;
$equipement = $result_cmd['equipement'] ;
$cmd = $result_cmd['cmd'] ;
$plugin = $result_cmd['plugin'] ;
$nb_hist = $result_cmd['counthist'] ;
if ( $nb_hist == '' ) $nb_hist = 0 ;
if (date('H') <= 5 ) $timestamp_archivage = mktime(5, 0, 0, date("m") , date("d")-1, date("Y"));
else $timestamp_archivage = mktime(5, 0, 0, date("m") , date("d"), date("Y"));
// recup de la config de la commande
$conf_histo = cmd::byId($id)->getIsHistorized() ;
$conf_histoMode = cmd::byId($id)->getConfiguration('historizeMode') ;
if ( $conf_histoMode == '' || $conf_histoMode == 'none' ) $conf_histoMode = 'aucun' ;
$conf_histopurge = cmd::byId($id)->getConfiguration('historyPurge') ;
if ( $conf_histopurge == '' || $conf_histopurge == 'none' ) $conf_histopurge = 'aucun' ;
$nb_hist24h = round($nb_hist * 86400 / ( time() - $timestamp_archivage)) ;
$scenario->setLog('| '.$plugin.' -> #['. $object .']['.$equipement.']['.$cmd.']# (id : '.$id.')');
if ( $nb_hist24h >= $seuilalert24h && $conf_histoMode == 'aucun' && $conf_histopurge == 'aucun' ) $scenario->setLog('| /!\ PB DE PARAMETRAGE, nb de valeur par 24h important ('. number_format($nb_hist24h,0,',',' ').') et aucun lissage ni aucune purge paramétrés');
if ( $nb_arch >= $seuilArch ) $scenario->setLog('| /!\ PB DE PARAMETRAGE, nb de valeur archivéess trop importantes ('. number_format($nb_arch,0,',',' ').'), superieur à '.$seuilArch);
$scenario->setLog('| Configuration : historisé -> '.$conf_histo.' , lissage -> '. $conf_histoMode . ' , purge -> '. $conf_histopurge ) ;
$scenario->setLog('| Historique : '.$nb_hist.' caractères (estimation sur 24h : '.$nb_hist24h.')' );
$scenario->setLog('| Archives : '.$nb_arch.' caractères depuis '.$diff_in_day.' jours ('.$nb_valeurParJour.' caractères par jour en moyenne)');
$scenario->setLog('|');
}
}
$scenario->setLog('└───────────────────────────');
Pour voir le résultat, on lance le bloc code via un scenario et on vérifie les logs du scenario, c’est on ne peut plus simple, avec un retour de ce type :
Une section TACHE D’ARCHIVAGE
[2023-05-04 23:16:00][SCENARIO] | -------- TACHE D'ARCHIVAGE
[2023-05-04 23:16:00][SCENARIO] |
[2023-05-04 23:16:00][SCENARIO] | Actif : 1
[2023-05-04 23:16:00][SCENARIO] | Statut : stop
[2023-05-04 23:16:00][SCENARIO] | Last run : 2023-05-04 05:00:05
Une section RESUME avec les 5 tables les plus grosses
[2023-03-26 10:41:39][SCENARIO] ┌──────────── Logs bloc code - version du 25/03/2023 19:00
[2023-03-26 10:41:39][SCENARIO] |
[2023-03-26 10:41:39][SCENARIO] | -------- RESUME
[2023-03-26 10:41:39][SCENARIO] |
[2023-03-26 10:41:39][SCENARIO] | Table historyArch : Taille -> 82MB , nb lignes -> 1266492
[2023-03-26 10:41:39][SCENARIO] | /!\ Table Anormalement grosse, taille superieure au seuil (82MB)
[2023-03-26 10:41:39][SCENARIO] | /!\ Table Anormalement grosse, Nb de lignes superieur au seuil (1266492 lignes)
[2023-03-26 10:41:39][SCENARIO] | Table conso_teleinfo : Taille -> 54MB , nb lignes -> 371482
[2023-03-26 10:41:39][SCENARIO] | /!\ Table Anormalement grosse, taille superieure au seuil (54MB)
[2023-03-26 10:41:39][SCENARIO] | Table history : Taille -> 5MB , nb lignes -> 23905
[2023-03-26 10:41:39][SCENARIO] | Table cmd : Taille -> 2MB , nb lignes -> 3709
[2023-03-26 10:41:39][SCENARIO] | Table config : Taille -> 2MB , nb lignes -> 1683
[2023-03-26 10:41:39][SCENARIO] |
[2023-03-26 10:41:39][SCENARIO] | -------- FIN RESUME
Une section EQUIPEMENTS avec les équipements (nb paramétrable) qui ont le plus de lignes dans les archives, et les alertes éventuelles
[2023-03-26 10:41:39][SCENARIO] | -------- EQUIPEMENTS
[2023-03-26 10:41:39][SCENARIO] |
[2023-03-26 10:41:39][SCENARIO] | teleinfo -> #[Electricité][021775837695][BBRHCJB]# (id : 39862)
[2023-03-26 10:41:39][SCENARIO] | /!\ PB DE PARAMETRAGE, nb de valeur par 24h important (3886) et aucun lissage ni aucune purge paramétrés
[2023-03-26 10:41:39][SCENARIO] | Configuration : historisé -> 1 , lissage -> aucun , purge -> aucun
[2023-03-26 10:41:39][SCENARIO] | Historique : 922 valeurs (estimation sur 24h : 3886)
[2023-03-26 10:41:39][SCENARIO] | Archives : 28834 valeurs depuis 10 jours (2883 valeurs par jour en moyenne)
[2023-03-26 10:41:39][SCENARIO] |
[2023-03-26 10:41:39][SCENARIO] | teleinfo -> #[Electricité][021775837695][BBRHPJB]# (id : 39863)
[2023-03-26 10:41:39][SCENARIO] | /!\ PB DE PARAMETRAGE, nb de valeur par 24h important (3886) et aucun lissage ni aucune purge paramétrés
[2023-03-26 10:41:39][SCENARIO] | Configuration : historisé -> 1 , lissage -> aucun , purge -> aucun
[2023-03-26 10:41:39][SCENARIO] | Historique : 922 valeurs (estimation sur 24h : 3886)
[2023-03-26 10:41:39][SCENARIO] | Archives : 28834 valeurs depuis 10 jours (2883 valeurs par jour en moyenne)
[2023-03-26 10:41:39][SCENARIO] |
[2023-03-26 10:41:39][SCENARIO] | teleinfo -> #[Electricité][021775837695][BBRHCJW]# (id : 39864)
[2023-03-26 10:41:39][SCENARIO] | /!\ PB DE PARAMETRAGE, nb de valeur par 24h important (3886) et aucun lissage ni aucune purge paramétrés
[2023-03-26 10:41:39][SCENARIO] | Configuration : historisé -> 1 , lissage -> aucun , purge -> aucun
[2023-03-26 10:41:39][SCENARIO] | Historique : 922 valeurs (estimation sur 24h : 3886)
[2023-03-26 10:41:39][SCENARIO] | Archives : 28834 valeurs depuis 10 jours (2883 valeurs par jour en moyenne)
[2023-03-26 10:41:39][SCENARIO] |
[2023-03-26 10:41:39][SCENARIO] | teleinfo -> #[Electricité][021775837695][BBRHPJW]# (id : 39865)
[2023-03-26 10:41:39][SCENARIO] | /!\ PB DE PARAMETRAGE, nb de valeur par 24h important (3886) et aucun lissage ni aucune purge paramétrés
[2023-03-26 10:41:39][SCENARIO] | Configuration : historisé -> 1 , lissage -> aucun , purge -> aucun
[2023-03-26 10:41:39][SCENARIO] | Historique : 922 valeurs (estimation sur 24h : 3886)
[2023-03-26 10:41:39][SCENARIO] | Archives : 28834 valeurs depuis 10 jours (2883 valeurs par jour en moyenne)
[2023-03-26 10:41:39][SCENARIO] |
[2023-03-26 10:41:39][SCENARIO] | teleinfo -> #[Electricité][021775837695][BBRHCJR]# (id : 39866)
[2023-03-26 10:41:39][SCENARIO] | /!\ PB DE PARAMETRAGE, nb de valeur par 24h important (3886) et aucun lissage ni aucune purge paramétrés
[2023-03-26 10:41:39][SCENARIO] | Configuration : historisé -> 1 , lissage -> aucun , purge -> aucun
[2023-03-26 10:41:39][SCENARIO] | Historique : 922 valeurs (estimation sur 24h : 3886)
[2023-03-26 10:41:39][SCENARIO] | Archives : 28834 valeurs depuis 10 jours (2883 valeurs par jour en moyenne)
Pour corriger ceci, rien de plus facile. il faut aller soit sur la page de la commande,
soit dans analyse >> historique pour corriger en masse
… ET ATTENDRE L’ARCHIVAGE à 5h du matin ou le lancer manuellement
SI vous avez supprimé des commandes, n’hésitez pas aussi à lancer un « Nettoyage de la base de données » dans les outils _OS/DB
Bon courage à tous, et j’espere que ce petit post vous sera utile
Norbert