Node.js から Go へ: 数千のファイルのダウンロードを 1 つの ZIP としてスーパーチャージする

WBOY
リリース: 2024-08-21 12:32:40
オリジナル
914 人が閲覧しました

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

開発者として、私たちは大規模なデータの処理と配信を扱うときにしばしば課題に直面します。 Kamiro では最近、ファイル配信パイプラインの重大なボトルネックに取り組みました。私たちのアプリケーションを使用すると、ユーザーは特定のイベントに関連する数千のファイルを単一の zip ファイルとしてダウンロードできます。この機能は、S3 バケットからのファイルのフェッチと圧縮を担当する Node.js ベースの Lambda 関数によって強化されていますが、ユーザーベースが拡大するにつれて、メモリの制約と長い実行時間に悩まされました。

この投稿では、リソースを大量に消費する Node.js 実装から、大規模な S3 ダウンロードを効率的に処理する無駄のない超高速 Go ソリューションへの移行について詳しく説明します。特定のイベントから大量のファイルをリクエストする際に、ユーザーにシームレスなエクスペリエンスを提供するために、システムをどのように最適化し、すべてを 1 つの便利な zip ダウンロードにパッケージ化したかを見ていきます。

挑戦

私たちの元の Lambda 関数は、大規模なイベントベースのファイルセットを処理する際に、いくつかの重大な問題に直面しました。

  1. メモリ消費量: 10GB のメモリが割り当てられていても、より大きなイベントで 20,000 以上のファイルを処理すると、関数は失敗します。
  2. 実行時間: 多数のファイルを含むイベントの ZIP 操作に時間がかかりすぎ、完了する前にタイムアウトになる場合がありました。
  3. スケーラビリティ: この関数は増大する負荷を効率的に処理できず、人気のイベントからの大きなファイル セットをユーザーに提供する能力が制限されていました。
  4. ユーザー エクスペリエンス: ダウンロードの準備に時間がかかると、特にファイル数が多いイベントの場合、ユーザーの満足度に影響を及ぼしていました。

Node.js 実装: 概要

私たちの元の実装では、s3-zip ライブラリを使用して S3 オブジェクトから zip ファイルを作成しました。ファイルの処理方法を簡略化したスニペットを次に示します:

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

// ... other code ...

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

await uploadZipFile(Upload_Bucket, zipfileKey, body);
ログイン後にコピー

このアプローチは機能しましたが、zip を作成する前にすべてのファイルがメモリに読み込まれるため、メモリ使用率が高くなり、大きなファイル セットではメモリ不足エラーが発生する可能性がありました。

Go の登場: 革新的なリライト

私たちは、効率性と組み込みの同時実行機能を活用して、Lambda 関数を Go で書き直すことにしました。結果は驚くべきものでした:

  1. メモリ使用量: 同じワークロードで 10GB からわずか 100MB に減少しました。
  2. 速度: 機能が約 10 倍高速になりました。
  3. 信頼性: 20,000 以上のファイルを問題なく正常に処理します。

Go 実装における主要な最適化

1. 効率的な S3 運用

AWS SDK for Go v2 を使用しました。これは、v1 と比較してパフォーマンスが向上し、メモリ使用量が少なくなります。

cfg, err := config.LoadDefaultConfig(context.TODO())
s3Client = s3.NewFromConfig(cfg)
ログイン後にコピー

2. 同時処理

Go のゴルーチンを使用すると、複数のファイルを同時に処理できます。

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()
ログイン後にコピー

このアプローチにより、同時実行レベルを制御しながら複数のファイルを同時に処理し、システムに負荷がかかるのを防ぐことができます。

3. ストリーミング ZIP の作成

すべてのファイルをメモリにロードする代わりに、zip コンテンツを 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,
})
ログイン後にコピー

このストリーミング アプローチにより、メモリ使用量が大幅に削減され、より大きなファイル セットを処理できるようになります。

結果

Go への書き直しにより、目覚ましい改善がもたらされました。

  1. メモリ使用量: 99% 削減 (10GB から 100MB へ)
  2. 処理速度: 約1000%向上
  3. 信頼性: 20,000 以上のファイルを問題なく正常に処理します
  4. コスト効率: メモリ使用量の削減と実行時間の短縮により、AWS Lambda のコストが削減されます

学んだ教訓

  1. 言語の選択は重要です: Go の効率性と同時実行モデルは、私たちのユースケースに大きな違いをもたらしました。
  2. ボトルネックを理解する: Node.js 関数をプロファイリングすることで、改善すべき重要な領域を特定することができました。
  3. クラウドネイティブ ソリューションの活用: AWS SDK for Go v2 を使用し、S3 の機能を理解することで、統合とパフォーマンスを向上させることができました。
  4. ストリームで考える: 大規模な操作では、データをすべてメモリにロードするのではなく、ストリームとして処理することが重要です。

結論

Go で Lambda 関数を書き直すことで、当面のスケーリングの問題が解決されただけでなく、ファイル処理のニーズに対してより堅牢で効率的なソリューションも提供されました。最初は Node.js が役に立ちましたが、この経験から、特にリソースを大量に消費するタスクを大規模に処理する場合には、ジョブに適したツールを選択することの重要性が浮き彫りになりました。

最適な言語またはフレームワークは、特定の使用例によって異なることに注意してください。私たちのシナリオでは、Go のパフォーマンス特性が私たちのニーズと完全に一致し、その結果、ユーザー エクスペリエンスが大幅に向上し、運用コストが削減されました。

サーバーレス機能に関して同様の課題に直面したことがありますか?どのようにしてそれらを克服しましたか?以下のコメント欄であなたの経験をぜひお聞かせください!

以上がNode.js から Go へ: 数千のファイルのダウンロードを 1 つの ZIP としてスーパーチャージするの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート