Woodstock Backup - Optimiser la consommation mémoire de Node.js avec Rust

Posté le 10. May 2023 dans ProgrammationTags: woodstock, backup, sauvegarde, javascript, nodejs

Temps de lecture: 15 min

Introduction

Node.js est un environnement d'exécution JavaScript côté serveur qui repose sur le moteur JavaScript V8 de Google. Il est utilisé pour développer des applications serveur en back-end d'une application web, des outils en ligne de commande et des applications desktop. Cependant, la consommation de mémoire peut être un problème pour certaines applications Node.js, en particulier celles qui manipulent de grandes quantités de données ou des données volumineuses.

Dans cet article, nous allons voir comment optimiser la consommation de mémoire d'une application Node.js en le couplant avec Rust. Rust est un langage de programmation système qui offre des performances similaires à celles du C++, tout en offrant une sécurité de mémoire à la compilation. Rust peut être utilisé pour écrire des bibliothèques C/C++ natives pour Node.js.

Problématique

J'ai développé un logiciel de sauvegarde appelé Woodstock Backup, écrit en TypeScript. Lors du lancement des sauvegardes, il crée une représentation du système de fichier en mémoire et nécessite une grande quantité de mémoire. Pour illustrer cela, nous avons reproduit notre cas avec le code suivant :

const filesize = require("filesize.js");
const fs = require("fs");
// Utilisation des méthodes de sérialisation et de désérialisation du moteur V8
const { serialize, deserialize } = require("v8");

// Méthode pour générer une chaîne de caractère contenant des caractères aléatoires
function randomString(size) {
  const buffer = Buffer.alloc(size);
  for (let i = 0; i < size; i++) {
    buffer[i] = Math.floor(Math.random() * 256);
  }
  return buffer;
}

// Méthode pour générer un nombre aléatoire de la taille d'un nombre de 53 bits
function randomNumber() {
  return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
}

// Création d'un objet de test en javascript contenant que des données aléatoires
const testObject = () => ({
  path: randomString(100),
  stats: {
    ownerId: { low: randomNumber(), high: randomNumber(), unsigned: true },
    groupId: { low: randomNumber(), high: randomNumber(), unsigned: true },
    size: { low: randomNumber(), high: randomNumber(), unsigned: true },
    compressedSize: {
      low: randomNumber(),
      high: randomNumber(),
      unsigned: true,
    },
    lastRead: { low: randomNumber(), high: randomNumber(), unsigned: true },
    lastModified: { low: randomNumber(), high: randomNumber(), unsigned: true },
    created: { low: randomNumber(), high: randomNumber(), unsigned: true },
    mode: { low: randomNumber(), high: randomNumber(), unsigned: true },
    dev: { low: randomNumber(), high: randomNumber(), unsigned: true },
    rdev: { low: randomNumber(), high: randomNumber(), unsigned: true },
    ino: { low: randomNumber(), high: randomNumber(), unsigned: true },
    nlink: { low: randomNumber(), high: randomNumber(), unsigned: true },
  },
  chunks: [randomString(32), randomString(32), randomString(32)],
  sha256: randomString(32),
});

// Lancement du GC pour s'assurer que la mémoire utilisé ne contient que les objets de test
global.gc();
// On recupère la mémoire utilisé avant le test
const memoryBefore = process.memoryUsage().heapUsed;
// On recupère le temps avant le test (pour mesurer le temps de traitement)
const time = Date.now();

// Création des objets. J'ai du lancer plusieurs fois le script pour trouver une valeur qui ne causé pas de crash de 
// Node.JS pour cause de manque de mémoire
const nbObjects = 1_300_000;
const testArray = new Array(nbObjects);
for (let i = 0; i < nbObjects; i++) {
  testArray[i] = testObject();
}

// Combien de temps à pris la création des objets
console.log("Creation time: ", Date.now() - time);
// Lancement du GC pour s'assurer que nous n'avons pas d'autres reliquats
global.gc();
// Récupération de la mémoire après le test
const memoryAfter = process.memoryUsage().heapUsed;

console.log("Memory consumption: ", filesize.default(memoryAfter - memoryBefore));
console.log("Memory consumption by objects: ", filesize.default((memoryAfter - memoryBefore) / nbObjects));

// Dans la suite on va écrire un fichier contenant le contenu de la mémoire. Cela a été fait initiallement pour 
// s'assurer que le GC ne supprime pas mes objets car non utilisés.
const time2 = Date.now();

