分佈式系統測試那些事兒——信心的毀滅與重建

本話題系列文章整理自 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

7.png

一邊是 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

8.png

其實還有一些更加先進的工具,你們平時以爲特別穩定的東西,都被摧殘的不行。Nginx 、NGPD、tcpdump 、LibreOffice ,若是有用 Linux 的同窗可能知道,還有 Flash、sqlite。這個東西一出來,當時你們很興奮,說怎麼一會兒找了這麼多 bug,爲何之前那麼穩定的系統這麼不堪一擊,會以爲這個東西它還挺智能的。就好比說你程序裏面有個 if 分支,它是這樣的,假如你程序有一百條指令,它先從前面一直走,走到某條分支指令的時候,它是一直持續探索,一個分支走不下去,它會一直在這兒持續探索,再給你隨機的輸入,直到我探索進去了,我記下來了下次我知道我用這個輸入能夠進去特定的分支。那我能夠再往下走,好比說你 if 分支進去以後裏面還有 if ,那你傳統手段可能探測不進去了但它能夠,它記錄一下,我這個能夠進去,而後我重來,反正我繼續輸入這個,我再往裏面走,一旦我探測到一個新的分支,我再記住,我再往裏面走。因此它一出來的時候你們都說這個真厲害,一下發現這麼多 bug。但最激動的不是這些人,最激動的是黑客,爲何?由於忽然有不少棧溢出、堆溢出漏洞被發現了,而後就能夠寫一堆工具去攻擊線上的這麼多系統。因此不少的技術的推動在早期的時候是黑客作出來,可是他們的目的固然不必定是爲了測試 bug,而是爲了怎麼黑一個系統進去,這是他們當時作的,因此這個工具也是很是強大、很是有意思的,你們能夠拿去研究一下本身的系統。

你們印象裏面各類文件系統是很穩定的,但是當用 American fuzzy lop 來測試的時候,被驚呆了。 Btrfs 連 5 秒都沒有堅持到就跪了,你們用的最多的 Ext4 是最堅挺的,也才抗了兩個小時!!!

9.png

再來講說 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。它能夠用一條線來表達你的請求在各個階段耗時多長,若是有幾段,那麼分到幾個機器,分別並行的時候好了多長時間。大致的結構是這樣的:

10.png

這裏是一個具體的例子:

11.png

很清晰,一看就知道了,不用去看 log,這事其實一點也不新鮮,Google 十幾年前就作了一個分佈式追蹤的工具。而後開源社區要作一個實現叫作 Zipkin,好像是 java 仍是什麼寫的,又出了新的叫 OpenTracing,是 Go 寫的。咱們如今正準備上這個系統,用來追蹤 TiDB 的請求在各個階段的響應時間。

最後想說一下,你們研究系統發現 bug 多了以後,不要對系統就喪失了信心,畢竟bug 一直在那裏,只是從前沒有發現,如今發現得多了,整體上新的測試方法讓系統的質量比之前好了不少。好像有點超時了,先聊到這裏吧,還有好多細節無法展開,下次再聊。(本系列完結)

相關文章
相關標籤/搜索