簡體   English   中英

為什么 Google App 引擎不使用 Node.js 釋放 memory

[英]Why isn't Google App engine freeing memory using Node.js

所以這篇文章是一個兩部分的問題。 我正在使用實例 class F4 測試 Google 應用引擎(內存:1024 MB 和 CPU 2.4GHz,具有自動縮放功能)。 這是在 App 引擎上找到的配置文件:

runtime: nodejs10
env: standard
instance_class: F4
handlers:
  - url: .*
    script: auto
automatic_scaling:
  min_idle_instances: automatic
  max_idle_instances: automatic
  min_pending_latency: automatic
  max_pending_latency: automatic
network: {}

我的 Nodejs 服務器具有正常的 Post 和 Get 路由,除了提供 static 文件和從 MongoDB 獲取數據之外,這些路由不會繁重。 這是使用這些路由時的 memory 使用圖:

圖 1.Graph 顯示了從這些非重路由獲取時在 Google StackDriver 上看到的內存使用情況

我的第一個問題是,為什么這么小的任務需要這么多內存(大約 500mb)?

我正在使用 Chrome Devtools Node.js Memory Profiler 在我的 Windows 10 機器上運行分析測試,並且它在獲取這些數字時無處可取,我正在四處拍攝快照。

我的第二個問題是關於一個特定的路線,該路線采用上傳的文件並使用sharp將其調整為3個不同的圖像。

盡管在我的 Windows 10 機器上按預期工作,但在調整大小完成后,為什么 Memory 沒有被釋放?

我正在對10mb圖像進行大小調整測試,該圖像被轉換為緩沖區,然后存儲在 memory 中 轉換代碼如下:

const resizeAndSave = (buffer, filePath, widthResize, transform) => {
  const { width, height, x, y } = transform;
  //create sharp instance
  const image = sharp(buffer);
  //prepare to upload to Cloud storage
  const file = publicBucket.file(filePath);
  return new Promise((resolve, reject) => {
    image
      .metadata()
      .then(metadata => {
        //do image operations
        const img = image
          .extract({
            width: isEmpty(transform) ? metadata.width : parseInt(width),
            height: isEmpty(transform) ? metadata.height : parseInt(height),
            left: isEmpty(transform) ? 0 : parseInt(x),
            top: isEmpty(transform) ? 0 : parseInt(y)
          })
          .resize(
            metadata.width > widthResize
              ? {
                  width: widthResize || metadata.width,
                  withoutEnlargement: true
                }
              : metadata.height > widthResize
              ? {
                  height: widthResize || metadata.height,
                  withoutEnlargement: true
                }
              : {
                  width: widthResize || metadata.width,
                  withoutEnlargement: true
                }
          )
          .jpeg({
            quality: 40
          });
        //pipe to cloud storage and resolve filepath when done
        img
          .pipe(file.createWriteStream({ gzip: true }))
          .on("error", function(err) {
            reject(err);
          })
          .on("finish", function() {
            // The file upload is complete.
            resolve(filePath);
          });
      })
      .catch(err => {
        reject(err);
      });
  });
};

這個 function 對於每個圖像被連續調用了 3 次,Promise.all 並沒有用於防止它們為了測試而並行運行:

async function createAvatar(identifier, buffer, transform, done) {
  const dir = `uploads/${identifier}/avatar`;
  const imageId = nanoid_(20);
  const thumbName = `thumb_${imageId}.jpeg`;
  await resizeAndSave(buffer, `${dir}/${thumbName}`, 100, transform);
  const mediumName = `medium_${imageId}.jpeg`;
  await resizeAndSave(buffer, `${dir}/${mediumName}`, 400, transform);
  const originalName = `original_${imageId}.jpeg`;
  await resizeAndSave(buffer, `${dir}/${originalName}`, 1080, {});
  done(null, {
    thumbUrl: `https://bucket.storage.googleapis.com/${dir_}/${thumbName}`,
    mediumUrl: `https://bucket.storage.googleapis.com/${dir_}/${mediumName}`,
    originalUrl: `https://bucket.storage.googleapis.com/${dir_}/${originalName}`
  });
  /* Promise.all([thumb])
    .then(values => {

      done(null, {
        thumbUrl: `https://bucket.storage.googleapis.com/${dir_}/${thumbName}`,
        mediumUrl: `https://bucket.storage.googleapis.com/${dir_}/${mediumName}`,
        originalUrl: `https://bucket.storage.googleapis.com/${dir_}/${originalName}`
      });
    })
    .catch(err => {

      done(err, null);
    }); */
}

在我的 Window 10 機器上運行服務器時的堆快照是:

圖 2.Node.js 的 chrome devtools 的堆快照

這些堆快照清楚地表明,使用 memory 將 10mb 圖像存儲在 memory 並調整其大小正在返回到我機器上的操作系統。

StackDriver 上報告的 memory 使用情況為: 圖 3. 使用圖像大小調整路由時 Google StackDriver 的內存使用情況

這清楚地表明memory在操作完成時並沒有被釋放,而且非常高,從晚上8點左右開始,它上升到800mb並且從未下降。

我也嘗試了 Stackdriver 分析器,但它沒有顯示任何高 memory 使用率,但實際上,它顯示大約 55mb,接近我的 windows 機器:

Fig 4.StackDriver profiler heap shot

因此,如果我的分析是正確的,我假設它與運行應用引擎中的實例的操作系統有關? 我沒有任何線索。

更新:這是在使用圖像處理路線並且一個小時不接觸應用程序后從 Stackdriver 獲得的最新 memory 用法:

圖 5. 調整大小后讓應用閑置一小時時的內存使用情況

更新 2 :根據 Travis 的建議,我在導航到路線時查看了該過程,發現 memory 的使用率略高於堆,但與應用引擎顯示的相差甚遠: 圖 6.Windows 10 Nodejs 進程內存

更新 3 :在與圖 5 相同的時間間隔內使用的實例數(而 memory 的使用率很高): 在與圖 5 相同的時間間隔內使用的實例數

更新 4:所以我嘗試切換到實例 class F1(256 MB 600 MHz)看看會發生什么。 結果顯示空閑時內存使用量減少,但當我處理 10mb 圖像時,應用程序引擎會發送一條警告說升級內存。 (它顯示了 2 個正在運行的實例)。 具有 256MB 內存的 F1 實例類

這使我認為這些實例無論如何都試圖占用大部分可用的內存。

因此,作為上述評論和您上次更新(更新 4)的結果,我們可以意識到:

  • Stackdriver Profiler 指標,顯示平均 Memory 僅使用堆 Memory
  • 和 GCP 指標,它們展示了總 Memory 使用情況(所有實例)

是預期的行為。

調查 Node.js 應用程序 Memory 用法的一種方法是深入了解垃圾收集器的概念。

垃圾收集器(GC)的工作是回收未被使用的對象(垃圾)占用的 memory。

在這里這里您可以在 Node.js 中找到有關 Memory 管理和使用的信息

此外,Node.js 在認為有必要時會啟動 GC。 根據這篇文章,檢測可能的 memory 泄漏的想法是手動強制垃圾收集器並檢查 memory 是否仍在上升。 然而,這不是一個好的做法,不建議在生產中使用,而只是作為一種診斷方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM