《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 模擬設(shè)計 > 業(yè)界動態(tài) > 睡覺的時候,,程序能不能自動查 bug,?

睡覺的時候,,程序能不能自動查 bug,?

2020-02-17
來源:搜狐科技
關(guān)鍵詞: Bug ChaosEngineering Google

e067552dc5b54730baa4006c3a4f4e8c.jpeg

  作者 | 杜沁園 等

  責(zé)編 | 郭芮

  出品 | CSDN(ID:CSDNnews)

  曾在 Hacker News 上看到過一個 Oracle 工程師處理 bug 的 日常:

  先花兩周左右時間來理解 20 個參數(shù)如何通過神奇的組合引發(fā) bug,。

  改了幾行代碼,,嘗試對 bug 進(jìn)行修復(fù),,提交測試集群開始跑近百萬個測試 case,,通常要 20~30 小時。

  運(yùn)氣好的話會有 100 多個 case 沒過,,有時候上千個也有可能,,只好挑選幾個來看,發(fā)現(xiàn)還有 10 個參數(shù)之前沒有注意到,。

  又過了兩周,,終于找到了引起 bug 的真正參數(shù)組合,,并跑通了所有測試。并增加 100 多個測試 case 確保覆蓋他的修改,。

  經(jīng)過一個多月的代碼 review,,他的修改終于合并了,開始處理下一個 bug……

  后來這個工程師感慨說:“I don't work for Oracle anymore. Will never work for Oracle again!”

  Oracle 12.2 有將近 2500 萬行 C 代碼,,復(fù)雜系統(tǒng)的測試是一件艱難,、艱苦和艱巨的事情,而測試一個分布式數(shù)據(jù)庫的情況就更復(fù)雜了,。我們永遠(yuǎn)不知道用戶可能寫出什么樣的 SQL,,表結(jié)構(gòu)和索引有多少種組合,此外還要考慮集群在什么時候節(jié)點發(fā)生宕機(jī),,以及受到網(wǎng)絡(luò)抖動,、磁盤性能退化等因素的影響——可能性幾乎是無限的。

  那么有沒有一種方法能讓程序自動幫我們查 bug,?

  如何做到「睡覺的時候讓程序自動查 bug」,?

  項目的思路其實很簡單,如果在每次跑 case 的時候能用統(tǒng)計學(xué)的方法對足夠多次實驗的代碼路徑進(jìn)行分析,,就可以找出疑似 bug 的代碼,,最終結(jié)果以代碼染色的方式由前端可視化呈現(xiàn),就得到了如下圖展示的效果:

2.gif

  「顏色越深,,亮度越高」表示包含錯誤邏輯的可能性越大,。該方法不僅適用于數(shù)據(jù)庫系統(tǒng)的測試,同樣適用于其他任何復(fù)雜的系統(tǒng),。

  背后的原理

  項目最初是受到 VLDB 的一篇論文的啟發(fā) APOLLO: Automatic Detection and Diagnosis of Performance Regressions in Database Systems,,該論文主要圍繞如何診斷引發(fā)數(shù)據(jù)庫性能回退的代碼,其核心思想也同樣適用于排查 bug,。論文中提到的自動診斷系統(tǒng)由 SQLFuzz,,SQLMin 和 SQLDebug 三個模塊組成。

3.png

  SQLFuzz:負(fù)責(zé)隨機(jī)生成 SQL,,并利用二分查找定位到性能回退的前后兩個版本,,傳遞給 SQLMin 模塊。

  SQLMin:通過剪枝算法將 SQLFuzz 生成的 SQL 進(jìn)行化簡,,得出能夠復(fù)現(xiàn)該問題的最小 SQL ,,傳遞給 SQLDebug 模塊。目的是減少無關(guān)的代碼路徑,,降低噪音。

  SQLDebug:對源碼進(jìn)行插樁,,使其在執(zhí)行 SQL 時能夠輸出代碼的執(zhí)行路徑,。然后對兩個版本的代碼路徑進(jìn)行分析,,建立一個統(tǒng)計模型來定位問題的位置。

  最終系統(tǒng)自動生成測試報告,,內(nèi)容包含:

  哪一次的代碼 commit 引入了性能回退,。

  存在問題的代碼源文件。

  具體的函數(shù)位置,。

  而實際上,,考慮到并發(fā)、循環(huán),、遞歸等帶來的影響,,代碼執(zhí)行路徑分析會非常復(fù)雜。為了保證能夠在 Hackathon 那么短的時間內(nèi)展示出效果,,我們又參考了另一篇論文 Visualization of Test Information to Assist Fault Localization,,其核心思想是通過統(tǒng)計代碼塊被正確和錯誤測試用例經(jīng)過次數(shù),再基于分析算法來涂上不同的顏色,,簡單而實用,。

