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

執行個體耗用大量記憶體或發生記憶體不足 (OOM) 事件,是常見的問題。在記憶體使用率偏高的情況下,資料庫執行個體常會引發效能問題、停頓,甚至停機。

部分 MySQL 記憶體區塊會用於全域,這表示所有查詢工作負載都會共用記憶體位置、隨時占用記憶體,且只有在 MySQL 程序停止時才會釋出。部分記憶體區塊是以工作階段為基礎,也就是說,工作階段關閉後,該工作階段使用的記憶體也會釋回系統。

每當 MySQL 適用的 Cloud SQL 執行個體記憶體用量偏高時,Cloud SQL 會建議您找出使用大量記憶體的查詢或程序,並釋出記憶體。MySQL 記憶體用量分為三大類:

  • 執行緒和程序記憶體消耗量
  • 緩衝記憶體消耗量
  • 快取記憶體消耗量

執行緒和程序記憶體消耗量

每個使用者工作階段耗用的記憶體,取決於該工作階段執行的查詢、緩衝區或快取,並由 MySQL 的工作階段參數控制。主要參數包括:

  • thread_stack
  • net_buffer_length
  • read_buffer_size
  • read_rnd_buffer_size
  • sort_buffer_size
  • join_buffer_size
  • max_heap_table_size
  • tmp_table_size

如果在特定時間執行的查詢數量為 N,則在工作階段期間,每項查詢都會根據這些參數耗用記憶體。

緩衝記憶體消耗量

這部分記憶體是所有查詢共用,並由 innodb_buffer_pool_size、innodb_log_buffer_size 和 key_buffer_size 等參數控制。

InnoDB 緩衝區集區是由 innodb_buffer_pool_size 旗標設定,會占用 MySQL 適用的 Cloud SQL 執行個體的大量記憶體,並做為快取來提升效能。如要降低記憶體不足 (OOM) 事件的風險,可以啟用代管緩衝集區。

快取記憶體消耗量

快取記憶體包含查詢快取,用於儲存查詢及其結果,以便在後續執行相同查詢時更快擷取資料。此外,也包含 binlog 快取,用於保留交易執行期間對二進位記錄所做的變更,並由 binlog_cache_size 控制。

其他記憶體消耗

彙整和排序作業也會使用記憶體。如果查詢使用彙整或排序作業,則會根據 join_buffer_size 和 sort_buffer_size 使用記憶體。

此外,如果啟用效能結構定義,也會耗用記憶體。如要查看效能結構定義的記憶體用量,請使用下列查詢:

SELECT *
FROM
  performance_schema.memory_summary_global_by_event_name
WHERE EVENT_NAME LIKE 'memory/performance_schema/%';

MySQL 提供許多檢測工具,您可以設定這些工具,透過效能結構定義監控記憶體用量。詳情請參閱 MySQL 說明文件。

用於大量資料插入的 MyISAM 相關參數為 bulk_insert_buffer_size。

如要瞭解 MySQL 如何使用記憶體,請參閱 MySQL 說明文件。

建議

以下各節提供一些關於最佳記憶體用量的建議。

啟用代管緩衝區集區

啟用代管緩衝區集區,有助於在執行個體記憶體用量偏高時,降低 InnoDB 緩衝區集區 (或 innodb_buffer_pool_size) 的記憶體用量。這樣就能釋出記憶體,供其他資料庫程序使用。如果執行個體的記憶體用量偏高,可能會發生記憶體不足 (OOM) 事件。建議您在執行個體上啟用代管緩衝集區,避免發生 OOM 事件。

當記憶體用量穩定維持在較低值達 10 分鐘以上,代管緩衝集區會逐步將 innodb_buffer_pool_size 的值調回原始值。記憶體用量穩定後,您也可以將 innodb_buffer_pool_size 旗標的值提高至所選值。

資格條件

您無法為共用核心執行個體、MySQL 5.6 或 MySQL 5.7 啟用代管緩衝集區。

啟用功能

如要為執行個體啟用代管緩衝區集區,請將 innodb_cloudsql_managed_buffer_pool 旗標設為 on。如要進一步瞭解如何設定資料庫旗標,請參閱「設定資料庫旗標」。

變更 innodb_cloudsql_managed_buffer_pool 旗標的值時,不需要重新啟動 Cloud SQL 執行個體。

