跑三小时的monkey测试该怎么算_百亿次的锤炼 - 带逛Dragonboat的各类测试
本文以近期開源的Dragonboat多組Raft庫為例,介紹Dragonboat這樣一個(gè)典型分布式系統(tǒng)是如何做測(cè)試的。Dragonboat以Go實(shí)現(xiàn),能在普通硬件上提供每秒1000萬次以上的強(qiáng)一致讀寫,它是目前github.com上速度最快的功能完整的多組Raft開源庫。歡迎大家試用,并請(qǐng)點(diǎn)Star支持:
lni/dragonboat?github.com最大的誤導(dǎo)
常看到有系統(tǒng)吹捧自己可靠的方法是說某大型活動(dòng)用了它,或說是某某公司某內(nèi)部項(xiàng)目用了,從而得出可靠的結(jié)論,生產(chǎn)環(huán)境儼然成了廉價(jià)公關(guān)軟文口中的測(cè)試平臺(tái)。其實(shí)眾所周知,某活動(dòng)全場(chǎng)意外當(dāng)機(jī)重啟的節(jié)點(diǎn)數(shù)少之又少,磁盤毀損一整年才2-4%,而故障性的網(wǎng)絡(luò)分區(qū)在很多DevOps崗的整個(gè)職業(yè)生涯里也就遇到幾次而已,以至于多年來各一線公司網(wǎng)絡(luò)分區(qū)造成故障的故事收集起來也才寫滿幾頁紙。某活動(dòng)扛住了或是某項(xiàng)目用了,這些完全不是軟件可靠與否的充要條件。
事實(shí)其實(shí)是殘酷的。曾閱讀過國(guó)內(nèi)排名前四的某司一個(gè)共識(shí)庫,30分鐘代碼讀下來找到多處數(shù)據(jù)丟失毀損的bug,實(shí)現(xiàn)則是很典型的那種打死也不肯寫測(cè)試的全裸奔模式。
對(duì)于軟件,任何無法用代碼來驗(yàn)證的廉價(jià)營(yíng)銷式說辭,不說、不看、不聽相較于廉價(jià)的文宣,Dragonboat對(duì)系統(tǒng)正確性滿心敬畏,老老實(shí)實(shí)以完備的測(cè)試方案、開源的測(cè)試代碼、公開可驗(yàn)證的測(cè)試結(jié)果數(shù)據(jù)三者來提供切實(shí)的保障。
常規(guī)測(cè)試
常規(guī)測(cè)試部分,Dragonboat做了:
- 數(shù)萬行全手寫測(cè)試代碼,Raft協(xié)議3000行核心代碼擁有過萬行測(cè)試代碼護(hù)航
- Go內(nèi)建的race detector測(cè)試
- 各類靜態(tài)檢查,及早發(fā)現(xiàn)如錯(cuò)誤返回值未處理等可能問題
- 使用go-fuzz對(duì)所有網(wǎng)絡(luò)與本地輸入做隨機(jī)輸入fuzz測(cè)試
Dragonboat內(nèi)各Package覆蓋率基本均在90%以上。以Raft協(xié)議實(shí)現(xiàn)部分為例,基本不正確地刪改一行代碼就能觸發(fā)多個(gè)測(cè)試錯(cuò)誤。這些測(cè)試代碼,連同下面要介紹的monkey testing,nightly build時(shí)在race detector被打開的情況下運(yùn)行。對(duì)于長(zhǎng)期被人詬病的Golang的error處理方式,的確容易因?yàn)槿藶槭韬鲈斐蒭rror返回有漏檢的可能,但僅gometalinter一個(gè)軟件收錄的靜態(tài)檢測(cè)工具就有多種能對(duì)付它。對(duì)各輸入的Fuzz testing初聽來或許有些多此一舉,但一跑Fuzz testing幾十秒就發(fā)現(xiàn)bug的例子比比皆是,Dragonboat開發(fā)中也曾遇到。
基于Raft協(xié)議的自測(cè)
Raft協(xié)議對(duì)內(nèi)部數(shù)據(jù)有嚴(yán)格限定要求,比如顯而易見的就有:
- 所有entry的Index值始終應(yīng)該是連續(xù)且嚴(yán)格遞增的
- 所有entry的Term值應(yīng)該是單向的
- 當(dāng)Index與Term確定時(shí),entry內(nèi)容是唯一確定的
這些都提供較小代價(jià)下運(yùn)行時(shí)自測(cè)的機(jī)會(huì)。僅以第一項(xiàng)為例,在Dragonboat中它被落實(shí)到多個(gè)點(diǎn)位上,對(duì)應(yīng)用透明的進(jìn)行自測(cè):
- 在節(jié)點(diǎn)完成了協(xié)議規(guī)定的檢查,即將append log時(shí)
- 在entry被commit以后,準(zhǔn)備由Raft協(xié)議返回供復(fù)制狀態(tài)機(jī)執(zhí)行時(shí)
- 復(fù)制狀態(tài)機(jī)即將執(zhí)行entry,由該entry Index對(duì)比當(dāng)前最新已執(zhí)行的entry的Index值時(shí)
這些自測(cè)在Dragonboat中無法通過任何設(shè)置予以關(guān)閉,甚至在Benchmark跑分時(shí)也嚴(yán)格限定必須進(jìn)行。
磁盤文件IO測(cè)試
磁盤文件IO要做正確有多難,可以先看兩個(gè)事實(shí):
- Golang的標(biāo)準(zhǔn)庫在MacOS上默認(rèn)的使用,基本必然出現(xiàn)丟數(shù)據(jù)
- 專業(yè)測(cè)試顯示,包括git、leveldb、ZooKeeper等最著名項(xiàng)目,丟數(shù)據(jù)的bug曾有一堆
假設(shè)文件系統(tǒng)的可靠是天經(jīng)地義的吧?很遺憾,這種假設(shè)也是高危動(dòng)作。
TS Pillai的這張總結(jié)圖表直觀顯示文件IO做正確有多難為解決這些磁盤文件IO的挑戰(zhàn),Dragonboat首先選擇不自作聰明的到處自己去做文件操作,把存儲(chǔ)盡可能交給RocksDB,并對(duì)基于RocksDB的系統(tǒng)加以各類測(cè)試:
- 使用ScyllaDB的charybdefs實(shí)現(xiàn)的磁盤錯(cuò)誤注入測(cè)試
- 使用自動(dòng)開關(guān)的掉電數(shù)據(jù)完整性測(cè)試
前者可以模擬諸如RocksDB試圖讀一個(gè)sst文件的內(nèi)容時(shí)第二次讀操作返回錯(cuò)誤,幫助檢查Dragonboat是否按照設(shè)計(jì)正確地處理這樣的IO錯(cuò)誤。掉電測(cè)試檢查fsync是否被正確配置(如MacOS上是否fcntl(fd, F_FULLFSYNC)了)與調(diào)用,是否IO邏輯上有丟數(shù)據(jù)的問題。
看了上述介紹,可能有人覺得這是小題大做,從Turbo C就開始玩的文件操作有啥難?hehe,文件操作方面是git、ZooKeeper的作者經(jīng)驗(yàn)多,還是您更牛?
as we know, there are known knowns; there are things we know we know. We also know there are known unknowns; that is to say we know there are some things we do not know. But there are also unknown unknowns—the ones we don't know we don't know.Donald Rumsfeld
Monkey Testing
Monkey Testing有時(shí)也稱為Chaos Engineering,目的在于自動(dòng)測(cè)試系統(tǒng)在各組件失效當(dāng)機(jī)情況下系統(tǒng)是否依舊能按設(shè)計(jì)提供應(yīng)有的服務(wù)。與Fuzz testing的隨機(jī)數(shù)據(jù)輸入不同,Monkey Testing / Chaos Engineering著眼于隨機(jī)破壞性事件對(duì)系統(tǒng)的影響。
Netflix提供了大量公開的資料,推廣Chaos Engineering在Dragonboat的monkey testing中,各種隨機(jī)破壞性事件的組合被注入到一個(gè)多節(jié)點(diǎn)的測(cè)試環(huán)境里,在一年多的自動(dòng)測(cè)試期間,導(dǎo)致了百億數(shù)量級(jí)次數(shù)的Raft節(jié)點(diǎn)重啟事件,發(fā)現(xiàn)并修正了大量Raft協(xié)議實(shí)現(xiàn)與相關(guān)輔助功能的bug。具體的,在monkey testing中,被注入的隨機(jī)事件有:
- 隨意的停止各節(jié)點(diǎn)
- 隨意刪除節(jié)點(diǎn)所有Raft數(shù)據(jù)
- 隨意丟棄傳輸中的消息
- 隨意網(wǎng)絡(luò)分割節(jié)點(diǎn)暫時(shí)阻斷通訊
在上述大量注入的隨機(jī)破壞性事件前提下,同時(shí)在上述多節(jié)點(diǎn)測(cè)試環(huán)境上運(yùn)行大量Raft組實(shí)例,進(jìn)行Raft的讀寫測(cè)試。該monkey testing環(huán)境同時(shí)內(nèi)建一組三個(gè)節(jié)點(diǎn)的Drummer系統(tǒng),三個(gè)Drummer節(jié)點(diǎn)觀測(cè)、維護(hù)各Raft組健康信息,并在發(fā)現(xiàn)Raft組的成員失效以后,試圖在其它節(jié)點(diǎn)上通過Raft組成員變更,新增并啟動(dòng)一個(gè)新的Raft成員,替換已失效的Raft成員。
上述三節(jié)點(diǎn)的Drummer本身也是一個(gè)基于Dragonboat的Raft實(shí)現(xiàn)的無單點(diǎn)系統(tǒng),且在monkey testing中同樣會(huì)被注入上述隨機(jī)錯(cuò)誤。Drummer的上述監(jiān)控、修復(fù)Raft組的業(yè)務(wù)邏輯是在自身同樣面對(duì)大量被注入的隨機(jī)破壞性事件的前提下完成的,這進(jìn)一步驗(yàn)證了此類具體實(shí)際業(yè)務(wù)邏輯下,Dragonboat的Raft實(shí)現(xiàn)的可靠性。
在一個(gè)節(jié)點(diǎn)平均存活僅幾分鐘的情況下,在幾臺(tái)服務(wù)器上每晚便可完成千萬次量級(jí)的節(jié)點(diǎn)隨機(jī)失效與重啟測(cè)試。在此及其嚴(yán)酷的測(cè)試環(huán)境中,同時(shí)向系統(tǒng)施加Raft讀寫請(qǐng)求,配合大量后臺(tái)的Raft快照保存與快照恢復(fù)操作,嚴(yán)格的后驗(yàn)檢查確保:
- Jepsen的Knossos和porcupine檢查,絕無違反稱為linearizability的強(qiáng)一致性
- Raft組在有Quorum的時(shí)候需可用
- 用戶應(yīng)用狀態(tài)機(jī)狀態(tài)一致
- Raft組成員一致
- 磁盤上保存的Raft Entry Log一致
一部分Jepsen可讀格式的edn log已被公布,可供大家使用各自選定的Linearizability checker檢驗(yàn):
lni/knossos-data?github.com版權(quán)信息:
本文歡迎在不做任何修改刪節(jié)、保留完整原作者信息與出處的前提下合理轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的跑三小时的monkey测试该怎么算_百亿次的锤炼 - 带逛Dragonboat的各类测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 演讲者模式投影到幕布也看到备注_家用投影
- 下一篇: 如何制作印章_电子公章怎么制作