"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > De Node.js à Go : supercharger des téléchargements de milliers de fichiers en un seul zip

De Node.js à Go : supercharger des téléchargements de milliers de fichiers en un seul zip

Publié le 2024-08-24
Parcourir:671

From Node.js to Go: Supercharging Sownloads of Thousands of Files as a Single Zip

En tant que développeurs, nous sommes souvent confrontés à des défis lorsque nous traitons du traitement et de la livraison de données à grande échelle. Chez Kamero, nous avons récemment résolu un goulot d'étranglement important dans notre pipeline de livraison de fichiers. Notre application permet aux utilisateurs de télécharger des milliers de fichiers associés à un événement particulier sous la forme d'un seul fichier zip. Cette fonctionnalité, optimisée par une fonction Lambda basée sur Node.js, responsable de la récupération et de la compression des fichiers à partir des compartiments S3, était confrontée à des contraintes de mémoire et à de longs temps d'exécution à mesure que notre base d'utilisateurs grandissait.

Cet article détaille notre parcours depuis une implémentation de Node.js gourmande en ressources jusqu'à une solution Go légère et ultra-rapide qui gère efficacement les téléchargements S3 massifs. Nous explorerons comment nous avons optimisé notre système pour offrir aux utilisateurs une expérience transparente lors de la demande d'un grand nombre de fichiers provenant d'événements spécifiques, le tout regroupé dans un téléchargement zip unique et pratique.

Le défi

Notre fonction Lambda d'origine était confrontée à plusieurs problèmes critiques lors du traitement de grands ensembles de fichiers basés sur des événements :

  1. Consommation de mémoire : même avec 10 Go de mémoire allouée, la fonction échouerait lors du traitement de 20 000 fichiers pour des événements plus volumineux.
  2. Délai d'exécution : les opérations Zip pour les événements comportant de nombreux fichiers prenaient trop de temps, arrivant parfois à expiration avant la fin.
  3. Évolutivité : la fonction ne parvenait pas à gérer efficacement la charge croissante, limitant notre capacité à servir les utilisateurs disposant d'ensembles de fichiers volumineux provenant d'événements populaires.
  4. Expérience utilisateur : les temps de préparation du téléchargement lents avaient un impact sur la satisfaction des utilisateurs, en particulier pour les événements comportant un nombre de fichiers important.

L'implémentation de Node.js : un aperçu rapide

Notre implémentation originale utilisait la bibliothèque s3-zip pour créer des fichiers zip à partir d'objets S3. Voici un extrait simplifié de la façon dont nous traitions les fichiers :

const s3Zip = require("s3-zip");

// ... other code ...

const body = s3Zip.archive(
  { bucket: bucketName },
  eventId,
  files,
  entryData
);

await uploadZipFile(Upload_Bucket, zipfileKey, body);

Bien que cette approche ait fonctionné, elle a chargé tous les fichiers en mémoire avant de créer le zip, ce qui a entraîné une utilisation élevée de la mémoire et des erreurs potentielles de manque de mémoire pour les grands ensembles de fichiers.

Enter Go : une réécriture qui change la donne

Nous avons décidé de réécrire notre fonction Lambda dans Go, en tirant parti de son efficacité et de ses fonctionnalités de concurrence intégrées. Les résultats ont été stupéfiants :

  1. Utilisation de la mémoire : passée de 10 Go à seulement 100 Mo pour la même charge de travail.
  2. Vitesse : la fonction est devenue environ 10 fois plus rapide.
  3. Fiabilité : traite avec succès 20 000 fichiers sans problème.

Optimisations clés dans la mise en œuvre Go

1. Opérations S3 efficaces

Nous avons utilisé le SDK AWS pour Go v2, qui offre de meilleures performances et une utilisation moindre de la mémoire par rapport à la v1 :

cfg, err := config.LoadDefaultConfig(context.TODO())
s3Client = s3.NewFromConfig(cfg)

2. Traitement simultané

Les goroutines de Go nous ont permis de traiter plusieurs fichiers simultanément :

var wg sync.WaitGroup
sem := make(chan struct{}, 10) // Limit concurrent operations

for _, photo := range photos {
    wg.Add(1)
    go func(photo Photo) {
        defer wg.Done()
        sem 



Cette approche nous permet de traiter plusieurs fichiers simultanément tout en contrôlant le niveau de concurrence pour éviter de surcharger le système.

3. Création de Zip en streaming

Au lieu de charger tous les fichiers en mémoire, nous diffusons le contenu zip directement vers S3 :

pipeReader, pipeWriter := io.Pipe()

go func() {
    zipWriter := zip.NewWriter(pipeWriter)
    // Add files to zip
    zipWriter.Close()
    pipeWriter.Close()
}()

// Upload streaming content to S3
uploader.Upload(ctx, &s3.PutObjectInput{
    Bucket: &destBucket,
    Key:    &zipFileKey,
    Body:   pipeReader,
})

Cette approche de streaming réduit considérablement l'utilisation de la mémoire et nous permet de gérer des ensembles de fichiers beaucoup plus volumineux.

Les résultats

La réécriture vers Go a apporté des améliorations impressionnantes :

  1. Utilisation de la mémoire : réduite de 99 % (de 10 Go à 100 Mo)
  2. Vitesse de traitement : augmentée d'environ 1 000 %
  3. Fiabilité : gère avec succès 20 000 fichiers sans problème
  4. Rapport coût-efficacité : une utilisation moindre de la mémoire et un temps d'exécution plus rapide entraînent une réduction des coûts AWS Lambda

Leçons apprises

  1. Le choix de la langue est important : le modèle d'efficacité et de concurrence de Go a fait une énorme différence dans notre cas d'utilisation.
  2. Comprenez vos goulots d'étranglement : le profilage de notre fonction Node.js nous a aidé à identifier les domaines clés à améliorer.
  3. Tirez parti des solutions cloud natives : l'utilisation du SDK AWS pour Go v2 et la compréhension des capacités de S3 ont permis une meilleure intégration et de meilleures performances.
  4. Penser en flux : traiter les données sous forme de flux plutôt que de tout charger en mémoire est crucial pour les opérations à grande échelle.

Conclusion

La réécriture de notre fonction Lambda dans Go a non seulement résolu nos problèmes de mise à l'échelle immédiats, mais a également fourni une solution plus robuste et plus efficace pour nos besoins de traitement de fichiers. Bien que Node.js nous ait bien servi au début, cette expérience a souligné l'importance de choisir le bon outil pour le travail, en particulier lorsqu'il s'agit de tâches gourmandes en ressources à grande échelle.

N'oubliez pas que le meilleur langage ou framework dépend de votre cas d'utilisation spécifique. Dans notre scénario, les caractéristiques de performance de Go correspondaient parfaitement à nos besoins, ce qui se traduisait par une expérience utilisateur considérablement améliorée et une réduction des coûts opérationnels.

Avez-vous été confronté à des défis similaires avec les fonctions sans serveur ? Comment les avez-vous surmontés ? Nous serions ravis de connaître vos expériences dans les commentaires ci-dessous !

Déclaration de sortie Cet article est reproduit sur : https://dev.to/hiteshsisara/from-nodejs-to-go-supercharger-s3-downloads-of-thousands-of-files-as-a-single-zip-474b?1S'il y a en cas d'infraction, veuillez contacter [email protected] pour supprimer
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3