執行個體耗用大量記憶體或發生記憶體不足 (OOM) 事件,是常見的問題。在記憶體使用率偏高的情況下,資料庫執行個體常會引發效能問題、停頓,甚至停機。
部分 MySQL 記憶體區塊會用於全域,這表示所有查詢工作負載都會共用記憶體位置、隨時占用記憶體,且只有在 MySQL 程序停止時才會釋出。部分記憶體區塊是以工作階段為基礎,也就是說,工作階段關閉後,該工作階段使用的記憶體也會釋回系統。
每當 MySQL 適用的 Cloud SQL 執行個體記憶體用量偏高時,Cloud SQL 會建議您找出使用大量記憶體的查詢或程序,並釋出記憶體。MySQL 記憶體用量分為三大類:
- 執行緒和程序記憶體消耗量
- 緩衝記憶體消耗量
- 快取記憶體消耗量
執行緒和程序記憶體消耗量
每個使用者工作階段耗用的記憶體,取決於該工作階段執行的查詢、緩衝區或快取,並由 MySQL 的工作階段參數控制。主要參數包括:
thread_stacknet_buffer_lengthread_buffer_sizeread_rnd_buffer_sizesort_buffer_sizejoin_buffer_sizemax_heap_table_sizetmp_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。