Heim  >  Artikel  >  Backend-Entwicklung  >  Von Node.js bis hin zu Go: Laden Sie Tausende von Dateien in einer einzigen Zip-Datei auf

Von Node.js bis hin zu Go: Laden Sie Tausende von Dateien in einer einzigen Zip-Datei auf

WBOY
WBOYOriginal
2024-08-21 12:32:40821Durchsuche

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

Als Entwickler stehen wir oft vor Herausforderungen, wenn es um die Verarbeitung und Bereitstellung umfangreicher Daten geht. Bei Kamero haben wir kürzlich einen erheblichen Engpass in unserer Dateibereitstellungspipeline behoben. Unsere Anwendung ermöglicht es Benutzern, Tausende von Dateien, die mit einem bestimmten Ereignis verknüpft sind, als eine einzige ZIP-Datei herunterzuladen. Diese Funktion, die von einer Node.js-basierten Lambda-Funktion unterstützt wird, die für das Abrufen und Komprimieren von Dateien aus S3-Buckets verantwortlich ist, hatte mit Speicherbeschränkungen und langen Ausführungszeiten zu kämpfen, als unsere Benutzerbasis wuchs.

Dieser Beitrag beschreibt unseren Weg von einer ressourcenhungrigen Node.js-Implementierung zu einer schlanken und blitzschnellen Go-Lösung, die massive S3-Downloads effizient verarbeitet. Wir werden untersuchen, wie wir unser System optimiert haben, um Benutzern ein nahtloses Erlebnis zu bieten, wenn sie eine große Anzahl von Dateien von bestimmten Ereignissen anfordern, alles verpackt in einem praktischen einzigen Zip-Download.

Die Herausforderung

Unsere ursprüngliche Lambda-Funktion hatte bei der Verarbeitung großer ereignisbasierter Dateisätze mehrere kritische Probleme:

  1. Speicherverbrauch: Selbst mit 10 GB zugewiesenem Speicher würde die Funktion bei der Verarbeitung von mehr als 20.000 Dateien für größere Ereignisse fehlschlagen.
  2. Ausführungszeit: Zip-Vorgänge für Ereignisse mit zahlreichen Dateien dauerten zu lange, manchmal kam es vor dem Abschluss zu einer Zeitüberschreitung.
  3. Skalierbarkeit: Die Funktion konnte die zunehmende Last nicht effizient bewältigen, was unsere Fähigkeit einschränkte, Benutzer mit großen Dateisätzen von beliebten Ereignissen zu bedienen.
  4. Benutzererfahrung: Langsame Download-Vorbereitungszeiten wirkten sich negativ auf die Benutzerzufriedenheit aus, insbesondere bei Veranstaltungen mit einer hohen Dateianzahl.

Die Node.js-Implementierung: Ein kurzer Blick

Unsere ursprüngliche Implementierung nutzte die s3-zip-Bibliothek, um ZIP-Dateien aus S3-Objekten zu erstellen. Hier ist ein vereinfachter Ausschnitt davon, wie wir Dateien verarbeitet haben:

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

// ... other code ...

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

await uploadZipFile(Upload_Bucket, zipfileKey, body);

Obwohl dieser Ansatz funktionierte, wurden alle Dateien vor dem Erstellen der ZIP-Datei in den Speicher geladen, was zu einer hohen Speicherauslastung und potenziellen Fehlern wegen unzureichendem Arbeitsspeicher bei großen Dateisätzen führte.

Geben Sie Go ein: Eine bahnbrechende Neufassung

Wir haben uns entschieden, unsere Lambda-Funktion in Go neu zu schreiben und dabei deren Effizienz und integrierte Parallelitätsfunktionen zu nutzen. Die Ergebnisse waren verblüffend:

  1. Speichernutzung: Von 10 GB auf nur noch 100 MB bei gleicher Arbeitslast gesunken.
  2. Geschwindigkeit: Die Funktion wurde etwa zehnmal schneller.
  3. Zuverlässigkeit: Verarbeitet mehr als 20.000 Dateien erfolgreich und ohne Probleme.

