首頁  >  文章  >  後端開發  >  從 Node.js 到 Go:以單一 Zip 方式增強數千個檔案的下載量

從 Node.js 到 Go:以單一 Zip 方式增強數千個檔案的下載量

WBOY
WBOY原創
2024-08-21 12:32:40824瀏覽

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

身為開發人員,我們在處理大規模資料處理和交付時經常面臨挑戰。在 Kamero,我們最近解決了文件傳輸管道中的一個重大瓶頸。我們的應用程式允許用戶將與特定事件相關的數千個檔案下載為單一 zip 檔案。此功能由基於 Node.js 的 Lambda 函數提供支持,負責從 S3 存儲桶中獲取和壓縮文件,但隨著我們用戶群的增長,該功能一直面臨著內存限制和較長執行時間的問題。

這篇文章詳細介紹了我們從資源匱乏的 Node.js 實現到高效處理大量 S3 下載的精益且快速的 Go 解決方案的歷程。我們將探討如何優化我們的系統,以便在從特定事件請求大量文件時為用戶提供無縫體驗,所有文件都打包到一個方便的單一 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:改變遊戲規則的重寫

我們決定用 Go 重寫 Lambda 函數,利用其效率和內建並發功能。結果令人震驚:

  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 的 goroutine 允許我們同時處理多個檔案:

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:以單一 Zip 方式增強數千個檔案的下載量的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn