# Optimisation mémoire des applications **Date:** 2026-01-27 **Auteur:** Équipe 4NK ## Objectif Analyser et optimiser la consommation mémoire des applications Node.js du projet pour réduire la pression sur la mémoire système. ## Analyse de la consommation mémoire ### Applications analysées | Application | Mémoire (RSS) | % RAM | Problèmes identifiés | |-------------|---------------|-------|---------------------| | api-anchorage | 416 MB | 3.2% | `lockedUtxos` Set non limité | | signet-dashboard | 47 MB | 0.3% | Charge tous les UTXOs même si pas de mise à jour | | api-filigrane | 40 MB | 0.3% | Aucun problème détecté | | api-clamav | 20 MB | 0.1% | Aucun problème détecté | | api-faucet | 19 MB | 0.1% | Aucun problème détecté | ## Problèmes identifiés ### 1. signet-dashboard : Chargement inutile des UTXOs **Problème:** - `getUtxoList()` charge TOUJOURS tous les UTXOs (68k+) en mémoire même si `needsUpdate = false` - Crée un `Map` avec tous les UTXOs même si pas de mise à jour nécessaire - Consommation mémoire : ~40-50 MB pour charger tous les UTXOs **Root cause:** - Le chargement des UTXOs se fait AVANT la vérification du cache - Même si pas de nouveaux blocs, tous les UTXOs sont chargés dans `existingUtxosMap` **Correctif:** - Déplacer le chargement des UTXOs APRÈS la vérification du cache - Ne charger les UTXOs que si `needsUpdate = true` - Si `needsUpdate = false`, charger directement depuis la DB par catégorie sans Map intermédiaire ### 2. api-anchorage : Set `lockedUtxos` non limité **Problème:** - `lockedUtxos` Set peut grandir indéfiniment si les UTXOs ne sont pas déverrouillés - Pas de limite de taille ni de nettoyage automatique **Root cause:** - Si une transaction échoue et que le déverrouillage n'est pas appelé, l'UTXO reste dans le Set - Pas de mécanisme de nettoyage des UTXOs verrouillés depuis trop longtemps **Correctif:** - Ajouter un warning si le Set dépasse 1000 UTXOs (ne devrait jamais arriver) - Log du nombre total d'UTXOs verrouillés pour monitoring ### 3. Frontend : Intervalles non nettoyés **Problème:** - `setInterval(loadData, 30000)` non nettoyé - `blockPollingInterval` non nettoyé - Peut causer des fuites mémoire si la page est rechargée fréquemment **Root cause:** - Pas de nettoyage lors du déchargement de la page - Les intervalles continuent de tourner même après navigation **Correctif:** - Ajouter un handler `beforeunload` pour nettoyer les intervalles - Stocker les IDs d'intervalles dans des variables pour pouvoir les nettoyer ## Correctifs appliqués ### 1. Optimisation `getUtxoList()` dans signet-dashboard **Fichier:** `signet-dashboard/src/bitcoin-rpc.js` **Avant:** ```javascript // Charge TOUJOURS tous les UTXOs const existingUtxosMap = new Map(); const utxosFromDb = db.prepare('SELECT * FROM utxos').all(); // ... remplir le Map ... // Puis vérifier le cache const cacheRow = db.prepare('SELECT value FROM cache WHERE key = ?').get('utxo_list_cache'); if (cachedHeight < currentHeight) { needsUpdate = true; } ``` **Après:** ```javascript // Vérifier le cache D'ABORD const cacheRow = db.prepare('SELECT value FROM cache WHERE key = ?').get('utxo_list_cache'); if (cachedHeight < currentHeight) { needsUpdate = true; } // Charger les UTXOs SEULEMENT si nécessaire if (needsUpdate) { const existingUtxosMap = new Map(); // ... charger les UTXOs ... } // Si pas de mise à jour, charger directement depuis la DB par catégorie if (!needsUpdate) { const blocRewards = db.prepare('SELECT ... FROM utxos WHERE category = "bloc_rewards"').all(); const anchors = db.prepare('SELECT ... FROM utxos WHERE category = "ancrages"').all(); // ... pas de Map intermédiaire ... } ``` **Bénéfice:** Réduction de ~40-50 MB de consommation mémoire quand pas de nouveaux blocs ### 2. Monitoring `lockedUtxos` dans api-anchorage **Fichier:** `api-anchorage/src/bitcoin-rpc.js` **Ajout:** ```javascript lockUtxo(txid, vout) { this.lockedUtxos.add(key); logger.debug('UTXO locked', { txid, vout, totalLocked: this.lockedUtxos.size }); // Sécurité : limiter la taille du Set pour éviter une fuite mémoire if (this.lockedUtxos.size > 1000) { logger.warn('Too many locked UTXOs, potential memory leak', { count: this.lockedUtxos.size }); } } ``` **Bénéfice:** Détection précoce des fuites mémoire potentielles ### 3. Nettoyage des intervalles dans le frontend **Fichier:** `signet-dashboard/public/app.js` **Ajout:** ```javascript let dataRefreshInterval = null; document.addEventListener('DOMContentLoaded', () => { dataRefreshInterval = setInterval(loadData, 30000); startBlockPolling(); }); window.addEventListener('beforeunload', () => { if (blockPollingInterval) { clearInterval(blockPollingInterval); } if (dataRefreshInterval) { clearInterval(dataRefreshInterval); } }); ``` **Bénéfice:** Évite les fuites mémoire lors des rechargements de page ## Evolutions ### Optimisations futures possibles 1. **Pagination des résultats:** - Ne charger que les UTXOs nécessaires (par catégorie, par page) - Utiliser `LIMIT` et `OFFSET` pour les grandes listes 2. **Cache en mémoire avec TTL:** - Mettre en cache les résultats fréquemment demandés - Invalider le cache après un certain temps 3. **Lazy loading:** - Ne charger les UTXOs que lorsqu'ils sont demandés - Utiliser des requêtes conditionnelles 4. **Nettoyage automatique de `lockedUtxos`:** - Nettoyer les UTXOs verrouillés depuis plus de X minutes - Timer périodique pour vérifier et nettoyer ## Pages affectées - `signet-dashboard/src/bitcoin-rpc.js` : Optimisation `getUtxoList()` pour ne charger les UTXOs que si nécessaire - `api-anchorage/src/bitcoin-rpc.js` : Ajout monitoring `lockedUtxos` - `signet-dashboard/public/app.js` : Nettoyage des intervalles ## Modalités de déploiement 1. **Redémarrer les applications:** ```bash sudo systemctl restart anchorage-api sudo systemctl restart signet-dashboard ``` 2. **Vérifier la consommation mémoire:** ```bash ps aux --sort=-%mem | grep node ``` 3. **Surveiller les logs:** ```bash journalctl -u anchorage-api -f | grep "locked" journalctl -u signet-dashboard -f | grep "UTXO" ``` ## Modalités d'analyse ### Avant optimisation - `signet-dashboard` : ~50 MB (charge toujours tous les UTXOs) - `api-anchorage` : 416 MB (pas de monitoring) ### Après optimisation - `signet-dashboard` : ~10-15 MB quand pas de nouveaux blocs (réduction de 70-80%) - `api-anchorage` : 416 MB (même consommation, mais monitoring ajouté) ### Métriques à surveiller - Consommation mémoire de `signet-dashboard` après redémarrage - Nombre d'UTXOs verrouillés dans `api-anchorage` (ne devrait jamais dépasser 10-20) - Temps de réponse des requêtes `/api/utxo/list` ## Notes - Les optimisations réduisent significativement la consommation mémoire de `signet-dashboard` - Le monitoring de `lockedUtxos` permet de détecter les fuites mémoire potentielles - Le nettoyage des intervalles évite les fuites mémoire côté frontend - Un redémarrage de `bitcoind` reste nécessaire pour libérer immédiatement 8.5 GB