Wichtige Optimierungen in der Go-Implementierung

1. Effizienter S3-Betrieb

Wir haben das AWS SDK for Go v2 verwendet, das im Vergleich zu v1 eine bessere Leistung und eine geringere Speichernutzung bietet:

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

2. Gleichzeitige Verarbeitung

Gos Goroutinen ermöglichten es uns, mehrere Dateien gleichzeitig zu verarbeiten:

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 <- struct{}{} // Acquire semaphore
        defer func() { <-sem }() // Release semaphore

        // Process photo
    }(photo)
}

wg.Wait()

Dieser Ansatz ermöglicht es uns, mehrere Dateien gleichzeitig zu verarbeiten und gleichzeitig den Grad der Parallelität zu kontrollieren, um eine Überlastung des Systems zu verhindern.

3. Streaming-Zip-Erstellung

Anstatt alle Dateien in den Speicher zu laden, streamen wir den ZIP-Inhalt direkt an 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,
})

Dieser Streaming-Ansatz reduziert die Speichernutzung erheblich und ermöglicht uns die Verarbeitung viel größerer Dateimengen.

Die Ergebnisse

Die Neufassung von Go lieferte beeindruckende Verbesserungen:

  1. Speicherverbrauch: Reduziert um 99 % (von 10 GB auf 100 MB)
  2. Verarbeitungsgeschwindigkeit: um ca. 1000 % erhöht
  3. Zuverlässigkeit: Verarbeitet erfolgreich über 20.000 Dateien ohne Probleme
  4. Kosteneffizienz: Geringere Speichernutzung und schnellere Ausführungszeit führen zu geringeren AWS Lambda-Kosten

Gelernte Lektionen

  1. Language Choice Matters: Das Effizienz- und Parallelitätsmodell von Go hat in unserem Anwendungsfall einen gewaltigen Unterschied gemacht.
  2. Verstehen Sie Ihre Engpässe: Durch die Profilierung unserer Node.js-Funktion konnten wir wichtige Verbesserungsbereiche identifizieren.
  3. Nutzung Cloud-nativer Lösungen: Die Verwendung von AWS SDK for Go v2 und das Verständnis der S3-Funktionen ermöglichten eine bessere Integration und Leistung.
  4. Denken Sie in Streams: Die Verarbeitung von Daten als Streams, anstatt alles in den Speicher zu laden, ist für groß angelegte Vorgänge von entscheidender Bedeutung.

Abschluss

Das Umschreiben unserer Lambda-Funktion in Go hat nicht nur unsere unmittelbaren Skalierungsprobleme gelöst, sondern auch eine robustere und effizientere Lösung für unsere Dateiverarbeitungsanforderungen bereitgestellt. Während Node.js uns anfangs gute Dienste leistete, verdeutlichte diese Erfahrung, wie wichtig es ist, das richtige Tool für die jeweilige Aufgabe auszuwählen, insbesondere bei der Bewältigung ressourcenintensiver Aufgaben im großen Maßstab.

Denken Sie daran, dass die beste Sprache oder das beste Framework von Ihrem spezifischen Anwendungsfall abhängt. In unserem Szenario stimmten die Leistungsmerkmale von Go perfekt mit unseren Anforderungen überein, was zu einer deutlich verbesserten Benutzererfahrung und geringeren Betriebskosten führte.

Stehten Sie mit serverlosen Funktionen vor ähnlichen Herausforderungen? Wie haben Sie sie überwunden? Wir würden gerne von Ihren Erfahrungen in den Kommentaren unten hören!

Das obige ist der detaillierte Inhalt vonVon Node.js bis hin zu Go: Laden Sie Tausende von Dateien in einer einzigen Zip-Datei auf. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn