執行個體通常會耗用大量記憶體或產生記憶體不足 (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 分鐘以上穩定維持在較低值,MySQL 會逐步將 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 的大小。預設門檻百分比介於 90% 到 97% 之間,視執行個體的 RAM 容量而定。如要修改門檻,請將 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 執行個體。
調整邏輯
受管理緩衝區集區不會將 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 的值時,變更不會反映在 Google Cloud 控制台中。如要查看啟用代管緩衝區集區時 innodb_buffer_pool_size 的目前值,可以使用 MySQL 用戶端:
mysql> SHOW GLOBAL VARIABLES LIKE 'innodb_buffer_pool_size';
限制
縮減緩衝區集區大小不一定能避免 OOM 錯誤。舉例來說,某些工作負載可能會消耗無法持續的記憶體,或以突然的速度增加;某些 Cloud SQL 執行個體可能資源不足,或緩衝區集區可能未預熱。Cloud SQL 可能無法快速釋出足夠的記憶體,以因應記憶體工作負載的突然變化。此外,Cloud SQL 無法處理其他記憶體旗標的設定錯誤值。
監控
您可以在 MySQL 錯誤記錄中監控受管理緩衝區集區。在 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.
您可以設定記錄指標,追蹤一段時間內的受管理緩衝區集區調整事件。
使用 Metrics Explorer 找出記憶體用量
您可以在 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;查看
SHOW ENGINE INNODB STATUS部分的BUFFER POOL AND MEMORY,瞭解目前的緩衝區集區和記憶體用量,有助於設定緩衝區集區大小。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 執行個體中變更旗標,可以使用 Google Cloud 控制台或 gcloud CLI。如要使用 Google Cloud 控制台變更旗標值,請編輯「Flags」部分,選取旗標並輸入新值。
最後,如果記憶體用量仍偏高,且您認為查詢和旗標值已最佳化,請考慮增加執行個體大小,以免發生 OOM 錯誤。