本話題系列文章整理自 PingCAP NewSQL Meetup 第 26 期劉奇分享的《深度探索分佈式系統測試》議題現場實錄。文章較長,爲方便你們閱讀,會分爲上中下三篇,本文爲下篇。html
接中篇:
ScyllaDB 有一個開源的東西,是專門用來給文件系統作 Failure Injection 的, 名字叫作 CharybdeFS。若是你想測試你的系統,就是文件系統在哪不斷出問題,好比說寫磁盤失敗了,驅動程序分配內存失敗了,文件已經存在等等,它均可以測模擬出來。java
CharybdeFS: A new fault-injecting file system for software testingsql
Simulate the following errors:數據庫
disk IO error (EIO)網絡
driver out of memory error (ENOMEM)併發
file already exists (EEXIST)app
disk quota exceeded (EDQUOT)框架
再來看看 Cloudera,下圖是整個 Cloudera 的一個 Failure Injection 的結構。dom
一邊是 Tools,一邊是它的整個的 Level 劃分。好比說整個 Cluster, Cluster 上面有不少 Host,Host 上面又跑了各類 Service,整個系統主要用於測試 HDFS, HDFS 也是很努力的在作有效的測試。而後每一個機器上部署一個 AgenTEST,就用來注射那些可能出現的錯誤。tcp
看一下它們做用有多強大。
Cloudera: Simulate the following errors:
Packets loss/corrupt/reorder/duplicate/delay
Bandwidth limit: Limit the network bandwidth for the specified address and port.
DNSFail: Apply an injection to let the DNS fail.
FLOOD: Starts a DoS attack on the specified port.
BLOCK: Blocks all the packets directed to 10.0.0.0/8 (used internally by EC2).
SIGSTOP: Pause a given process in its current state.
BurnCPU/BurnIO/FillDISK/RONLY/FIllMEM/CorruptHDFS
HANG: Hang a host running a fork bomb.
PANIC: Force a kernel panic.
Suicide: Shut down the machine.
數據包是能夠丟的,能夠壞的,能夠 reorder 的,好比說你發一個 A,再發一個 B,它能夠給你 reorder,變成先發了 B 再發了 A,而後看你應用程序有沒有正確的處理這種行爲。接着發完一次後面再給你重發,而後能夠延遲,這個就比較簡單。目前這個裏面的大部分,TiKV 都有實現,還有帶寬的限制,就好比說把你帶寬壓縮成 1M。之前咱們遇到一個問題頗有意思,發現有人把文件存到 Redis 裏面,但 Redis 是帶多個用戶共享的,一個用戶就能把整個 Redis 帶寬給打滿了,這樣其餘人的帶寬就很卡,那這種很卡的時候 Redis 可能出現的行爲是什麼呢?咱們並不須要一個用戶真的去把它打滿,只要用這種工具,瞬間就能出現我把你的帶寬限制到原來的 1%,假設別人在跟你搶帶寬,你的程序行爲是什麼?立刻就能出來,也不須要配很複雜的環境。這極大的提升了測試效率,同時能測試到不少 corner case。
而後 DNS fail。那 DNS fail 會有什麼樣的結果?有測過嗎?可能都沒有想過這個問題,可是在一個真正的分佈式系統裏面,每一點都是有可能出錯的。還有 FLOOD,假設你如今被攻擊了,整個系統的行爲是什麼樣的?而後一不當心被這個 IP table 給 block 了,該怎麼辦。這種狀況咱們確實出現過。咱們一上來併發,兩萬個鏈接一打出去,而後發現大部分都連不上,後來一看 IP table 自動啓用了一個機制,而後把大家都 block。固然咱們後面查了半個小時左右,才把問題查出來。但這種實際上應該是在最開始設計的時候就應該考慮的東西。
若是你的進程被暫停了,好比說你們在雲上跑在 VM 裏面,整個 VM 爲了升級,先把你整個暫停了,升級完以後再把你恢復的時候會怎麼樣?那簡單來說,就是若是假設你程序是有 GC 的,GC 如今把咱們的程序卡了五秒,程序行爲是正常的嗎?五十秒呢?這個頗有意思的就是,BurnCPU,就是再寫一個程序,把 CPU 全佔了,而後讓你這個如今的程序只能使用一小部分的 CPU 的時候,你程序的行爲是否是正常的。正常來說,你可能說我 CPU 不是瓶頸啊,我瓶頸在 IO,當別人跟你搶 CPU,把你這個 CPU 壓的很低的時候,到 CPU 是瓶頸的時候,正常你的程序的這個行爲是否是正常的?還有 IO,跟你搶讀的資源,跟你搶寫的資源,而後 filedisk 把磁盤寫滿,寫的空間不多。好比說對數據庫而言,你建立你的 redo log 的時候,都已經滿了會怎麼樣?而後我忽然把磁盤設爲只讀,就你忽然一個寫入會出錯,可是你接下來正常的讀寫行爲是否是對的?很典型的一個例子,若是一個數據庫你如今寫入,磁盤滿了,那外面讀請求是否就能正常響應。 Fill memory,就是瞬間把這個 memory 給壓縮下來,讓你下次 malloc 的時候可能分佈不到內存。這個就和業務比較相關了,就是破壞 HDFS 的文件。其它的就是 Hang、Panic,而後還有自殺,直接關掉機器,整個系統的行爲是什麼樣的?
如今比較痛苦的一點是你們各自爲政,每一家都作一套,可是沒有辦法作成一個通用的東西給全部的人去用。包括咱們本身也作了一套,可是確實沒有辦法和其餘的語言之間去 share,最先提到的那個 libfu 庫其實是在 C 語言寫的,那全部 C 相關的均可以去 call 那個庫。
Distributed testing
Namazu
ZooKeeper:
Found ZOOKEEPER-2212, ZOOKEEPER-2080 (race): (blog article)
Etcd:
Found etcdctl bug #3517 (timing specification), fixed in #3530. The fix also resulted a hint of #3611, Reproduced flaky tests {#4006, #4039}
YARN: Found YARN-4301 (fault tolerance), Reproduced flaky tests{1978, 4168, 4543, 4548, 4556}
而後 Namazu。你們確定以爲 ZooKeeper 很穩定呀, Facebook 在用、阿里在用、京東在用。你們都以爲這個東西也是很穩定的,直到這個工具出現了,而後輕輕鬆鬆就找到 bug 了,全部的你們認爲的這種特別穩定的系統,其實 bug 都還挺多的,這是一個毀三觀的事情,就是你以爲東西都很穩定,都很 stable,其實不是的。從上面,咱們能看到 Namazu 找到的 Etcd 的幾個 bug,而後 YARN 的幾個 bug,其實還有一些別的。
How TiKV use namazu
Use nmz container / non-container mode to disturb cluster.
Run container mode in CI for each commit. (1 hour)
Run non-container mode for a stable version. (1 week+)
Use
extreme
policy for process inspector
Pick up some processes and execute them with SCHED_RR scheduler. others are executed with SCHED_BATCH scheduler
Use [0, 30s] delay for filesystem inspector
接下來講一下 TiKV 用 Namazu 的一些經驗。由於咱們曾經在系統上、在雲上面出現過一次寫入磁盤花了五十幾秒才完成的狀況,因此咱們須要專門的工具模擬這個磁盤的抖動。有時候一次寫入可能確實耗時比較久,那這種時候是否是 OK 的。你們若是能把這種東西通通用上,我以爲還能爲不少開源系統找出一堆 bug。
稍微介紹一下咱們如今運行的基本策略,好比說咱們會用 0 到 30 秒的這個 delay (就是每一次你往文件系統的交互,好比說讀或者寫,那麼咱們會給你產生隨機的 0 到 30 秒的 delay ),但咱們正常應該仍是須要去測三十秒到幾分鐘的延遲的狀況,是否會讓整個系統崩掉了。
How TiKV simulate network transport
Drop/Delay messages randomly
Isolate Node
Partition [1, 2, 3, 4, 5] -> [1, 2, 3] + [4, 5]
Out of order messages
Filter messages
Duplicate and send redundant messages
怎麼模擬網絡呢?假設你有網絡,裏面有五臺機器,那我如今想作一個腦裂怎麼作?不能靠拔網線對吧?好比在 TiKV 的測試框架中,咱們就能夠直接經過 API 把 5 個節點腦裂成兩部分,讓 1, 2, 3 號節點互相聯通,4, 5 號節點也能聯通,這兩個分區彼此是隔離的,很是的方便。其實原理很簡單,這種狀況是用程序本身去模擬,假如是你發的包,自動給你丟掉,或者直接告訴你 unreachable,那這個時候你就知道這個網絡就腦裂了,而後你怎麼作?就是隻容許特定類型的消息進來,把其餘的都丟掉,這樣一來你能夠保證有些 bug 是必然重現的。這個框架給了咱們極大的信心用來模擬並重現各類 corner case,確保這些 corner case 在單元測試中每次都能被覆蓋到。
How to test Rocksdb
Treat storage as a black box.
Three steps(7*24):
Fill data, Random kill -9
Restart
Consistent check.
Results:
Found 2 bugs. Both fixed
而後說說咱們怎麼測 RocksDB。 RocksDB 在你們印象中是很穩定的,但咱們最近發現了兩個 bug。測的方法是這樣的:咱們往 RocksDB 裏面填數據,而後隨機的一段時間去把它 kill 掉,kill 掉以後咱們重啓,從新啓動以後去檢測咱們剛纔 fail 的 data 是否是一致的,而後咱們發現兩個可能形成數據丟失的 bug,可是官方的響應速度很是快,幾天就都 fix 了。但是你們廣泛運行的是這麼 stable 的系統,爲何還會這麼容易找到 bug?就說這個測試,若是是一直有這個測試的 cover,那麼這兩個 bug 可能很快就可以被發現。
這是咱們一個基本的,也就是當成一個純黑盒的測。你們在測數據庫的時候,基本也是當黑盒測。好比說 MySQL 寫入數據,kill 掉,好比說我 commit 一個事務,數據庫告訴咱們 commit 成功,我把數據庫 kill 掉,我再去查我剛纔提交的數據同樣能查到。這是一個正常的行爲,若是查不到,說明整個系統有問題。
More tools
american fuzzy lop
其實還有一些更加先進的工具,你們平時以爲特別穩定的東西,都被摧殘的不行。Nginx 、NGPD、tcpdump 、LibreOffice ,若是有用 Linux 的同窗可能知道,還有 Flash、sqlite。這個東西一出來,當時你們很興奮,說怎麼一會兒找了這麼多 bug,爲何之前那麼穩定的系統這麼不堪一擊,會以爲這個東西它還挺智能的。就好比說你程序裏面有個 if 分支,它是這樣的,假如你程序有一百條指令,它先從前面一直走,走到某條分支指令的時候,它是一直持續探索,一個分支走不下去,它會一直在這兒持續探索,再給你隨機的輸入,直到我探索進去了,我記下來了下次我知道我用這個輸入能夠進去特定的分支。那我能夠再往下走,好比說你 if 分支進去以後裏面還有 if ,那你傳統手段可能探測不進去了但它能夠,它記錄一下,我這個能夠進去,而後我重來,反正我繼續輸入這個,我再往裏面走,一旦我探測到一個新的分支,我再記住,我再往裏面走。因此它一出來的時候你們都說這個真厲害,一下發現這麼多 bug。但最激動的不是這些人,最激動的是黑客,爲何?由於忽然有不少棧溢出、堆溢出漏洞被發現了,而後就能夠寫一堆工具去攻擊線上的這麼多系統。因此不少的技術的推動在早期的時候是黑客作出來,可是他們的目的固然不必定是爲了測試 bug,而是爲了怎麼黑一個系統進去,這是他們當時作的,因此這個工具也是很是強大、很是有意思的,你們能夠拿去研究一下本身的系統。
你們印象裏面各類文件系統是很穩定的,但是當用 American fuzzy lop 來測試的時候,被驚呆了。 Btrfs 連 5 秒都沒有堅持到就跪了,你們用的最多的 Ext4 是最堅挺的,也才抗了兩個小時!!!
再來講說 Google,Google 怎麼作測試對外講的很少,最近 Chrome team 開源了他們的 Fuzz 測試工具 OSS-Fuzz,這個工具強大的地方在於自動化作的極好:
發現 bug 後自動建立 issue
bug 解決後自動 verify
更驚人的是 OSS-Fuzz 集羣一週能夠跑 ~4 trillion test cases 更多細節你們能夠看這篇文章:Announcing OSS-Fuzz: Continuous Fuzzing for Open Source Software
另外有些工具能讓分佈式系統開發人員的生活變得更美好一點。
Tracing tools may help you
Google Dapper
Zipkin
OpenTracing
還有 Tracing,好比說我一個 query 過來,而後通過這麼多層,通過這麼多機器,而後在不一樣的地方,不一樣環節耗時多久,實際上這個在分佈式系統裏面,有個專門的東西作 Tracing ,就是 distribute tracing tools。它能夠用一條線來表達你的請求在各個階段耗時多長,若是有幾段,那麼分到幾個機器,分別並行的時候好了多長時間。大致的結構是這樣的:
這裏是一個具體的例子:
很清晰,一看就知道了,不用去看 log,這事其實一點也不新鮮,Google 十幾年前就作了一個分佈式追蹤的工具。而後開源社區要作一個實現叫作 Zipkin,好像是 java 仍是什麼寫的,又出了新的叫 OpenTracing,是 Go 寫的。咱們如今正準備上這個系統,用來追蹤 TiDB 的請求在各個階段的響應時間。
最後想說一下,你們研究系統發現 bug 多了以後,不要對系統就喪失了信心,畢竟bug 一直在那裏,只是從前沒有發現,如今發現得多了,整體上新的測試方法讓系統的質量比之前好了不少。好像有點超時了,先聊到這裏吧,還有好多細節無法展開,下次再聊。(本系列完結)