【編者按】本文作者為 John Matson,主要介紹 mysql 性能監控應該關注的 4 大指標。 文章系國內 ITOM 管理平台 OneAPM 編譯呈現。
MySQL 是什么?
MySQL 是現而今最流行的開源關系型數據庫服務器。由 Oracle 所有,MySQL 提供了可以免費下載的社區版及包含更多特性與支持的商業版。從 1995 年首發以來,MySQL 衍生出多款備受矚目的分支,諸如具有相當競爭力的 MariaDB 及 Percona。
關鍵 MySQL 統計指標
如果你的數據庫運行緩慢,或者出於某種原因無法響應查詢,技術棧中每個依賴數據庫的組件都會遭受性能問題。為了保證數據庫的平穩運行,你可以主動監控以下四個與性能及資源利用率相關的指標:
-
查詢吞吐量
-
查詢執行性能
-
連接情況
-
緩沖池使用情況
MySQL 用戶可以接觸到數百個數據庫指標,因此,在本文中,筆者將專注於能幫助我們實時了解數據庫健康與性能的關鍵指標。
本文參考了我們在監控入門系列文章中介紹的指標術語,后者為指標收集與告警提供了基礎框架。
不同版本與技術的兼容性
本系列文章討論的一些監控策略只適用於 MySQL 5.6 與 5.7 版本。這些版本間的差異將在后文中提及。
本文列出的大多數指標與監控策略同樣適用於與 MySQL 兼容的技術,諸如 MariaDB 與 Percona 服務器,不過帶有一些明顯的差別。例如,MySQL Workbench(工作台) 中的一些特性(在本系列第二篇中有詳細介紹)就與當下的一些 MariaDB 版本不兼容。
Amazon RDS 用戶應該查看我們專門制作的 MySQL 在 RDS 以及與 MySQL 兼容的 Amazon Aurora監控手冊。
查詢吞吐量
名稱 | 描述 | 指標類型 | 可用性 |
---|---|---|---|
Questions | 已執行語句(由客戶端發出)計數 | Work:吞吐量 | 服務器狀態變量 |
Com_select | SELECT 語句 | Work:吞吐量 | 服務器狀態變量 |
Writes | 插入,更新或刪除 | Work:吞吐量 | 根據服務器狀態變量計算得到 |
在監控任何系統時,你最關心的應該是確保系統能夠高效地完成工作。數據庫的工作是運行查詢,因此在本例中,你的首要任務是確保 MySQL 能夠如期執行查詢。
MySQL 有一個名為 Questions
的內部計數器(根據 MySQL 用語,這是一個服務器狀態變量),客戶端每發送一個查詢語句,其值就會加一。由 Questions
指標帶來的以客戶端為中心的視角常常比相關的Queries
計數器更容易解釋。作為存儲程序的一部分,后者也會計算已執行語句的數量,以及諸如PREPARE
和 DEALLOCATE PREPARE
指令運行的次數,作為服務器端預處理語句的一部分。
通過以下指令,查詢諸如 Questions
或 Com_select
服務器狀態變量的值:
SHOW GLOBAL STATUS LIKE "Questions"; +---------------+--------+ | Variable_name | Value | +---------------+--------+ | Questions | 254408 | +---------------+--------+
你也可以監控讀、寫指令的分解情況,從而更好地理解數據庫的工作負載、找到可能的瓶頸。通常,讀取查詢會由 Com_select
指標抓取,而寫入查詢則可能增加三個狀態變量中某一個的值,這取決於具體的指令:
Writes = Com_insert + Com_update + Com_delete
應該設置告警的指標:Questions
當前的查詢速率通常會有起伏,因此,如果基於固定的臨界值,查詢速率常常不是一個可操作的指標。但是,對於查詢數量的突變設置告警非常重要——尤其是查詢量的驟降,可能暗示着某個嚴重的問題。
查詢性能
名稱 | 描述 | 指標類型 | 可用性 |
---|---|---|---|
查詢運行時間 | 每種模式下的平均運行時間 | Work:性能 | 性能模式查詢 |
查詢錯誤 | 出現錯誤的 SQL 語句數量 | Work:錯誤 | 性能模式查詢 |
Slow_queries | 超過可配置的long_query_time 限制的查詢數量 |
Work:性能 | 服務器狀態變量 |
MySQL 用戶監控查詢延遲的方式有很多,既可以通過 MySQL 內置的指標,也可以通過查詢性能模式。從 MySQL 5.6.6 版本開始默認啟用,MySQL 的 performance_schema
數據庫中的表格存儲着服務器事件與查詢執行的低水平統計數據。
性能模式語句摘要
性能模式的 events_statements_summary_by_digest
表格中保存着許多關鍵指標,抓取了與每條標准化語句有關的延遲、錯誤和查詢量信息。從該表截取的一行樣例顯示,某條語句被執行了兩次,平均執行用時為 325 毫秒(所有計時器的測量值都以微微秒為單位):
*************************** 1. row *************************** SCHEMA_NAME: employees DIGEST: 0c6318da9de53353a3a1bacea70b4fce DIGEST_TEXT: SELECT * FROM `employees` WHERE `emp_no` > ? COUNT_STAR: 2 SUM_TIMER_WAIT: 650358383000 MIN_TIMER_WAIT: 292045159000 AVG_TIMER_WAIT: 325179191000 MAX_TIMER_WAIT: 358313224000 SUM_LOCK_TIME: 520000000 SUM_ERRORS: 0 SUM_WARNINGS: 0 SUM_ROWS_AFFECTED: 0 SUM_ROWS_SENT: 520048 SUM_ROWS_EXAMINED: 520048 ... SUM_NO_INDEX_USED: 0 SUM_NO_GOOD_INDEX_USED: 0 FIRST_SEEN: 2016-03-24 14:25:32 LAST_SEEN: 2016-03-24 14:25:55
摘要表會標准化所有語句(如上面的 DIGEST_TEXT
一欄所示),忽略數據值,規范化空格與大小寫,因此,下面的兩條查詢會被認為是相同的:
select * from employees where emp_no >200;
SELECT * FROM employees WHERE emp_no > 80000;
想要按模式抽取出以微秒為單位的平均運行時間,你可以這樣查詢性能模式:
SELECT schema_name , SUM(count_star) count , ROUND( (SUM(sum_timer_wait) / SUM(count_star)) / 1000000) AS avg_microsec FROM performance_schema.events_statements_summary_by_digest WHERE schema_name IS NOT NULL GROUP BY schema_name; +--------------------+-------+--------------+ | schema_name | count | avg_microsec | +--------------------+-------+--------------+ | employees | 223 | 171940 | | performance_schema | 37 | 20761 | | sys | 4 | 748 | +--------------------+-------+--------------+
相似地,按模式計算出現錯誤的語句總數,可以這么做:
SELECT schema_name , SUM(sum_errors) err_count FROM performance_schema.events_statements_summary_by_digest WHERE schema_name IS NOT NULL GROUP BY schema_name; +--------------------+-----------+ | schema_name | err_count | +--------------------+-----------+ | employees | 8 | | performance_schema | 1 | | sys | 3 | +--------------------+-----------+
sys 模式
用上面的方式查詢性能模式能以編程方式有效地從數據庫中檢索出指標。然而,對於特別查詢或調查,使用 MySQL 的 sys 模式通常更為簡單。sys 模式以人們更易讀的格式提供了一個有條理的指標集合,使得對應的查詢更加簡單。例如,想要找出最慢的語句(運行時間在 95 名開外):
SELECT * FROM sys.statements_with_runtimes_in_95th_percentile;
或者查看哪些標准化語句出現了錯誤:
SELECT * FROM sys.statements_with_errors_or_warnings;
在 sys 模式的文檔中,詳細介紹了許多有用的例子。sys 模式在 MySQL 5.7.7 版本中是默認包含的。不過,MySQL 5.6 用戶通過簡單的幾個指令就能安裝它。
慢查詢
除了性能模式與 sys 模式中豐富的性能數據,MySQL 還提供了一個 Slow_queries
計數器,每當查詢的執行時間超過 long_query_time
參數指定的值之后,該計數器就會增加。默認情況下,該臨界值設置為 10 秒。
SHOW VARIABLES LIKE 'long_query_time'; +-----------------+-----------+ | Variable_name | Value | +-----------------+-----------+ | long_query_time | 10.000000 | +-----------------+-----------+
long_query_time
參數的值可通過一條指令進行調整。例如,將慢查詢臨界值設置為 5 秒:
SET GLOBAL long_query_time = 5;
(請注意,你可能要關閉會話,再重新連接至數據庫,這些更改才能在會話層生效。)
調查查詢性能問題
如果你的查詢運行得比預期要慢,很可能是某條最近修改的查詢在搗鬼。如果沒有發現特別緩慢的查詢,接下來就該評估系統級指標,尋找核心資源(CPU,磁盤 I/O,內存以及網絡)的限制。CPU 飽和與 I/O 瓶頸是常見的問題根源。你可能還想檢查 Innodb_row_lock_waits
指標,該指標記錄着 InnoDB 存儲引擎不得不停下來獲得某行的鎖定的次數。從 MySQL 5.5 版本起,InnoDB 就是默認的存儲引擎,MySQL 對 InnoDB 表使用行級鎖定。
為了提高讀取與寫入操作的速度,許多用戶會想通過調整 InnoDB 使用的緩沖池大小來緩存表與索引數據。本文的第二部分會對監控與調整緩沖池大小做詳細解讀。
應該設置告警的指標:
-
查詢運行時間:管理關鍵數據庫的延遲至關重要。如果生產環境中數據庫的平均查詢運行時間開始下降,應該尋找數據庫實例的資源限制,行鎖或表鎖間可能的爭奪,以及客戶端查詢模式的變化情況。
-
查詢錯誤:查詢錯誤的猛增可能暗示着客戶端應用或數據庫本身的問題。你可以使用 sys 模式快速查找可能導致問題的查詢。例如,列舉出返回錯誤數最多的 10 條標准化語句:
SELECT * FROM sys.statements_with_errors_or_warnings ORDER BY errors DESC LIMIT 10;
-
Slow_queries
:如何定義慢查詢(並由此設置long_query_time
參數)取決於你的用戶案例。但是,無論你如何定義 “慢”,你都會想知道慢查詢的數量是否超出了基准水平。為了找出真正執行緩慢的查詢,你可以詢問 sys 模式,或深入了解 MySQL 提供的慢查詢日志(該功能默認是禁用的)。有關啟用並讀取慢查詢日志的更多信心,請參考 MySQL 文檔。
連接
名稱 | 描述 | 指標類型 | 可用性 |
---|---|---|---|
Threads_connected | 當前開放的連接 | 資源: 利用率 | 服務器狀態變量 |
Threads_running | 當前運行的連接 | 資源: 利用率 | 服務器狀態變量 |
Connection_errors_internal | 由服務器錯誤導致的失敗連接數 | 資源: 錯誤 | 服務器狀態變量 |
Aborted_connects | 嘗試與服務器進行連接結果失敗的次數 | 資源: 錯誤 | 服務器狀態變量 |
Connection_errors_max_connections | 由 max_connections 限制導致的失敗連接數 |
資源: 錯誤 | 服務器狀態變量 |
檢查並設置連接限制
監控客戶端連接情況相當重要,因為一旦可用連接耗盡,新的客戶端連接就會遭到拒絕。MySQL 默認的連接數限制為 151,可通過下面的查詢加以驗證:
SHOW VARIABLES LIKE 'max_connections'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | max_connections | 151 | +-----------------+-------+
MySQL 的文檔指出,健壯的服務器應該能夠處理成百上千的連接數。
“常規情況下,Linux 或 Solaris 應該能夠支持 500 到 1000 個同時連接。如果可用的 RAM 較大,且每個連接的工作量較低或目標響應時間較為寬松,則最多可處理 10000 個連接。而 Windows 能處理的連接數一般不超過 2048 個,這是由於該平台上使用的 Posix 兼容層。”
連接數限制可以在系統運行時進行調整:
SET GLOBAL max_connections = 200;
然而,此設置會在服務器重啟時恢復為默認值。想要永久地改變連接數限制,可以在 my.cnf
配置文件中添加如下配置(查看本文了解如何定位配置文件):
max_connections = 200
監控連接使用率
MySQL 提供了 Threads_connected
指標以記錄連接的線程數——每個連接對應一個線程。通過監控該指標與先前設置的連接限制,你可以確保服務器擁有足夠的容量處理新的連接。MySQL 還提供了Threads_running
指標,幫助你分隔在任意時間正在積極處理查詢的線程與那些雖然可用但是閑置的連接。
如果服務器真的達到 max_connections
限制,它就會開始拒絕新的連接。在這種情況下,Connection_errors_max_connections
指標就會開始增加,同時,追蹤所有失敗連接嘗試的Aborted_connects
指標也會開始增加。
MySQL 提供了許多有關連接錯誤的指標,幫助你調查連接問題。Connection_errors_internal
是個很值得關注的指標,因為該指標只會在錯誤源自服務器本身時增加。內部錯誤可能反映了內存不足狀況,或者服務器無法開啟新的線程。
應該設置告警的指標
-
Threads_connected
:當所有可用連接都被占用時,如果一個客戶端試圖連接至 MySQL,后者會返回 “Too many connections(連接數過多)” 錯誤,同時將Connection_errors_max_connections
的值增加。為了防止出現此類情況,你應該監控可用連接的數量,並確保其值保持在max_connections
限制以內。 -
Aborted_connects
:如果該計數器在不斷增長,意味着用戶嘗試連接到數據庫的努力全都失敗了。此時,應該借助Connection_errors_max_connections
與Connection_errors_internal
之類細粒度高的指標調查該問題的根源。
緩沖池使用情況
名稱 | 描述 | 指標類型 | 可用性 |
---|---|---|---|
Innodb_buffer_pool_pages_total | 緩沖池中的總頁數 | 資源: 利用率 | 服務器狀態變量 |
緩沖池使用率 | 緩沖池中已使用頁數所占的比率 | 資源: 利用率 | 根據服務器狀態變量計算得到 |
Innodb_buffer_pool_read_requests | 向緩沖池發送的請求 | 資源: 利用率 | 服務器狀態變量 |
Innodb_buffer_pool_reads | 緩沖池無法滿足的請求 | 資源: 飽和度 | 服務器狀態變量 |
MySQL 默認的存儲引擎 InnoDB 使用了一片稱為緩沖池的內存區域,用於緩存數據表與索引的數據。緩沖池指標屬於資源指標,而非工作指標,前者更多地用於調查(而非檢測)性能問題。如果數據庫性能開始下滑,而磁盤 I/O 在不斷攀升,擴大緩沖池往往能帶來性能回升。
檢查緩沖池的大小
默認設置下,緩沖池的大小通常相對較小,為 128MiB。不過,MySQL 建議可將其擴大至專用數據庫服務器物理內存的 80% 大小。然而,MySQL 也指出了一些注意事項:InnoDB 的內存開銷可能提高超過緩沖池大小 10% 的內存占用。並且,如果你耗盡了物理內存,系統會求助於分頁,導致數據庫性能嚴重受損。
緩沖池也可以划分為不同的區域,稱為實例。使用多個實例可以提高大容量 (多 GiB) 緩沖池的並發性。
緩沖池大小調整操作是分塊進行的,緩沖池的大小必須為塊的大小乘以實例的數目再乘以某個倍數。
innodb_buffer_pool_size = N * innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances
塊的默認大小為 128 MiB,但是從 MySQL 5.7.5 開始可以自行配置。以上兩個參數的值都可以通過如下方式進行檢查:
SHOW GLOBAL VARIABLES LIKE "innodb_buffer_pool_chunk_size"; SHOW GLOBAL VARIABLES LIKE "innodb_buffer_pool_instances";
如果 innodb_buffer_pool_chunk_size
查詢沒有返回結果,則表示在你使用的 MySQL 版本中此參數無法更改,其值為 128 MiB。
在服務器啟動時,你可以這樣設置緩沖池的大小以及實例的數量:
$ mysqld --innodb_buffer_pool_size=8G
--innodb_buffer_pool_instances=16
在 MySQL 5.7.5 版本,你可以通過 SET
指令在系統運行時修改緩沖池的大小,並精確到字節數。例如,假設有兩個緩沖池實例,你可以將其總大小設置為 8 GiB,這樣每個實例的大小即為 4 GiB。
SET GLOBAL innodb_buffer_pool_size=8589934592;
關鍵的 InnoDB 緩沖池指標
MySQL 提供了許多關於緩沖池及其利用率的指標。其中一些有用的指標能夠追蹤緩沖池的總大小,緩沖池的使用量,以及其處理讀取操作的效率。
指標 Innodb_buffer_pool_read_requests
及 Innodb_buffer_pool_reads
對於理解緩沖池利用率都非常關鍵。Innodb_buffer_pool_read_requests
追蹤合理讀取請求的數量,而Innodb_buffer_pool_reads
追蹤緩沖池無法滿足,因而只能從磁盤讀取的請求數量。我們知道,從內存讀取的速度比從磁盤讀取通常要快好幾個數量級,因此,如果 Innodb_buffer_pool_reads
的值開始增加,意味着數據庫性能大有問題。
緩沖池利用率是在考慮擴大緩沖池之前應該檢查的重要指標。利用率指標無法直接讀取,但是可以通過下面的方式簡單地計算得到:
(Innodb_buffer_pool_pages_total - Innodb_buffer_pool_pages_free) / Innodb_buffer_pool_pages_total
如果你的數據庫從磁盤進行大量讀取,而緩沖池還有許多閑置空間,這可能是因為緩存最近才清理過,還處於熱身階段。如果你的緩沖池並未填滿,但能有效處理讀取請求,則說明你的數據工作集相當適應目前的內存配置。
然而,較高的緩沖池利用率並不一定意味着壞消息,因為舊數據或不常使用的數據會根據 LRU 算法 自動從緩存中清理出去。但是,如果緩沖池無法有效滿足你的讀取工作量,這可能說明擴大緩存的時機已至。
將緩沖池指標轉化為字節
大多數緩沖池指標都以內存頁面為單位進行記錄,但是這些指標也可以轉化為字節,從而使其更容易與緩沖池的實際大小相關聯。例如,你可以使用追蹤緩沖池中內存頁面總數的服務器狀態變量找出緩沖池的總大小(以字節為單位):
Innodb_buffer_pool_pages_total * innodb_page_size
InnoDB 頁面大小是可調整的,但是默認設置為 16 KiB,或 16,384 字節。你可以使用 SHOW VARIABLES
查詢了解其當前值:
SHOW VARIABLES LIKE "innodb_page_size";
結論
在本文中,我們介紹了許多你應該加以監控從而了解 MySQL 活動與性能表現的重要指標。如果你正在躊躇 MySQL 監控方案,抓取下面列出的指標能讓你真正理解數據庫的使用模式與可能的限制情況。這些指標也能幫助你發現,何時擴展服務器內存或將數據庫移至更為強大的主機,從而保持良好的應用性能。
-
查詢吞吐量
-
查詢延遲與錯誤
-
客戶端連接與錯誤
-
緩沖池利用率
鳴謝
非常感謝來自 Oracle 的 Dave Stokes 與 VividCortex 的 Ewen Fortune,他們在本文發布之前提供了許多寶貴的反饋意見。
本文系 OneAPM 工程師編譯整理。OneAPM Cloud Insight 集監控、管理、計算、協作、可視化於一身,幫助所有 IT 公司,減少在系統監控上的人力和時間成本投入,讓運維工作更加高效、簡單。想閱讀更多技術文章,請訪問 OneAPM 官方技術博客。
原文地址:https://www.datadoghq.com/blog/monitoring-mysql-performance-metrics/
http://blog.oneapm.com/apm-tech/754.html
http://blog.oneapm.com/apm-tech/755.html