開発者として、私たちは大規模なデータの処理と配信を扱うときにしばしば課題に直面します。 Kamiro では最近、ファイル配信パイプラインの重大なボトルネックに取り組みました。私たちのアプリケーションを使用すると、ユーザーは特定のイベントに関連する数千のファイルを単一の zip ファイルとしてダウンロードできます。この機能は、S3 バケットからのファイルのフェッチと圧縮を担当する Node.js ベースの Lambda 関数によって強化されていますが、ユーザー ベースが拡大するにつれて、メモリの制約と長い実行時間に悩まされました。
この投稿では、リソースを大量に消費する Node.js 実装から、大規模な S3 ダウンロードを効率的に処理する無駄のない超高速 Go ソリューションへの移行について詳しく説明します。特定のイベントから大量のファイルをリクエストする際に、ユーザーにシームレスなエクスペリエンスを提供するためにシステムをどのように最適化し、すべてを便利な 1 つの zip ダウンロードにパッケージ化したかを見ていきます。
私たちの元の Lambda 関数は、大規模なイベントベースのファイルセットを処理するときにいくつかの重大な問題に直面しました:
私たちの元の実装では、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 を作成する前にすべてのファイルがメモリに読み込まれるため、メモリ使用率が高くなり、大きなファイル セットではメモリ不足エラーが発生する可能性がありました。
私たちは、効率性と組み込みの同時実行機能を活用して、Lambda 関数を Go で書き直すことにしました。結果は驚くべきものでした:
AWS SDK for Go v2 を使用しました。これにより、v1 と比較してパフォーマンスが向上し、メモリ使用量が少なくなります:
cfg, err := config.LoadDefaultConfig(context.TODO()) s3Client = s3.NewFromConfig(cfg)
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 への書き直しにより、目覚ましい改善がもたらされました:
- メモリ使用量: 99% 削減 (10GB から 100MB に)
- 処理速度: 約1000%向上
- 信頼性: 20,000 個のファイルを問題なく処理できます
- コスト効率: メモリ使用量の削減と実行時間の短縮により、AWS Lambda のコストが削減されます
学んだ教訓
- 言語の選択は重要です: Go の効率性と同時実行モデルは、私たちのユースケースに大きな違いをもたらしました。
- ボトルネックを理解する: Node.js 関数をプロファイリングすることで、改善すべき重要な領域を特定することができました。
- クラウドネイティブ ソリューションの活用: AWS SDK for Go v2 を使用し、S3 の機能を理解することで、統合とパフォーマンスを向上させることができました。
- ストリームで考える: 大規模な操作では、データをすべてメモリにロードするのではなく、ストリームとして処理することが重要です。
結論
Go で Lambda 関数を書き直すことで、当面のスケーリングの問題が解決されただけでなく、ファイル処理のニーズに対してより堅牢で効率的なソリューションも提供されました。最初は Node.js が役に立ちましたが、この経験から、特にリソースを大量に消費するタスクを大規模に処理する場合には、ジョブに適したツールを選択することの重要性が強調されました。
最適な言語またはフレームワークは、特定の使用例によって異なることに注意してください。私たちのシナリオでは、Go のパフォーマンス特性が私たちのニーズと完全に一致し、その結果、ユーザー エクスペリエンスが大幅に向上し、運用コストが削減されました。
サーバーレス機能に関して同様の課題に直面したことがありますか?どのようにしてそれらを克服しましたか?以下のコメント欄であなたの経験についてお聞かせください!
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3