如果您已啟用代管緩衝區集區,且執行個體的記憶體用量超過分配記憶體的預設門檻百分比,Cloud SQL 就會開始縮減 innodb_buffer_pool_size 的大小。這個預設門檻百分比會因執行個體的 RAM 容量而異,介於 90% 到 97% 之間。如要修改門檻,請將 innodb_cloudsql_managed_buffer_pool_threshold_pct 旗標設為不同的百分比值。舉例來說,如要將門檻調整為 97%,請使用下列指令:

gcloud sql instances patch INSTANCE_NAME \
   --database-flags=EXISTING_FLAGS,innodb_cloudsql_managed_buffer_pool=on,\
     innodb_cloudsql_managed_buffer_pool_threshold_pct=97

您可以將 innodb_cloudsql_managed_buffer_pool_threshold_pct 旗標設為 50 到 99 之間的整數值。變更記憶體用量門檻值時,不需要重新啟動 Cloud SQL 執行個體。

如果記憶體用量在先前減少後穩定 10 分鐘以上,代管緩衝區集區會增加 innodb_buffer_pool_size 旗標。根據預設,資料庫記憶體用量必須維持在 70% 以下,才會觸發增加。如要修改門檻,請將 innodb_cloudsql_managed_buffer_pool_tuneup_pct 旗標設為不同的百分比值。舉例來說,如要將增加門檻變更為 80%,請使用下列指令:

gcloud sql instances patch INSTANCE_NAME \
   --database-flags=EXISTING_FLAGS,innodb_cloudsql_managed_buffer_pool=on,\
     innodb_cloudsql_managed_buffer_pool_tuneup_pct=80

調整邏輯

代管緩衝區集區不會將 innodb_buffer_pool_size 縮減至預先決定的固定大小下限。而是會反覆動態縮減大小,直到執行個體記憶體總使用率降至設定的門檻百分比 (innodb_cloudsql_managed_buffer_pool_threshold_pct) 以下。系統會調整 innodb_buffer_pool_size 旗標的值,並運用 InnoDB 內建的緩衝區集區大小調整功能,縮減緩衝區集區。

如果記憶體用量在縮減後仍居高不下,為避免 innodb_buffer_pool_size 縮減至嚴重影響效能的大小,這項功能會使用內部安全下限。值代表必須分配給緩衝區集區的執行個體記憶體總量百分比。

MySQL 容器大小 緩衝區集區大小下限
1025–2048 MB 35%
2049 至 6528 MB 30%
6529–11315 MB 40%
11316–22630 MB 45%
其他大小 (預設) 50%

innodb_buffer_pool_size 的減少量取決於資料庫執行個體的記憶體容量。下表列出各容器大小的減少百分比:

MySQL 容器大小 調降百分比
1025–2048 MB 15%
2049 至 6528 MB 11%
6529–11315 MB 8%
11316–22630 MB 6%
其他大小 (預設) 5%

計算出新的縮減值後,代管緩衝區集區會將 innodb_buffer_pool_size 四捨五入至最接近 innodb_buffer_pool_instances 和 innodb_buffer_pool_chunk_size 值的倍數。

當代管緩衝集區調整innodb_buffer_pool_size的值時,變更不會反映在 Cloud de Confiance 控制台中。如要在啟用代管緩衝區集區時查看 innodb_buffer_pool_size 的目前值,可以使用 MySQL 用戶端:

mysql> SHOW GLOBAL VARIABLES LIKE 'innodb_buffer_pool_size';

限制

縮減緩衝集區大小不一定能避免 OOM。例如,某些工作負載可能會以不可持續的方式消耗記憶體,或突然增加記憶體用量,某些 Cloud SQL 執行個體可能佈建不足,或緩衝集區可能未預熱。Cloud SQL 可能無法快速釋出記憶體,因應記憶體工作負載的突發變化。此外,Cloud SQL 無法容納其他記憶體旗標的錯誤設定值。

監控

您可以在 MySQL 錯誤記錄中監控代管緩衝集區。在 Cloud Logging Logs Explorer中,您可以篩選 mysql.err 記錄檔,找出前置字串為 Managed Buffer Pool Plugin: 或 Tuner Plugin: 的項目,找出最新的調整事件。

代管緩衝區集區首次啟動時,會發出類似以下的記錄:

[Note] [MY-000000] [Server] Managed Buffer Pool Plugin: MySQL Instance memory limit: 29533, Current MySQL memory usage: 2663641088, Max Allowed MySQL memory usage: 30732730368 ...

以下記錄顯示自動降低 innodb_buffer_pool_size 的範例:

[Note] [MY-000000] [Server] Managed Buffer Pool Plugin: Decreasing InnoDB Buffer Pool Size.
[Note] [MY-000000] [Server] Managed Buffer Pool Plugin: Updated innodb_buffer_pool_size=805306368 bytes.