// Remove test file if exist
try {
  fs.unlinkSync("test");
} catch (e) {}

const stream = fs.createWriteStream("test");

// C'est moche, mais c'est pour tester
stream.on("close", () => {
  console.log("Write to file time: ", Date.now() - time2);
  // Size of file test on disk
  const stats = fs.statSync("test");
  console.log("Size of file on disk: ", filesize.default(stats.size));
  console.log(
    "Size of object in the file",
    filesize.default(stats.size / nbObjects)
  );
});

for (const obj of testArray) {
  stream.write(serialize(obj));
}
stream.end();

En estimant rapidement la mémoire que la taille de l'objet aurait dû prendre, je l'estime à environ 432 octets (12 nombres de 2*64 bits + 1 octet de boolean + 128 caractères pour les chunks et 100 caractères pour le nom). ...


Lire la suite ...

Woodstock Backup - Protocol et Language de sauvegarde

Posté le 7. April 2023 dans ProgrammationTags: woodstock, backup, sauvegarde, javascript, nodejs

Temps de lecture: 18 min

Woodstock Backup - Protocol et Language de sauvegarde

Note de 2023 : Ce billet a été écrit en avril 2021, il y a deux ans, mais n'a jamais été publié. Le temps passe vite.

Depuis lors, j'ai travaillé sur d'autres projets, mais aussi sur ce logiciel de sauvegarde. En progressant dans le développement du projet, j'ai pu optimiser les performances et me faire une opinion sur le choix que j'ai finalement fait, que je partagerai à la fin de l'article.

Je mettrai à jour mes conclusions en fonction de mes avancées sur le sujet.

...

Lire la suite ...

Du souhait d'achat d'un vélo ...

Posté le 27. September 2021 dans ProgrammationTags: javascript, nodejs, aws, web, velo, sms

Temps de lecture: 17 min

Que penseriez-vous si je vous racontais un peu mes vacances ? Attendez ... attendez ... ne partez pas ... l'histoire est intéressante, et surtout nous allons parler informatique.

Début Août j'ai décidé de m'acheter un nouveau vélo (un VTC à assistance électrique). Le choix du vélo importe peu, mais du fait d'une pénurie de matière première et d'une forte demande en vélo depuis le début de la crise de mes sanitaire, tous les vélos sont en rupture de stock.

J'ai fait le choix personnel de me rendre dans une enseigne connue dont le nom est aussi une discipline de l'athlétisme pour acheter ce VTC.1

Et là c'est le drame. ...


Lire la suite ...

Mise à jour du blog vers gridsome

Posté le 2. March 2021 dans LogicielsTags: dedie, javascript

Temps de lecture: 10 min

J'avais migré en Janvier 2013 mon blog vers Pelican en venant de Dotclear. Pelican est un générateur de site statique en Python. J'avais alors dû faire l'impasse sur les commentaires mais au bénéfice d'un site performant et avec une surface d'attaque plus faible.

Plus tard, en décembre 2016, j'avais changé le thème pour alexandrevicenzi/Flex. Aujoud'hui je vais vous montrer la migration de mon blog vers Gridsome.

Je reste sur un générateur de site statique car, j'aime l'idée d'un site à la fois rapide et immuable tant que je ne décide pas de modifier le contenu mon blog. Alors pourquoi changer de Pelican vers Gridsome ?

Gridsome est un générateur de site statique écrit en Javascript. Il a la particularité de pouvoir générer des pages depuis des fichiers au format Markdown mais aussi depuis des CMS Headless, ou de n'importe quelles autres API et ce grace à une API commune en GraphQL. ...


Lire la suite ...

Woodstock Backup - Utilisation de Btrfs et son remplacement

Posté le 12. January 2021 dans WoodstockTags: backup, sauvegarde, btrfs, rsync, javascript, nodejs, woodstock

Temps de lecture: 11 min

Bonjour à tous,

La version 1 de mon programme de sauvegarde Woodstock Backup utlise Btrfs et Rsync pour effectuer une sauvegarde. Je l'utilise depuis quelques mois pour sauvegarder mes differentes machines (7 machines).

