」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 從 Node.js 到 Go:以單一 Zip 方式增強數千個檔案的下載量

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

發佈於2024-08-24
瀏覽:595

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 



這種方法允許我們同時處理多個文件,同時控制並發等級以防止系統不堪重負。

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-thousands-of-files-as-a-single-zip-474b?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何在 Go 中處理不同套件之間相同的方法簽名?
    如何在 Go 中處理不同套件之間相同的方法簽名?
    處理不同套件中具有相同方法簽名的介面在Go中,當處理具有相同方法簽署但定義在不同套件中的多個介面時,可能會出現以下情況實作兩個介面的類型會導致意外行為。 考慮在不同套件中定義的這兩個介面(Doer)和函數(FuncA 和 FuncB):// Package A type Doer interface...
    程式設計 發佈於2024-11-06
  • 如何使用 jQuery 填充級聯下拉清單以獲得更好的相容性和使用者體驗?
    如何使用 jQuery 填充級聯下拉清單以獲得更好的相容性和使用者體驗?
    使用jQuery 填充級聯下拉清單在表單開發領域,級聯下拉清單經常用於提供更用戶友好和動態體驗。為了增強相容性並解決跨瀏覽器問題,jQuery 提供了一個強大的解決方案來非同步填充這些下拉清單。 問題中所示的用於建立級聯下拉清單的原始 JavaScript 函數缺乏與 IE 的兼容性。為了解決這個問...
    程式設計 發佈於2024-11-06
  • 了解 JavaScript 中的擴充運算子:初學者簡單指南
    了解 JavaScript 中的擴充運算子:初學者簡單指南
    介紹 JavaScript 是一種有趣的程式語言,其最令人興奮的功能之一是擴充運算子。如果您剛開始編碼,或者即使您是一個對學習 JavaScript 感興趣的孩子,也不必擔心!我將以最簡單的方式分解這個概念,並舉例來幫助您理解。 什麼是價差運算子? 擴充運算子看起...
    程式設計 發佈於2024-11-06
  • 在 Python 中使用 OpenSearch 掌握 CRUD 操作:實用指南
    在 Python 中使用 OpenSearch 掌握 CRUD 操作:實用指南
    OpenSearch, an open-source alternative to Elasticsearch, is a powerful search and analytics engine built to handle large datasets with ease. In this b...
    程式設計 發佈於2024-11-06
  • 冰沙框架的重要概念||如何精通冰沙
    冰沙框架的重要概念||如何精通冰沙
    要精通 Frappe,有几个关键概念和领域需要关注。以下是最重要的细分: 1. 文档类型 定义:DocTypes是Frappe中的核心数据模型。每个实体或记录都存储在 DocType 中,并且它们可以具有字段、权限和工作流程。 为什么它很重要:了解如何创建和自定义 DocType 至...
    程式設計 發佈於2024-11-06
  • 如何解決 JLabel 拖放的滑鼠事件衝突?
    如何解決 JLabel 拖放的滑鼠事件衝突?
    用於拖放的JLabel 滑鼠事件:解決滑鼠事件衝突為了在JLabel 上啟用拖放功能,滑鼠事件必須被覆蓋。然而,當嘗試使用 mousePressed 事件實作拖放時,會出現一個常見問題,因為 mouseReleased 事件對該 JLabel 無效。 提供的程式碼在 mousePressed 事件中...
    程式設計 發佈於2024-11-06
  • MySQL 中的資料庫分片:綜合指南
    MySQL 中的資料庫分片:綜合指南
    随着数据库变得越来越大、越来越复杂,有效地控制性能和扩展就出现了。数据库分片是用于克服这些障碍的一种方法。称为“分片”的数据库分区将大型数据库划分为更小、更易于管理的段(称为“分片”)。通过将每个分片分布在多个服务器上(每个服务器保存总数据的一小部分),可以提高可扩展性和吞吐量。 在本文中,我们将探...
    程式設計 發佈於2024-11-06
  • 如何將 Python 日期時間物件轉換為秒?
    如何將 Python 日期時間物件轉換為秒?
    在Python 中將日期時間物件轉換為秒在Python 中使用日期時間物件時,通常需要將它們轉換為秒以適應各種情況分析目的。但是,toordinal() 方法可能無法提供所需的輸出,因為它僅區分具有不同日期的日期。 要準確地將日期時間物件轉換為秒,特別是對於 1970 年 1 月 1 日的特定日期,...
    程式設計 發佈於2024-11-06
  • 如何使用 Laravel Eloquent 的 firstOrNew() 方法有效最佳化 CRUD 操作?
    如何使用 Laravel Eloquent 的 firstOrNew() 方法有效最佳化 CRUD 操作?
    使用 Laravel Eloquent 優化 CRUD 操作在 Laravel 中使用資料庫時,插入或更新記錄是很常見的。為了實現這一點,開發人員經常求助於條件語句,在決定執行插入或更新之前檢查記錄是否存在。 firstOrNew() 方法幸運的是, Eloquent 透過firstOrNew() ...
    程式設計 發佈於2024-11-06
  • 為什麼在 PHP 中重寫方法參數違反了嚴格的標準?
    為什麼在 PHP 中重寫方法參數違反了嚴格的標準?
    在PHP 中重寫方法參數:違反嚴格標準在物件導向程式設計中,里氏替換原則(LSP) 規定:子類型的物件可以替換其父對象,而不改變程式的行為。然而,在 PHP 中,用不同的參數簽名覆蓋方法被認為是違反嚴格標準的。 為什麼這是違規? PHP 是弱型別語言,這表示編譯器無法在編譯時確定變數的確切型別。這表...
    程式設計 發佈於2024-11-06
  • 哪個 PHP 函式庫提供卓越的 SQL 注入防護:PDO 還是 mysql_real_escape_string?
    哪個 PHP 函式庫提供卓越的 SQL 注入防護:PDO 還是 mysql_real_escape_string?
    PDO vs. mysql_real_escape_string:綜合指南查詢轉義對於防止 SQL 注入至關重要。雖然 mysql_real_escape_string 提供了轉義查詢的基本方法,但 PDO 成為了一種具有眾多優點的卓越解決方案。 什麼是 PDO? PHP 資料物件 (PDO) 是一...
    程式設計 發佈於2024-11-06
  • React 入門:初學者的路線圖
    React 入門:初學者的路線圖
    大家好! ? 我剛開始學習 React.js 的旅程。這是一次令人興奮(有時甚至具有挑戰性!)的冒險,我想分享一下幫助我開始的步驟,以防您也開始研究 React。這是我的處理方法: 1.掌握 JavaScript 基礎 在開始使用 React 之前,我確保溫習一下我的 JavaScript 技能,...
    程式設計 發佈於2024-11-06
  • 如何引用 JavaScript 物件中的內部值?
    如何引用 JavaScript 物件中的內部值?
    如何在JavaScript 物件中引用內部值在JavaScript 中,存取引用同一物件中其他值的物件中的值有時可能具有挑戰性。考慮以下程式碼片段:var obj = { key1: "it ", key2: key1 " works!" }; a...
    程式設計 發佈於2024-11-06
  • Python 列表方法快速指南及範例
    Python 列表方法快速指南及範例
    介紹 Python 清單用途廣泛,並附帶各種內建方法,有助於有效地操作和處理資料。以下是所有主要清單方法的快速參考以及簡短的範例。 1. 追加(項目) 將項目新增至清單末端。 lst = [1, 2, 3] lst.append(4) # [1, 2, 3, ...
    程式設計 發佈於2024-11-06

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3