4.png

  其實借助這個思路也可以應(yīng)用到其他領(lǐng)域,后面我們將展開來介紹,。接下來我們先來看看 SQLDebug 是如何實現(xiàn)的,。

  聊聊細(xì) (gān) 節(jié) (huò)

  如何自動產(chǎn)生測試 case?

  由于是基于統(tǒng)計的診斷,,我們需要先構(gòu)建足夠多的測試用例,,這個過程當(dāng)然最好也由程序自動完成。事實上,,grammar-based 的測試在檢驗編譯器正確性方面有相當(dāng)長的歷史,,DBMS 社區(qū)也采用類似的方法來驗證數(shù)據(jù)庫的功能性。比如:微軟的 SQL Server 團(tuán)隊開發(fā)的 RAGS 系統(tǒng)對數(shù)據(jù)庫進(jìn)行持續(xù)的自動化測試,,還有社區(qū)比較出名的 SQLSmith 項目等等,。今年 TiDB Hackathon 的另一個獲獎項目 sql-spider 也是實現(xiàn)類似的目的。

  這里我們暫時采用 PingCAP 開源的隨機(jī)測試框架 go-randgen 實現(xiàn) SQL fuzzing,,它需要用戶寫一些規(guī)則文件來幫助生成隨機(jī)的 SQL 測試用例,。規(guī)則文件由一些產(chǎn)生式組成。randgen 每次從 query 開始隨機(jī)游走一遍產(chǎn)生式,,生成一條 SQL,,產(chǎn)生一條像下圖紅線這樣的路徑。

5.png

  我們將每個產(chǎn)生式生成正確與錯誤用例的比例作為該產(chǎn)生式的顏色值,,繪制成一個頁面,,作為 SQLFuzz 的展示頁面。通過該頁面,,可以比較容易地看出哪條產(chǎn)生式更容易產(chǎn)生錯誤的 SQL,。

6.gif

  代碼跟蹤

  為了跟蹤每一條 SQL 在運(yùn)行時的代碼執(zhí)行路徑,,一個關(guān)鍵操作是對被測程序進(jìn)行插樁 (Dynamic Instrumentation)。VLDB 論文中提到一個二進(jìn)制插樁工具 DynamoRIO,,但是我們不確定用它來搞 Go 編譯的二進(jìn)制能否正常工作,。換一個思路,如果能在編譯之前直接對源碼進(jìn)行插樁呢,?

  參考 go cover tool 的實現(xiàn),,我們寫了一個專門的代碼插樁工具 tidb-wrapper。它能夠?qū)θ我獍姹镜?TiDB 源碼進(jìn)行處理,,生成 wrapped 代碼,。并且在程序中注入一個 HTTP Server,假設(shè)某條 SQL 的摘要是 df6bfbff(這里的摘要指的是 SQL 語句的 32 位 MurmurHash 計算結(jié)果的十六進(jìn)制,,主要目的是簡化傳輸?shù)臄?shù)據(jù)),,那么只要訪問 http://<tidb-server-

7.png

ip>::43222/trace/df6bfbff 就能獲得該 SQL 所經(jīng)過的源碼文件和代碼塊信息。

  因為主要目標(biāo)是正確性診斷,,所以我們限定系統(tǒng)不對 TiDB 并發(fā)執(zhí)行 SQL,,這樣就可以認(rèn)為從 server/conn.go:handleQuery 方法被調(diào)用開始,到 SQLDebug 模塊訪問 trace 接口的這段時間所有被執(zhí)行的基本塊都是這條 SQL 的執(zhí)行路徑,。當(dāng) SQLDebug 模塊訪問 HTTP 接口,,將會同時刪除該 SQL 相關(guān)的 trace 信息,避免內(nèi)存被撐爆,。

  基本塊統(tǒng)計

  SQLDebug 模塊在獲取到每條 SQL 經(jīng)過的基本塊信息后,,會對每個基本塊建立如下的可視化模型。

  首先是顏色,,經(jīng)過基本塊的失敗用例比例越高,,基本塊的顏色就越深。

8.png

  然后是亮度,,經(jīng)過基本塊的失敗用例在總的失敗用例中占的比例越高,,基本塊的亮度越高。

9.png

  已經(jīng)有了顏色指標(biāo),,為什么還要一個亮度指標(biāo)呢,?其實亮度指標(biāo)是為了彌補(bǔ)“顏色指標(biāo) Score”的一些偏見。比如某個代碼路徑只被一個錯誤用例經(jīng)過了,,那么它顯然會獲得 Score 的最高分 1,,事實上這條路徑不那么有代表性,因為這么多錯誤用例中只有一個經(jīng)過了這條路徑,,大概率不是錯誤的真正原因,。所以需要額外的一個亮度指標(biāo)來避免這種路徑的干擾, 只有顏色深,,亮度高的代碼塊,,才是真正值得懷疑的代碼塊,。

  上面的兩個模型主要是依據(jù)之前提到的 Visualization 的論文,,我們還自創(chuàng)了一個文件排序的指標(biāo),,失敗用例在該文件中的密度越大(按照基本塊),文件排名越靠前:

10.png

  前端拿到這些指標(biāo)后,,按照上面計算出的文件排名順序進(jìn)行展示,,越靠前的文件存在問題的風(fēng)險就越高。

11.png

  當(dāng)點擊展開后可以看到染色后的代碼塊:

