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

執行個體的 CPU 使用率偏高可能有多種原因,例如工作負載增加、大量交易、查詢速度緩慢和執行時間長的交易。

未充分配置的執行個體推薦工具會分析 CPU 使用率。如果 CPU 使用率在過去 30 天內有相當長的時間達到或超過 95%,推薦工具就會發出警示,並提供其他洞察資料,協助您解決問題。

本文說明如何檢查及改善 Cloud SQL for MySQL 執行個體,如果該執行個體的 CPU 使用率過高,就會由未充分配置的執行個體推薦工具判斷。

建議

CPU 使用率會隨著工作負載成比例增加。如要降低 CPU 使用率,請檢查執行中的查詢並進行最佳化。以下是檢查 CPU 用量的步驟。

  1. 查看 Threads_runningThreads_connected

    使用下列查詢,查看執行中的執行緒數量:

    > SHOW STATUS like 'Threads_%';
    

    Threads_runningThreads_connected 的子集。其餘執行緒處於閒置狀態。Threads_running 增加會導致 CPU 用量增加。建議您檢查這些執行緒正在執行的內容。

  2. 查看查詢狀態

    執行 SHOW PROCESSLIST 指令,查看目前的查詢。它會依序傳回所有已連結的執行緒,以及這些執行緒正在執行的 SQL 陳述式。

    mysql> SHOW [FULL] PROCESSLIST;
    

    請留意狀態和時間長度欄。檢查是否有許多查詢卡在相同狀態。

    • 如果許多執行緒顯示 Updating,可能會發生記錄鎖定爭用情形。請參閱下一個步驟。
    • 如果許多執行緒都顯示資料表中繼資料鎖定的 Waiting,請檢查查詢以瞭解資料表,然後尋找可能保留中繼資料鎖定的 DDL (例如 ALTER TABLE)。如果早期查詢 (例如長時間執行的 SELECT query) 正在保留資料表中繼資料鎖定,DDL 也可能會等待資料表中繼資料鎖定。
  3. 檢查記錄鎖定競爭

    當交易鎖定熱門索引記錄時,會阻止其他交易要求相同的鎖定。這可能會導致連鎖效應,導致許多要求卡住,並增加 Threads_running 的值。如要診斷鎖定爭用情形,請使用 information_schema.innodb_lock_waits 表格。

    以下查詢會列出每筆封鎖交易,以及相關封鎖交易的數量。

    SELECT 
      t.trx_id, 
      t.trx_state, 
      t.trx_started, 
      COUNT(distinct w.requesting_trx_id) AS blocked_trxs
    FROM 
      information_schema.innodb_lock_waits w 
    INNER JOIN information_schema.innodb_trx t
       ON t.trx_id = w.blocking_trx_id 
    GROUP BY t.trx_id,t.trx_state, t.trx_started
    ORDER BY t.trx_id;
    

    單一大型 DML 和許多並行的 DML 都可能會導致列鎖競爭。您可以透過下列步驟,從應用程式端進行最佳化:

    • 避免長時間交易,因為資料列鎖定會保留到交易結束為止。
    • 將單一大型 DML 分割成小型 DML。
    • 將單一資料列 DML 分批處理成小型區塊。
    • 盡量減少執行緒之間的爭用情形;舉例來說,如果應用程式程式碼使用連線集區,請將 ID 範圍指派給同一個執行緒。
  4. 找出長時間執行的交易

    • 使用SHOW ENGINE INNODB STATUS

      在「交易」部分,您可以看到所有未結交易,並以最早到最舊的順序排列。

      mysql> SHOW ENGINE INNODB STATUS\G
      ……
      ------------
      TRANSACTIONS
      ------------
      …
      ---TRANSACTION 245762, ACTIVE 262 sec
      2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
      MySQL thread id 9210, OS thread handle 140262286128896, query id 202218 localhost root
      

      請從最早的交易開始,找出下列問題的答案:

      • 這些交易執行多久了?
      • 有多少個鎖定結構體和列鎖定項目?
      • 有多少個復原記錄項目?
      • 連線主機和使用者是什麼?
      • 持續查詢的 SQL 陳述式為何?
    • 使用information_schema.innodb_trx

      如果 SHOW ENGINE INNODB STATUS 遭到截斷,則另一種檢查所有未結交易的方法是使用 information_schema.innodb_trx 資料表:

      SELECT
       trx_id, trx_state, 
       timestampdiff(second, trx_started, now()) AS active_secs, 
       timestampdiff(second, trx_wait_started, now()) AS wait_secs, trx_tables_in_use,
       trx_tables_locked, 
       trx_lock_structs, 
       trx_rows_locked, 
       trx_rows_modified, 
       trx_query 
      FROM information_schema.innodb_trx
      

    如果交易顯示目前執行時間較長的陳述式,您可以選擇停止這些交易以減輕伺服器的壓力,或是等待重要交易完成。如果較舊的交易記錄沒有顯示任何活動,請繼續執行下一個步驟,找出交易記錄。

  5. 檢查長時間執行交易的 SQL 陳述式

    • 使用performance_schema

      如要使用 performance_schema,您必須先開啟該功能。這項變更需要重新啟動執行個體。performance_schema 開啟後,請確認是否已啟用檢測工具和取用者:

      SELECT * FROM setup_consumers where name like 'events_statements_history';
      SELECT * FROM setup_instruments where name like 'statement/sql/%';
      
      

      如果尚未啟用,請按照下列步驟操作:

      UPDATE setup_instruments SET ENABLED = 'YES', timed = 'YES' WHERE NAME LIKE 'statement/%';
      UPDATE setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE 'events_statements%';
      

      根據預設,每個執行緒都會保留 performance_schema_events_statements_history_size 定義的最後 10 個事件。這些資訊通常足以在應用程式程式碼中找出交易。此參數不是動態參數。

      使用 mysql thread id (即 processlist_id) 查詢記錄事件:

      SELECT 
       t.thread_id, 
       event_name, 
       sql_text, 
       rows_affected, 
       rows_examined, 
       processlist_id, 
       processlist_time, 
       processlist_state 
      FROM events_statements_history h 
      INNER JOIN threads t 
      ON h.thread_id = t.thread_id 
      WHERE processlist_id = <mysql thread id>
      ORDER BY event_id;
      
    • 使用慢速查詢記錄

      為了進行偵錯,您可以將花費超過 N 秒的所有查詢記錄到慢速查詢記錄中。如要啟用慢速查詢記錄,請在Google Cloud 主控台或 gcloud CLI 的執行個體頁面中編輯執行個體設定,然後在Google Cloud 主控台或 gloud CLI 中使用記錄檢視器查看記錄。

  6. 檢查信號量爭用

    在並行環境中,共用資源的互斥鎖和讀/寫鎖定可能會成為爭用點,導致伺服器效能變慢。此外,如果訊號量化器的等待時間超過 600 秒,系統可能會當機,以便擺脫停滯狀態。

    如要查看信號量爭用情形,請使用下列指令:

    mysql> SHOW ENGINE INNODB STATUS\G
    ----------
    SEMAPHORES
    ----------
    ...
      --Thread 140396021667584 has waited at row0purge.cc line 862 for 241.00 seconds the semaphore:
      S-lock on RW-latch at 0x30c03e8 created in file dict0dict.cc line 1183
      a writer (thread id 140395996489472) has reserved it in mode  exclusive
      number of readers 0, waiters flag 1, lock_word: 0
      Last time read locked in file row0purge.cc line 862
      Last time write locked in file /build/mysql-5.7-FFKPr6/mysql-5.7-5.7.22/storage/innobase/dict/dict0stats.cc line 2376
    ...
    

    每個信號量等待作業中,第一行會顯示等待中的執行緒、特定信號量,以及等待時間長度。如果重複執行 SHOW ENGINE INNODB STATUS 時經常出現信號量等待,尤其是等待時間超過幾秒,表示系統正在執行並行處理瓶頸。

    不同工作負載和設定會有不同的競爭點。

    如果信號機經常位於 btr0sea.c,則自適應雜湊索引可能就是爭用的原因。請嘗試使用 Google Cloud 控制台或 gcloud CLI 停用該功能。

  7. 最佳化長 SELECT 查詢

    首先,請查看查詢。找出查詢的目標,以及取得結果的最佳方式。最佳查詢計畫是盡量減少資料存取次數的計畫。

    • 檢查查詢執行計畫:
    mysql> EXPLAIN <the query>;
    

    請參閱 MySQL 說明文件,瞭解如何解讀輸出內容並評估查詢效率。

    • 使用正確的索引

    檢查索引鍵欄,看看是否使用預期的索引。如果不是,請更新索引統計資料:

    mysql> analyze table <table_name> 
    

    增加用於計算索引統計資料的網頁樣本數量。詳情請參閱 MySQL 說明文件

    • 充分運用索引

    使用多欄索引時,請檢查 key_len 欄,瞭解是否充分運用索引來篩選記錄。最左欄必須是相等比較,且索引可用於第一個範圍條件,包括該條件在內。

    • 使用最佳化器提示

    另一種確保正確索引的方法,是使用索引提示資料表彙整順序的提示

  8. 避免使用 READ COMMITTED 產生長長的記錄清單

    記錄清單是指還原資料表空間中未清除的交易清單。交易的預設隔離等級為 REPEATABLE READ,這會要求交易在整個期間內讀取相同的快照。因此,SELECT 查詢會阻斷清除自查詢 (或交易) 開始以來所建立的復原記錄。因此,長的記錄清單會降低查詢效能。如要避免建立長的記錄清單,您可以將交易隔離層級變更為 READ COMMITTED。有了 READ COMMITTED,您就不需要再保留瀏覽記錄清單,以便提供一致的讀取檢視畫面。您可以為所有工作階段、單一工作階段或下一個單一交易,在全球變更交易隔離層級。詳情請參閱 MySQL 說明文件

  9. 調整伺服器設定

    伺服器設定有很多種方式。雖然完整的情況超出本文的範圍,但值得一提的是,伺服器也會回報各種狀態變數,提供相關設定的相關資訊。例如:

    • 如果 Threads_created/Connections 很大,請調整 thread_cache_size。適當的執行緒快取可縮短執行緒建立時間,並協助處理高並行工作負載。
    • 如果 Table_open_cache_misses/Table_open_cache_hits 並非瑣事,請調整 table_open_cache。在資料表快取中加入資料表可節省查詢執行時間,並在高並行環境中產生差異。
  10. 結束不必要的連線

    如果查詢似乎無效或不再需要,您可以停止查詢。如要瞭解如何識別及結束 MySQL 執行緒,請參閱「管理資料庫連線」。

最後,如果 CPU 使用率仍偏高,且查詢形成必要流量,建議您考慮增加執行個體的 CPU 資源,以免資料庫發生當機或停機情形。

後續步驟