盡可能改善執行個體記憶體用量偏高的情形

本文說明如何找出 Cloud SQL 執行個體記憶體用量偏高的問題,並提供解決記憶體相關問題的建議。

如要瞭解如何設定 Cloud SQL 執行個體的記憶體用量,請參閱「管理記憶體用量的最佳做法」。

找出記憶體用量偏高的情形

以下各節將說明記憶體用量偏高的情況。

使用 Metrics Explorer 找出記憶體用量

您可以在 Metrics Explorer 中,使用 database/memory/components 指標查看執行個體的記憶體用量:

  • usage:PostgreSQL 程序主動使用的記憶體,包括 shared_buffers 和其他資料庫內快取。
  • cache:作業系統頁面快取使用的記憶體,通常可回收。cache 值偏高不一定代表記憶體壓力。
  • free:資料庫程序或作業 系統頁面快取可用的未使用記憶體。

使用查詢洞察分析說明計畫,找出耗用大量資源的查詢

查詢洞察可協助您偵測、診斷及預防 Cloud SQL 資料庫的查詢效能問題。查詢洞察會列出長時間執行的查詢,以及說明計畫 (PostgreSQL 說明文件)。查看說明計畫,找出查詢中記憶體用量偏高的掃描方法。無論查詢執行時間為何,查詢洞察都會提供所有查詢的說明計畫。找出耗時較長的複雜查詢,瞭解哪些查詢會長時間占用記憶體。

常見的高記憶體用量 PostgreSQL 掃描方法包括:

  • 點陣圖堆積掃描
  • 快速排序
  • 雜湊彙整或雜湊

已啟用 Gemini 的執行個體記憶體用量偏高,以及相關記錄

如果啟用 Gemini,系統會終止執行高記憶體用量查詢的連線,避免資料庫因 OOM 故障而停機。如要找出預設查詢,請查看資料庫記錄中的下列項目:

  (...timestamp….) db=postgres, user=customer FATAL: terminating connection due to administrator command

系統會顯示下列 PostgreSQL 適用的 Cloud SQL 資料庫記錄,其中擷取了因記憶體用量過高而終止的查詢,以防 OOM。查詢是原始查詢的標準化版本:

  db=postgres,user=customer LOG:  postgres process with PID 1734 for the query "SELECT COUNT(product) AS item_count FROM test_table WHERE product_type = $1 AND product LIKE $2 AND c6_2 IN ($3,$4,$5,$6,$7)" has been cancelled.

「Cloud SQL 執行個體」頁面也會顯示下列事件的通知:

  • 執行個體過去 24 小時的記憶體使用率。
  • 過去 24 小時內取消的標準化查詢清單。
  • 點選這個連結,即可查看 Google 說明文件,瞭解如何最佳化記憶體用量。

記憶體用量偏高 - 建議

以下建議可解決常見的記憶體相關問題。如果執行個體持續使用大量記憶體,最終很可能會發生 out of memory 問題。如果 PostgreSQL 或其他程序的記憶體需求導致系統記憶體不足,PostgreSQL 記錄中會顯示 Out of Memory 核心訊息,且 PostgreSQL 執行個體最終會停止。例如:

Out of Memory: Killed process 12345 (postgres)

最常見的 OOM 問題是 work_mem 值較高,且有大量活躍連線。因此,如果 PostgreSQL 適用的 Cloud SQL 執行個體經常發生 OOM,或您想避免 OOM,建議採取下列做法:

  • 設定work_mem

    使用快速排序的查詢,速度會比使用外部合併排序的查詢快。不過,前者可能會導致記憶體耗盡。如要解決這個問題,請將 work_mem 值設為合理範圍,平衡記憶體和磁碟中的排序作業。您也可以考慮在工作階段層級設定 work_mem,而不是為整個執行個體設定。

  • 監控進行中的工作階段

    每個連線都會使用一定數量的記憶體。使用下列查詢,檢查有效連線數量:

      SELECT
        state,
        usename,
        count(1)
      FROM
        pg_stat_activity
      WHERE
        pid <> pg_backend_pid()
      GROUP BY
        state,
        usename
      ORDER BY
        1;
    

    如果有效工作階段數量過多,請分析根本原因,例如交易鎖定。

  • 設定shared_buffers

    如果 shared_buffers 設為較高的值,建議您降低 shared_buffers 值,以便將記憶體用於其他作業 (例如 work_mem),或建立新的連線。

    快取命中率

    PostgreSQL 通常會嘗試將最常存取的資料保留在快取中。當用戶端要求資料時,如果資料已快取在共用緩衝區中,就會直接提供給用戶端。這種情況稱為「快取命中」。如果共用緩衝區中沒有資料,系統會先從磁碟擷取資料至共用緩衝區,然後再提供給用戶端。這種情況稱為「快取失敗」。 快取命中率是指快取處理的內容要求數量,與收到的要求數量相比。執行下列查詢,檢查 PostgreSQL 執行個體中資料表要求的快取命中率:

    SELECT
      sum(heap_blks_read) as heap_read,
      sum(heap_blks_hit)  as heap_hit,
      sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio
    FROM
      pg_statio_user_tables;
    

    執行下列查詢,檢查 PostgreSQL 執行個體中索引要求的快取命中率:

      SELECT
        sum(idx_blks_read) as idx_read,
        sum(idx_blks_hit)  as idx_hit,
        (sum(idx_blks_hit) - sum(idx_blks_read)) / sum(idx_blks_hit) as ratio
      FROM
        pg_statio_user_indexes;
    

    一般來說,快取命中率達到 95% 至 99% 就算良好。

  • 在 PostgreSQL 適用的 Cloud SQL 中,系統預設會啟用 huge_pages 旗標,以便改善記憶體管理。如要進一步瞭解 huge_pages,請參閱 PostreSQL 說明文件。

  • 設定max_locks_per_transaction

    max_locks_per_transaction 值代表可同時鎖定的資料庫物件數量。在多數情況下,預設值 64 已足夠。不過,如果處理的是大型資料集,可能會發生記憶體不足的情況。建議您將 max_locks_per_transaction 的值提高到足以避免 OOM 的程度。

    max_locks_per_transaction 值應為 max_locks_per_transaction * (max_connections + max_prepared_transactions) 個物件。也就是說,如果您有 30 萬個物件,且 max_connections 的值為 200,則 max_locks_per_transaction 應為 1500。

  • 設定max_pred_locks_per_transaction

    如果用戶端在單一可序列化交易中接觸多個不同的資料表,交易可能會失敗。在這種情況下,建議將 max_pred_locks_per_transaction 提高到合理的高值。與 max_locks_per_transaction 一樣,max_pred_locks_per_transaction 也會使用共用記憶體,因此請勿設定過高的值。

  • 如果記憶體用量仍居高不下,且您認為這些查詢是合法流量,建議增加執行個體的記憶體資源數量,以免資料庫停止運作或停機。

後續步驟