您可以設定記錄指標,追蹤代管緩衝集區調整事件。

使用 Cloud Monitoring Metrics Explorer 找出記憶體用量

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

一般來說,如果 database/memory/components.cache 和 database/memory/components.free 的記憶體總量低於 10%,發生 OOM 事件的風險就會很高。為監控記憶體用量並避免 OOM 事件,建議您在 database/memory/components.usage 中設定警告政策,並加入指標門檻條件。

下表列出執行個體記憶體與建議警告門檻之間的關係:

執行個體記憶體 建議的快訊門檻
小於或等於 16 GB 90%
大於 16 GB 95%

計算記憶體消耗量

計算 MySQL 資料庫的記憶體用量上限,為 MySQL 資料庫選取合適的執行個體類型。請使用下列公式:

MySQL 記憶體用量上限 = innodb_buffer_pool_size + innodb_additional_mem_pool_size + innodb_log_buffer_size + tmp_table_size + key_buffer_size + ((read_buffer_size + read_rnd_buffer_size + sort_buffer_size + join_buffer_size) x max_connections)

公式中使用的參數如下:

  • innodb_buffer_pool_size:緩衝區集區的大小 (以位元組為單位),緩衝區集區是 InnoDB 快取資料表和索引資料的記憶體區域。
  • innodb_additional_mem_pool_size:InnoDB 用於儲存資料字典資訊和其他內部資料結構的記憶體集區大小 (以位元組為單位)。
  • innodb_log_buffer_size:InnoDB 用來寫入磁碟記錄檔的緩衝區大小 (以位元組為單位)。
  • tmp_table_size:MEMORY 儲存引擎建立的內部記憶體內暫存資料表大小上限,以及 MySQL 8.0.28 版起的 TempTable 儲存引擎。
  • key_buffer_size:用於索引區塊的緩衝區大小。MyISAM 資料表的索引區塊會經過緩衝處理,並由所有執行緒共用。
  • read_buffer_size:每個對 MyISAM 資料表執行循序掃描的執行緒,都會為掃描的每個資料表分配這個大小 (以位元組為單位) 的緩衝區。
  • read_rnd_buffer_size:這個變數用於從 MyISAM 資料表讀取資料、任何儲存引擎,以及多範圍讀取最佳化。
  • sort_buffer_size:每個必須執行排序的工作階段都會分配這個大小的緩衝區。sort_buffer_size 並非特定儲存引擎專用,而是以一般方式套用,用於最佳化。
  • join_buffer_size:緩衝區的大小下限,用於一般索引掃描、範圍索引掃描,以及不使用索引而執行完整資料表掃描的彙整作業。
  • max_connections:同時允許的用戶端連線數量上限。

排解記憶體用量過高的問題

  • 執行 SHOW PROCESSLIST,查看正在消耗記憶體的查詢。這個外掛程式會顯示所有已連結的執行緒和執行中的 SQL 陳述式,並嘗試進行最佳化。請留意「狀態」和「時間長度」欄。

    mysql> SHOW [FULL] PROCESSLIST;
    
    
  • 查看「BUFFER POOL AND MEMORY」部分的 SHOW ENGINE INNODB STATUS,瞭解目前的緩衝集區和記憶體用量,以便設定緩衝集區大小。

    mysql> SHOW ENGINE INNODB STATUS \G
    ----------------------
    BUFFER POOL AND MEMORY
    ----------------------
    Total memory allocated 398063986; in additional pool allocated 0
    Dictionary memory allocated 12056
    Buffer pool size 89129
    Free buffers 45671
    Database pages 1367
    Old database pages 0
    Modified db pages 0
    
  • 使用 MySQL 的 SHOW variables 指令檢查計數器值,即可取得臨時資料表數量、執行緒數量、資料表快取數量、髒頁、開啟的資料表,以及緩衝集區用量等資訊。

    mysql> SHOW variables like 'VARIABLE_NAME'
    

套用變更

分析不同元件的記憶體用量後,請在 MySQL 資料庫中設定適當的旗標。如要變更 MySQL 適用的 Cloud SQL 執行個體中的旗標,可以使用 Cloud de Confiance 控制台或 gcloud CLI。如要使用 Cloud de Confiance 控制台變更旗標值,請編輯「Flags」(旗標) 區段,選取旗標,然後輸入新值。

最後,如果記憶體用量仍偏高,且您認為執行中的查詢和旗標值已最佳化,請考慮增加執行個體大小,以免發生 OOM。

後續步驟