使用插桩技术解决慢查询测试问题
原文由zlulu發表于TesterHome社區,原文鏈接
緣起
前段時間,我負責測試的系統在生產環境運行出現問題。該系統對于響應時間要求較高,問題發生的時候并發很高,出現大量請求超時,超時請求比例隨時間推遲越來越高,最后幾乎全部請求都失敗。滾動重啟了所有進程后,很快又出現超時情況。
后經過排查,發現是新版本實現某個功能時修改了一個數據庫查詢語句,修改后該查詢語句的查詢條件未使用到索引字段,而所查詢的表生產環境中體量巨大,因此這個查詢操作耗時從毫秒級變成了秒級,也就是形成了所謂的慢查詢,再加上大量并發,悲劇就發生了。
事件發生后,我們測試團隊進行了反思,這么嚴重的問題為何測試環境沒有發現?總結了兩點原因,一是,測試環境進行功能測試時并發量不高,即使單個請求變慢也不會發生超時現象;二是,測試環境數據庫表的數據量較生產環境小很多,所以單個查詢操作比生產快很多,這樣壓力測試中請求也極少超時。
求索
綜上所述,想要在測試過程中人為識別一個慢查詢很難,為了杜絕這類問題再次發生,在后續版本測試中我們做了一些嘗試。
因為我們內部本來就有使用代碼掃描的工具,每個版本都會通過掃描來識別一些問題,所以我們首先想到了通過靜態掃描原代碼,撈出所有的數據庫查詢語句然后進行分析。實際操作后發現,我們系統在數據庫操作上大量使用框架,不同模塊使用的框架還不同,撈出的數據庫語句千奇百怪,且包含代碼元素,并不是能直接執行的語句,對于大型系統而言,人工去分析這些語句工作量太大,這種方法并不可行。
然后我們想到,可以從數據庫側來解決這個問題,通過開啟 Mysql 的慢查詢日志開關,將功能測試過程中大于 long_query_time 配置時間的數據庫查詢操作都記錄下來,再逐個分析是否存在慢查詢問題。過程中我們確實抓到了很多執行較慢的查詢語句,但經過分析后發現,這些語句絕大部分都是測試人員人工查詢數據庫的操作,更遺憾的是,由于測試數據數量級較少,之前發生生產問題的查詢語句在測試環境的執行時間并沒有超過 long_query_time,由此并不能被識別出來。由此可見,這種方法誤報和漏報概率很大,也不可行。
革新
現有工具無法滿足我們識別慢查詢語句的需求,于是我們決定自己做了一套工具。通過大量的分析和實驗,我們得到了一個高效、準確性、且通用性極好的解決方案:
?
經過分析,識別慢查詢語句需要解決兩個問題:一是,如何獲得系統執行是查詢語句;二是,如何分析某個查詢是否是慢查詢。
解決第一個問題,我們想到了使用插樁技術。
對于一個查詢操作,不管上層應用代碼如何編寫、或使用何種數據庫框架,這個操作最終會與目標數據庫交互,而交互的時候它一定必須是一個標準的 SQL 語句。基于這一點,我們對這個應用進行了全面的分析,我們的系統部署在 Jboss 上,通過層層剖析,我們找到了這個實際執行查詢操作數據庫交互的方法,位于 Jboss 的 JCA 包中,共用到以下兩處:
通過大量的實驗,我們確定我們這個系統所有數據庫查詢操作必定會調用①②中的一個來完成(實現邏輯不同其他系統可能調用的是 JCA 的其他方法)。再通過在①②設置斷點 bebug 我們發現,在①②方法內部 SQL 語句是完全可見的。
接下來我們利用的 Java Instrument Api 及其衍生的開源組件,搭建了一個 agent 程序。啟動 agent,agent 在應用系統程序運行時動態的往這兩個地方分別插個樁,樁的內容非常簡單:將當前方法體內存中正在執行的 SQL 語句打印到某個固定位置(假設我們把 SQL 語句輸出到日志文件 A 中)。相對于在①②方法體內部多寫一句 print,僅僅只做一個打印的操作,不會對業務邏輯產生任何干擾。
于是我們就完成了這樣一個事情:當應用系統要進行數據庫查詢操作時,它會調用①②中的一個來執行這個查詢 SQL,①②被調用時,會將正在執行的 SQL 語句輸出到日志文件 A 中。這樣,每一個查詢操作,都會將實際的查詢語句記錄在日志文件 A 中,也就完成了查詢語句的收集啦。
通過插樁我們獲得了大量的 SQL 語句,接下來解決第二個問題,如何判斷一個查詢語句是否為慢查詢。
由于測試和生產數據數量級的差異,用執行時間來判斷顯然不科學。同時,我們一共獲得了幾萬條 SQL 語句,直接進行人工分析顯然不可行。
我們想到了 Mysql 提供的 explain 命令來擴展 SQL 語句,通過 Mysql 的執行計劃來科學判斷執行的快慢。每條可執行 SQL 語句都可以直接用 explain 命令獲得
?
執行計劃中的每一個列標簽都可以作為匹配環節的關注項,我們稱其為指標項,我們用到了與查詢效率相關的指標項中最重要的兩個:
1、key:表示這個 SQL 語句執行時會使用的索引的鍵;
2、type:訪問方式,表示執行 SQL 語句是在數據庫表中找到所需行的方式,可能的值如下:
從 system 到 ALL,性能從好到差,一般來說應保證至少達到 range 級別。
第一步,我們將日志文件 A 中所有的 SQL 語句逐條轉換成執行計劃;
第二步,根據系統實際需求,建立一套規則,對執行計劃進行篩選,找出可能是慢查詢的語句;
我們系統匹配慢查詢的規則是:
這個規則表示:如果一個 SQL 語句它未經過索引、或者訪問方式為 range、index、ALL 之一、或者預估掃描行數大于等于 1000 條,那么它可能是一個慢查詢。
第三步,對可能是慢查詢的語句進行人工分析。
通過第二步的篩選,我們將需要分析的 SQL 語句數量從幾十萬條降到了十幾條,后續再人工逐一分析。
如此,我們完成了系統的慢查詢測試工作。之前導致生產問題的 SQL 語句完美命中,其他疑似慢查詢語句結合查詢頻率、生產數據表數量級等因素,人工判定為非慢。
破浪
后來,通過實現 agent 插樁位置、慢查詢篩選規則的可配置,我們將這套解決方案優化為一個通用框架,并推廣到部門的多個系統使用,并發現了若干慢查詢隱患。
對于這套基于插樁的慢查詢測試方法,總結優勢如下:
1、SQL 語句覆蓋全面,且準確性較高。只有插樁點分析準備,可以保證捕獲程序運行時執行的所有 SQL 語句(由于實際執行過的 SQL 語句才能被捕獲,因此依賴于功能測試的完整性),而以執行計劃為基礎的分析更具有科學性,且不受數據量大小的影響,準確性更高。
2、有極好的通用性。插樁位置可配置,不同系統只需修改配置既能使用。樁點一般為底層實現與數據庫交互的數據庫驅動包某一些特定的類和方法,與具體應用程序實現方式不相關,也就是說,無論程序功能是什么、無論使用了什么數據庫框架,只要配置正確的數據庫交互類及其方法,都能適配。
3、非侵入、可插拔,被測應用無感知。agent 啟動,則動態插樁,agent 停止,則樁點消失。無需對被測應用源碼做任何修改,檢測過程對功能無影響,可在功能測試中悄無聲息的完成。
收獲前沿測試開發技術 ·?學習先進質量管理辦法 · 結識測試大咖和行業精英?↓↓↓↓?
??
總結
以上是生活随笔為你收集整理的使用插桩技术解决慢查询测试问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vsCode页面缩小放大默认快捷键
- 下一篇: 500 Internal Privoxy