「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > Node.js から Go へ: 数千のファイルのダウンロードを 1 つの ZIP としてスーパーチャージする

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

2024 年 8 月 24 日に公開
ブラウズ:785

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. メモリ消費量: 10 GB のメモリが割り当てられていても、より大きなイベントで 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. メモリ使用量: 同じワークロードで 10 GB からわずか 100 MB に減少しました。
  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 



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

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 のパフォーマンス特性が私たちのニーズと完全に一致し、その結果、ユーザー エクスペリエンスが大幅に向上し、運用コストが削減されました。

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

リリースステートメント この記事は、https://dev.to/hiteshsisara/from-nodejs-to-go-supercharging-s3-downloads-of-of-of-of-files-as-as-as-a-single-zip-474bに再現されています。
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3