12.png

  我們經(jīng)過一些簡單的實驗,,文件級別的診斷相對比較準(zhǔn)確,,對于基本塊的診斷相對還有些粗糙,這跟沒有實現(xiàn) SQLMin 有很大關(guān)系,,畢竟 SQLMin 能去除不少統(tǒng)計時的噪聲,。

  還能不能做點別的?

  看到這里,,你可能覺得這個項目不過是針對數(shù)據(jù)庫系統(tǒng)的自動化測試,。而實際上借助代碼自動調(diào)試的思路,可以給我們更多的啟發(fā),。

  源碼教學(xué)

  閱讀和分析復(fù)雜系統(tǒng)的源碼是個頭疼的事情,,基于源碼的運(yùn)行時可視化跟蹤能否做成一個通用工具呢?這樣在程序執(zhí)行的同時就可以直觀地看到代碼的運(yùn)行過程,,對快速理解源碼一定會大有幫助,。更進(jìn)一步,配合源碼在線執(zhí)行有沒有可能做成一個在線 web 應(yīng)用呢,?

  全鏈路測試覆蓋統(tǒng)計

  語言本身提供的單測覆蓋統(tǒng)計工具已經(jīng)比較完備了,,但一般測試流程中還要通過 e2e 測試、集成測試,、穩(wěn)定性測試等等,。能否用本文的方法綜合計算出各種測試的覆蓋度,并且與 CI 系統(tǒng)和自動化測試平臺整合起來,。利用代碼染色技術(shù),,還可以輸出代碼執(zhí)行的熱力圖分析。結(jié)合 profiler 工具,,是不是還可以輔助來定位代碼的性能問題,?

  Chaos Engineering

  在 PingCAP 內(nèi)部有諸多的 Chaos 測試平臺,用來驗證分布式系統(tǒng)的魯棒性,,譬如像 Schrodinger,,Jepsen 等等?;煦鐪y試有個弊端就是,,當(dāng)跑出問題之后想再次復(fù)現(xiàn)就很難,,所以只能通過當(dāng)時的情形去猜代碼可能哪里有問題。如果能在程序運(yùn)行時記錄代碼的執(zhí)行路徑,,根據(jù)問題發(fā)生時間點附近的日志和監(jiān)控進(jìn)一步縮小范圍,,再結(jié)合代碼路徑進(jìn)行分析就能精確快速的定位到問題的原因。

  與分布式 Tracing 系統(tǒng)集成

  Google 有一篇論文是介紹其內(nèi)部的 分布式追蹤系統(tǒng) Dapper ,,同時社區(qū)也有比較出名的項目 Open Tracing 作為其開源實現(xiàn),,Apache 下面也有類似的項目 Skywalking。一般的 Tracing 系統(tǒng)主要是跟蹤用戶請求在多個服務(wù)之間的調(diào)用關(guān)系,,并通過可視化來輔助排查問題,。但是 Tracing 系統(tǒng)的跟蹤粒度一般是服務(wù)層面,如果我們把 trace_id 和 span_id 也當(dāng)作標(biāo)注傳遞給代碼塊進(jìn)行打樁,,那是不是可以在 Tracing 系統(tǒng)的界面上直接下鉆到源碼,,聽起來是不是特別酷?

  接下來的工作

  以上我們只完成了一個非常簡單的原型,,距離真正實現(xiàn)睡覺時程序自動查 bug 還有一段路要走,,我們計劃對項目持續(xù)的進(jìn)行完善。

  接下來,,首先要支持并行執(zhí)行多個測試用例,,這樣才能在短時間得到足夠多的實驗樣本,分析結(jié)果才能更加準(zhǔn)確,。另外,,要將注入的代碼對程序性能的影響降低到最小,從而應(yīng)用于更加廣泛的領(lǐng)域,,比如性能壓測場景,,甚至在生產(chǎn)環(huán)境中也能夠開啟。

  看到這里可能你已經(jīng)按耐不住了,,附上項目的完整源碼:

  https://github.com/fuzzdebugplatform/fuzz_debug_platform

  Welcome to hack!

  作者簡介:

  黃寶靈,,PingCAP 前端開發(fā)工程師,喜歡 React 和 Type,。

  滿俊朋, 效率工具工程師, 目前在 PingCAP 從事 Benchmark, Stability 相關(guān)工具的研發(fā),。

  杜沁園,中科大研究生,,曾在 PingCAP 實習(xí),,從事數(shù)據(jù)庫測試工具的研發(fā)。

  韓玉博,,中科大研究生,,在 Tradeshift 實習(xí),從事前端開發(fā)。


本站內(nèi)容除特別聲明的原創(chuàng)文章之外,,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,,并不代表本網(wǎng)站贊同其觀點。轉(zhuǎn)載的所有的文章,、圖片,、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無法一一聯(lián)系確認(rèn)版權(quán)者,。如涉及作品內(nèi)容,、版權(quán)和其它問題,請及時通過電子郵件或電話通知我們,,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟(jì)損失,。聯(lián)系電話:010-82306118,;郵箱:[email protected]