作者:王悅
Copyright (C) 2021 wingYue
本文來源:原創投稿
*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。
最近使用了 bcc 工具集中的 dbslower ,這個工具可以探測 MySQL 指定閾值下的慢 query ,使用非常方便。
使用舉例:
因為這個工具是一個 python 指令碼,於是開啟學習一下內部的機制。
首先開始的一段是一些使用案例:
這裡我們關注這兩個:
dbslower mysql -p 480 -m 30 # trace MySQL queries slower than 30ms
dbslower mysql -x $(which mysqld) # trace MySQL queries with uprobes
同樣是檢測慢日誌,一種是提供 pid ,另一種是提供二進位制檔案地址,粗看之下只是使用方式的不同,其實其中完全走向了不同的機制。
我們接著看下一段
這一段是用來確認最終使用的機制 mode ,如果提供 pid ,那麼 mode=“MYSQL57” ,如果提供的是二進位制地址,那麼 mode=“USDT” 。
這裡 USDT 指的是(Userland Statically Defined Tracing)使用者態靜態探針,也就是說,當使用 pid 時,指令碼實際使用了 USDT 靜態探針機制,而使用二進位制檔案時,則使用了另一種動態探針機制。要繼續理解下面的段落,我們先來看一下靜態探針和動態探針到底是指什麼。
探針的分類
探針大致可以分為兩類,靜態探針和動態探針。
靜態探針就比如我們上文看到的 USDT ,對應 MySQL 中,則是 MySQL DTrace 的實現。這類探針需要事先在程式碼中定義並在編譯時開啟。
需要說明的是 MySQL DTrace 在 MySQL5.7.18 被棄用,在 MySQL8.0 被徹底刪除,所以我們只能在早期的版本中進行 DTrace 檢測。MySQL 的 DTrace 包含了很多的探針,比如 query-start 和 query-done 用於檢測一條語句的執行過程,比如 connection-start 和 connection-done 用於檢測客戶端連線的過程,這些探針都是需要在程式碼中實現的。且啟用探針需要增加編譯引數 -DENABLE_DTRACE=1。
我們來看一個官方示例直觀的瞭解一下:
https://dev.MySQL.com/doc/ref...
這裡使用了 query-start 和 query-done 這兩個探針,來獲取語句執行時間
編輯 DTrace 指令碼
執行效果
可惜靜態探針在新版的 MySQL 上已經沒有了,我們就不去深究了。
除了靜態探針,還有一類是動態探針,就比如bfs技術中經常使用到的 uprobes 和 kprobes ,這類探針比較靈活,可以在程式執行時動態新增,如果熟悉程式碼,可謂是神器。
我使用 MySQL8.0 作為實驗環境,簡單寫了一個利用 uprobes 列印 query 的示例。
這裡的關鍵在於{ printf("%s\n", str(*arg1)); }
,意思是列印出 dispatch_command方 法的第二個引數指向的內容。
同樣的原理,變更一下函式,能動態列印任何我們想要的變數內容,或者利用探針寫一些 bpf 指令碼,能夠實現許多功能,十分好用。
好了,回到我們的 dbslower 指令碼上來。實際上這個指令碼同時實現了靜態探針和動態探針兩種機制。
當我們使用 pid 時,比如dbslower MySQL -p 480 -m 30
,變數 mode 值為 “USDT” ,走入了上圖的 else 段落,即利用了query__start
和query__done
這兩個靜態探針,當探針被觸發時,掛載到對應的處理函式query_start
和query_end
,這兩個處理函式中的邏輯很簡單,就是獲取對應的 query 內容,記錄時間等,有興趣的話可以去指令碼中檢視,這裡就不羅列了。
另一種情況,當我們使用二進位制檔案地址時,比如dbslower MySQL -x $(which MySQLd)
,變數 mode 值為 “MYSQL57” ,走入了上圖的if段落,mysql_func_name 在指令碼中被賦予的值是 dispatch_command 函式,即利用了 bfp ,在函式 dispatch_command 執行前後插入了動態探針,同樣的,當探針被觸發時,掛載到對應的處理函式query_start
和query_end
進行時間的計算。
總結
- dbslower 指令碼利用探針檢測 MySQL query 執行時間。
- 當 dbslower 使用 pid 時,實際利用了靜態探針機制,需要在編譯時開啟-DENABLE_DTRACE=1 ,且該機制在 MySQL 新版本中被刪除了,需要特別注意。
- 當 dbslower 使用 mysqld 二進位制路徑時,實際是利用了動態探針機制,動態探針可以在程式執行時動態新增,無論新舊版本的 MySQL 都可以使用。
- bpf 的 uprobe 動態探針十分靈活,熟練使用之後,對一些故障排查場景是一大利器,缺點是多數情況下需要對照程式碼進行配置。