Voici un premier compte-rendu de l'utilisation de la première version de cet outil dont je suis l'auteur:

  • Lors de mon utilisation la sauvegarde fonctionne très bien, et cela c'est cool :). Je suis aux alentours de 200 snapshots.
  • J'ai eu un problème d'espace disque. Lors du déplacement de plusieurs énormes fichiers sur un serveur. La taille de l'espace de stockage à augmenté énormément.

...

Lire la suite ...

Comment créer une bonne API Web - Partie 3

Posté le 29. November 2020 dans ProgrammationTags: api, graphql, rest, javascript, nodejs

Temps de lecture: 18 min

Bonjour,

Cet article fait partie d'un ensemble:

Il y a quelques années de cela, j'ai souhaité résoudre un problème que j'ai depuis longtemps avec les API REST: comment bien normaliser les tris, les projections, et les filtres. En effectuant mes recherches je suis tombé sur deux frameworks qui permettent de résoudre le problème des projections.

Qu'est qu'une API Falcor

Je ne vais parler que succinctement de Falcor. C'est un framework que je n'ai pas utilisé mais j'ai tout de même été très intéressé par ce dernier et je vais écrire quelques lignes sur ce Framework. ...


Lire la suite ...

L'Application du confinement pour se déplacer

Posté le 14. November 2020 dans ProgrammationTags: android, programmation, java, confinement

Temps de lecture: 10 min

Préambule: A cause du temps de validation du PlayStore, je publie cet article avec une semaine de retard.

Cela fait plus d'une semaine (quand j'écris ces lignes) que le re-confinement à commencé. Quand je vais courir, je dois me cantonner à 1km autour de chez moi. Mais quand je cours j'aimerais que mon téléphone intelligent me prévienne quand j'approche du rayon de 1km ou quand je le dépasse. Je ne souhaite pas avoir le nez sur une carte de mon téléphone.

Je regarde ce qui se fait. J'ai trouvé l'application suivante sur le play store : 1km. L'application m'avait l'air de répondre à mes critères mais ne fonctionnait pas lors de mon utilisation (en plus il y avait de la pub).

Une autre application 1km pourrait répondre à mon besoin mais je ne l'ai pas testé. ...


Lire la suite ...

Comment créer une bonne API Web - Partie 2

Posté le 2. November 2020 dans ProgrammationTags: api, graphql, rest, javascript, nodejs

Temps de lecture: 16 min

Bonjour,

Cet article fait partie d'un ensemble:

Qu'est qu'une API REST

REST est une norme dont voici les grandes lignes. Il n'est pas dans mon but de faire un cours sur REST (et il y en déjà de très bons sur internet). Je souhaiterais surtout parler des points qui me semblent importants. N'hésitez pas à venir me dire si vous pensez qu'il manque des points importants. Je viendrai alors compléter mon article.

Le principe de REST est de séparer l'API en différentes ressources logiques qui peuvent être manipulées par les verbes HTTP (GET, POST, ...). La réponse de son côté se base également sur les codes http. ...


Lire la suite ...

Comment créer une bonne API Web - Partie 1

Posté le 11. October 2020 dans ProgrammationTags: api, graphql, rest, javascript, nodejs

Temps de lecture: 10 min

Bonjour,

Je souhaite vous parler de l'écriture d'API. Je vais découper cet article en 3 parties:

Je me limiterai au WEB et aux normes REST et GraphQL même s'il y a d'autres normes/frameworks pour écrire des API.

Commençons donc par le début ! Qu'est-ce qu'une API ? API signifie Application Programming Interface. C'est une interface de programmation prête à être consommée par un client. ...


Lire la suite ...

Woodstock Backup v1.0.0

Posté le 20. September 2020 dans WoodstockTags: backup, sauvegarde, btrfs, rsync, javascript, nodejs, woodstock

Temps de lecture: 10 min

Bonjour à tous,

Un projet s'en va et un autre commence. Je suis heureux de vous présenter ce nouveau projet: Woodstock Backup.

Genèse du projet

Mes problèmes

Pour faire des sauvegardes, j'utilisais jusqu'ici BackupPC. C'est un très bon logiciel pour effectuer des sauvegardes de plusieurs machines sur une instance centralisée.

BackupPC est écrit en Perl avec des partie en C. En effet il se base sur un fork de rsync qui permet d'enregistrer le résultat des sauvegardes dans un format qui lui est propre. Malgré qu'il fonctionne très bien j'ai eu plusieurs problèmes avec récemment. ...


Lire la suite ...