效能優化利器:剖析MySQL 5.7新特徵 sys schema
導讀:很多團隊在評估合適的時機切換到 MySQL 5.7,本文是李春在高可用架構群的分享,介紹 MySQL 5.7 新的效能分析利器。
李春,現任沃趣科技 MySQL 負責人,高階 MySQL 資料庫專家,從事 MySQL 開發和運維工作 8 年。在阿里巴巴擔任 MySQL 資料庫 leader 期間,主要負責應用架構的優化和部署,實現了阿里巴巴 3 億 產品 從 Oracle 小型機到 64 臺 MySQL 的平滑遷移。專注於研究 MySQL 複製、高可用、分散式和運維自動化相關領域。在大規模、分散式 MySQL 叢集管理、調優、快速定位和解決問題方面有豐富經驗。管理超過 1400 臺 MySQL 伺服器,近 3000 個例項。完成 MySQL 自動裝機系統、阿里巴巴 MySQL 標準化文件和操作手冊、MySQL 自動規範性檢查系統、MySQL 自動資訊採集系統等標準化文件和自動化運維工具。
sys schema 由來
Performance schema 引入
Oracle 早就有了 v$ 等一系列方便診斷資料庫效能的工具,MySQL DBA 只有羨慕嫉妒恨的份,但是 5.7 引入的 sys schema 緩解了這個問題,讓我們可以通過 sys schema 一窺 MySQL 效能損耗,診斷 MySQL 的各種問題。
說到診斷 MySQL 效能問題,不得不提在 MySQL 5.5 引入的 performance_schema,最開始引入時,MySQL 的 performance_schema 效能消耗巨大,隨著版本的更新和程式碼優化,5.7 的 performance_schema 對 MySQL 伺服器額外的消耗越來越少,我們可以放心的開啟 performance_shema 來收集 MySQL 資料庫的效能損耗。Tarique Saleem 同學測試了一下 sys schema 對 CPU 和 IO的額外消耗,基本在 1% – 3% 之間,有興趣的同學可以參考他的這篇 blog:
(CPU Bound, Sysbench Read Only Mode)
performance_schema 不僅由於他的效能消耗大著名,還由於其複雜難用而臭名昭著。5.7 上的 performance schema 已經有 87 張表了,每個表都是各種統計資訊的羅列;另外,他的這些表和 information_schema 中的部分表也纏夾不清,讓大家用得很不習慣。
sys schema VS performance schema VS information schema
現在 MySQL 在 5.7 又新增了sys schema,它和 performance_schema 和 information schema 到底是什麼關係?
- Information_schema 定位基本是 MySQL 元資料資訊,比如:TABLES 記錄了 MySQL 有哪些表,COLUMNS 記錄了各個表有哪些列 。
- performance_schema 記錄了 MySQL 實時底層效能消耗情況,比如:events_waits_current 記錄了 MySQL 各個執行緒當前在等待的 event。
雖然他們之間的這個定位區別並沒有那麼明顯:比如,Information_schema 的 innodb_locks 就記錄了 innodb 當前鎖的資訊,它並不是 MySQL 的元資料資訊。sys schema 最開始是 MarkLeith 同學為了方便讀取和診斷 MySQL 效能引入到 MySQL 的。所以 sys schema 定位應該是最清晰的:它包含一系列物件,這些物件能夠輔助 DBA 和開發人員瞭解 performance schema 和 information_schema 採集的資料。
sys schema 包含了什麼?
sys schema 包含一些物件,這些物件主要用於調優和故障分析。 包括:
- 將 performance schema 和 information schema 中的資料用更容易理解的方式來總結歸納出來的“檢視”。
- 提供 performance schema 和 information schema 配置或者生成分析報告類似操作的“儲存過程”
- sys schema 本身不採集和儲存什麼資訊,它只是為程式或者使用者提供一個更加方便的診斷系統性能和排除故障的“介面”。也就是說,查詢 performance schema 和 information schema 配置和提供格式化服務的“儲存函式” 。
- 避免使用者在 information schema 和 performance schema 中寫各種複雜的查詢來獲得到底誰鎖了誰,每個執行緒消耗的記憶體是多少 ( 檢視 memory_by_thread_by_current_bytes ),每個 SQL 執行了多少次,大致的執行時間是多少( 檢視 statements_with_runtimes_in_95th_percentile )等,這些 sys schema 都直接幫你寫好,你只需要直接查詢就好了。
- 編寫了一些現成的儲存過程,方便你:直接使用 diagnostics() 儲存過程建立用於診斷當前伺服器狀態的報告;使用 ps_trace_thread() 儲存過程建立對應執行緒的圖形化( .dot型別 )效能資料。
- 編寫了一些現成的儲存函式,方便你:直接使用 ps_thread_account() 儲存函式獲得發起這個執行緒的使用者,使用 ps_thread_trx_info() 來獲得某執行緒當前事務或者歷史執行過的語句( JSON 格式返回 )。
當然,你也可以在 sys schema 下增加自己用於診斷 MySQL 效能的“檢視”、“儲存過程”和“儲存函式”。
sys schema 舉例
怎麼利用 sys schema 來定位問題和診斷資料庫效能?這裡簡單舉一個 innodb 行鎖的例子來說明。
模擬行鎖
拿一個實際的場景來說 sys schema 能夠輔助我們分析當前資料庫上哪個 session 被鎖住了,並且提供“清理”鎖的語句。我們模擬一個表的某一行被鎖住的情況,假設表建立語句如下:
CREATE TABLE `test2` (
`id` int(11) NOT NULL,
`name` varchar(16) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`sex` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
有一條資料如下:
mysql > select * from test2;
+—-+———+——+——+
| id | name | age | sex |
+—-+———+——+——+
| 2 | pickup1 | 1 | 1 |
+—-+———+——+——+
我們分別在 session 1 和 session 2 上同時操作這條資料,這樣的話必然對同一行記錄相互有鎖死的情況,然後我們通過 session 3 來檢視 sys schema 裡面的 innodb_lock_waits,確定到底是誰鎖了誰,怎麼解鎖?操作步驟如下:
通過 sys.innodb_lock_waits 檢視 innodb 鎖表情況
對應的在 session 3上檢視到的記錄:
mysql > select * from sys.innodb_lock_waits\G
*************************** 1. row ***************************
wait_started: 2016-05-04 01:04:38
wait_age: 00:00:02
wait_age_secs: 2
locked_table: `test`.`test2`
locked_index: PRIMARY
locked_type: RECORD
waiting_trx_id: 5382
waiting_trx_started: 2016-05-04 00:24:21
waiting_trx_age: 00:40:19
waiting_trx_rows_locked: 4
waiting_trx_rows_modified: 0
waiting_pid: 3
waiting_query: update test2 set name=’pickup3′ where id=2
waiting_lock_id: 5382:31:3:3
waiting_lock_mode: X
blocking_trx_id: 5381
blocking_pid: 2
blocking_query: NULL
blocking_lock_id: 5381:31:3:3
blocking_lock_mode: X
blocking_trx_started: 2016-05-04 00:23:49
blocking_trx_age: 00:40:51
blocking_trx_rows_locked: 1
blocking_trx_rows_modified: 1
sql_kill_blocking_query: KILL QUERY 2
sql_kill_blocking_connection: KILL 2
這裡我們可以看到 3 號執行緒( waiting_pid: 3 )在等待 2 號執行緒( blocking_pid: 2 )的 X 鎖( blocking_lock_mode: X ),如果需要解鎖,需要殺掉 2 號執行緒( sql_kill_blocking_connection: KILL 2 )。
innodb_lock_waits 本質
其實 sys schema 的 innodb_lock_waits 只是 information schema 的檢視而已。
CREATE ALGORITHM = TEMPTABLE DEFINER = `mysql.sys`@`localhost` SQL SECURITY INVOKER VIEW `innodb_lock_waits` AS
SELECT
`r`.`trx_wait_started` AS `wait_started`,
TIMEDIFF(NOW(),
`r`.`trx_wait_started`) AS `wait_age`,
TIMESTAMPDIFF(
SECOND,
`r`.`trx_wait_started`,
NOW()) AS `wait_age_secs`,
`rl`.`lock_table` AS `locked_table`,
`rl`.`lock_index` AS `locked_index`,
`rl`.`lock_type` AS `locked_type`,
`r`.`trx_id` AS `waiting_trx_id`,
`r`.`trx_started` AS `waiting_trx_started`,
TIMEDIFF(NOW(),
`r`.`trx_started`) AS `waiting_trx_age`,
`r`.`trx_rows_locked` AS `waiting_trx_rows_locked`,
`r`.`trx_rows_modified` AS `waiting_trx_rows_modified`,
`r`.`trx_mysql_thread_id` AS `waiting_pid`,
`sys`.`format_statement`(`r`.`trx_query`) AS `waiting_query`,
`rl`.`lock_id` AS `waiting_lock_id`,
`rl`.`lock_mode` AS `waiting_lock_mode`,
`b`.`trx_id` AS `blocking_trx_id`,
`b`.`trx_mysql_thread_id` AS `blocking_pid`,
`sys`.`format_statement`(`b`.`trx_query`) AS `blocking_query`,
`bl`.`lock_id` AS `blocking_lock_id`,
`bl`.`lock_mode` AS `blocking_lock_mode`,
`b`.`trx_started` AS `blocking_trx_started`,
TIMEDIFF(NOW(),
`b`.`trx_started`) AS `blocking_trx_age`,
`b`.`trx_rows_locked` AS `blocking_trx_rows_locked`,
`b`.`trx_rows_modified` AS `blocking_trx_rows_modified`,
CONCAT(
‘KILL QUERY ‘,
`b`.`trx_mysql_thread_id`
) AS `sql_kill_blocking_query`,
CONCAT(‘KILL ‘,
`b`.`trx_mysql_thread_id`) AS `sql_kill_blocking_connection`
FROM
(
(
(
(
`information_schema`.`innodb_lock_waits` `w`
JOIN
`information_schema`.`innodb_trx` `b` ON((`b`.`trx_id` = `w`.`blocking_trx_id`))
)
JOIN
`information_schema`.`innodb_trx` `r` ON(
(`r`.`trx_id` = `w`.`requesting_trx_id`)
)
)
JOIN
`information_schema`.`innodb_locks` `bl` ON(
(
`bl`.`lock_id` = `w`.`blocking_lock_id`
)
)
)
JOIN
`information_schema`.`innodb_locks` `rl` ON(
(
`rl`.`lock_id` = `w`.`requested_lock_id`
)
)
)
ORDER BY
`r`.`trx_wait_started`
innodb_lock_waits和x\$innodb_lock_waits區別
有心的同學可能會注意到,sys schema 裡面有 innodb_lock_waits 和 x\$innodb_lock_waits。 其實 sys schema 的這些檢視大部分都成對出現,其中一個的名字除了 x\$ 字首以外跟另外一個是一模一樣的。例如,host_summmary_by_file_io 檢視分析彙總的是根據主機彙總的檔案 IO 情況,並將延遲從皮秒( picoseconds )轉換成更加易讀值( 帶單位 )顯示出來:
mysql> SELECT * FROM host_summary_by_file_io;
+————+——-+————+
| host | ios | io_latency |
+————+——-+————+
| localhost | 67570 | 5.38 s |
| background | 3468 | 4.18 s |
+————+——-+————+
而 x\$host_summary_by_file_io 檢視分析彙總的是同樣的資料,但是顯示的是未格式化過的皮秒( picosecond )延遲值
mysql> SELECT * FROM x$host_summary_by_file_io;
+————+——-+—————+
| host | ios | io_latency |
+————+——-+—————+
| localhost | 67574 | 5380678125144 |
| background | 3474 | 4758696829416 |
+————+——-+—————+
沒有 x\$ 字首的檢視是為了提供更加友好,對人更加易讀的輸出格式。帶 x\$ 字首的檢視顯示了資料原始格式,它方便其他工具基於這些資料進行自己的處理。需要了解非 x\$ 和 x\$ 檢視的不同點的進一步資訊。
Q&A
提問:sys schema 只是在 performance_schema 和 information_schema 之上建立檢視和儲存過程?
李春:對,sys schema 主要針對的其實是 iperformance schema,有部分 information schema 的表也會整理到 sys schema 中統一展現。
提問:執行 KILL 2 殺掉 2 執行緒?blocking_lock_mode: X 的 X 什麼意思?
李春:blocking_lock_mode 的 X 是指 X 鎖,exclusive 鎖,排它鎖,跟它對應的是 S 鎖,共享鎖。kill 2 是殺掉 2 號執行緒,這樣可以將鎖釋放,讓被鎖的這個執行緒正常執行下去。
提問:可以放心的開啟 performance_schema,為何不使用 performance_schema 再造一個 sys schema?
李春:performance schema 是 MySQL 採集資料庫效能的儲存空間。sys schema 其實只是對 performance schema 多個表 join 和整合。兩者的定位有所不同,如果直接放在 performance schema 中,分不清哪些是基表,哪些是檢視,會比較混淆。
提問:pt-query-digest 這些工具的有開始使用 sys schema 嗎?
李春:沒有,pt-query-digest 主要用於分析慢查和 tcpdump 的結果,跟 sys schema 的定位有部分重疊的地方,sys schema 會分析得更細,更核心,更偏底層一些,pt-query-digest 主要還是從慢查和 tcpdump 中抽取 SQL 來格式化展現。
提問:阿里這麼多資料庫例項,使用什麼運維工具?分散式事務又是怎麼解決的呢?
李春:阿里內部有非常多的運維工具,dbfree,idb 等,用於資料庫資源池管理,資料庫脫敏,開發測試庫同步,資料庫訂正,表結構變更等。分散式事務主要通過業務上的修改去遮蔽掉,比如:電影買票並不是你選了座位和付款就必須在一個事務裡面,搶票,選座,付款分別是自己的子事務,系統耦合性比較弱,相互通知解決問題。
提問:Oracle 有 v$,MySQL 有 x$ ?兩個 $ 是完成相似功能的嗎?
李春:MySQL 的 x$ 可以說是仿照 Oracle 的 v$ 來做的,但是目前離 Oracle 的那麼強大的資料庫診斷功能還有一些距離。
提問:資料庫脫敏能否簡單介紹下實現方式?
李春:開發測試人員無法訪問線上資料庫,需要通過一個專門的 idb 來訪問,而 idb 系統每個欄位都有密級定義,滿足許可權的才能被訪問;這個系統頁控制了使用者是否可以訪問某個表,可以訪問資料表的行數,只有主管同意了,使用者才能訪問某個表的資料,並且加密資料是以*顯示的。
文章出處:高可用架構(ArchNotes)
推薦閱讀