# Lightning Talk -- 單體應用程式下的混沌工程 (Chaos Engineering) 應用 ###### tags: ``Lightning Talk`` ___ ## 概觀 ### 可量測的 *Monkey try* (Chaos Monkey) * 混沌工程,是因應微服務~~架構~~部署方式、愈來愈複雜的系統部署環境,發展出來的~~測試~~遙測 (telemetry) 方法 * 不過也要先有監測 (monitoring) 機制,才能有效的遙測 * 一般的測試:找到 "知道自己不知道" 的問題 * 混沌工程:探索 "不知道自己不知道" 的問題 ### 術語 * [Watcher](https://codecentric.github.io/chaos-monkey-spring-boot/latest/#watchers) * [Assaults](https://codecentric.github.io/chaos-monkey-spring-boot/latest/#assaults) ## 單體應用程式環境的應用 ### “地端” 單體應用程式和微服務有什麼差別 沒有複雜的部署需求,甚至是沒有部署需求,例如**地端無人看管設備、工具**。畢竟 Chaos Engineering 是大神們因應複雜網路架構、服務,發展出來的系統。 ### 混沌工程實際的應用 **讓壓力測試更 ... 完善?** 在單體應用程式的觀點,不論是整合測試、負載測試,都是在測試 "知道自己不知道" 的問題。但是壓力測試則是對 "超過表定規格" 的部分,測試容錯、復歸等 "不知道自己不知道的事情"。因此可以嘗試用 Monkey try 的方式,讓測試更完整。 **可以用在單元測試嗎?** 可以,但是 Monkey try 的意義與單元測試不同。例如在 BDD 中,單元測試等於 "有商業目的可執行規格",所以 Monkey try 還是留給整合測試來做。 **到底要測試什麼** 就是真的做 Monkey try 的事情,像是網路斷線連線、out of memory。只是這些測試是可以量化、量測的。 ## 技術資源參考 * [``chaos-monkey-spring-boot``](https://github.com/codecentric/chaos-monkey-spring-boot) * [Chaos Mesh](https://chaos-mesh.org/) ## 超簡單練習 -- Kotlin/JVM 單體應用程式的 Chaos Enginnering :::info Kotlin 版 demo 程式: https://github.com/linahbei/chaos-monkey-monolithic/tree/kotlin-chaos-monkey 作者剛從 Kotlin 的 ``Hello, World!`` 開始學,緩慢前進中。 ::: ### 新手議題 **沒有部署環境的產品要怎麼 Monkey try?** 這裡關注的仍然是 "**地端無人看管設備**" 類型的產品。沒有部署環境的意思,通常指的是沒有 IaaS、PaaS,與對應的工具、部署機制。渾沌工程的 Chaos Monkey 工具,通常是為了支援這類環境而開發的,但是我們的單體式應用程式又不在這樣的環境中,所以只能自己想辦法了。 **沒有部署環境,但是應該要有 Lab 環境吧?** 另外,我們在做整合測試的時候,通常燴犯一個錯誤,就是沒有準備乾淨的 Lab、staging 環境。即使是單體式的應用程式,也需要乾淨的 Lab 環境來做整合測試。其中最簡單的原因,就是 dev 環境通常該有的都有了,或是為了讓程式能動,也有一些作弊的配置。所以有時候就會遇到,東西怎麼測試都過關,但是一到使用者環境就壞掉的尷尬情況。 **沒有部署環境,但是應用程式可以吃設定檔吧?** 即使我們的單體應用程式真的很簡單,但是從安裝、使用的角度來看,應該還是會支援基本的環境變數、設定檔,或是 license key 吧?這些可以吃設定檔的機制,其實也是最基礎、低標得部署機制了,也是 Chaos Engineering 的測試點。 **要怎麼監測、遙測單體應用程式?** 首先最基本的,就是要有可讀、有意義的 log。有了這些可讀、有意義的 log,就可以做到最簡單的監測機制,然後才能和 Chaos monkey 整合,去量測測試結果。如果團隊還沒有用到 Elastic Stack 這類 "現代" 工具,其實先把程式的 log 認真寫好,然後把 Nagios 架起來也是可以的。 **從瞎測到壓測** 在業界我們最常聽到的就是壓測這個名詞,再怎麼不了解自家產品的同仁,在出貨前也會出聲提醒 "記得要壓測"。但是我們在了解效能、負載、壓力、~~燒雞~~燒機測試後,或許會發現壓測這兩個字,有時候被用的很隨興,或者實際上就是瞎測。因此才需要了解渾沌工程,用有效、可量測的方法,改善原本用 "混亂工程" 的 Monkey try。 ### 範例應用程式設計 (實作開始) 我們先設計一個很簡單,但是具有 "**地端無人看管設備**" 應用程式特性,預備用來練習 Chaos Engineering 的 (Kotlin/JVM) [Daemon 程式](https://github.com/linahbei/chaos-monkey-monolithic/blob/c5075dfb18163e5dd653e17b92e04f2e2330d328/kotlin-chaos-monkey/src/main/kotlin/mono/MonoDaemon.kt#L66),和 [Client 範例 ](https://github.com/linahbei/chaos-monkey-monolithic/blob/kotlin-chaos-monkey/kotlin-chaos-monkey/src/main/kotlin/Main.kt)。 :::info **Command consumer *daemon app*** * Producter 可以一直送出指令 * Consumer 會及時處理指令 * Rate limit 為 3 秒一個指令,指令送太快會被 Consumer 丟掉 * Chaos monkey 應該要幫忙測試什麼? ::: 執行結果如下,會印出由 Producter 送出的指令名稱、狀態 (被執行或是丟掉),和最初送出指令的時間。 ```shell 1: executed (added: 1646638812728) 2: dropped (added: 1646638812728) 3: executed (added: 1646638812728) 4: dropped (added: 1646638812728) 5: executed (added: 1646638812728) 6: executed (added: 1646638815728) ``` ### 撰寫 Unit test ("我知道我不知道的問題") [提供 3 個測試](https://github.com/linahbei/chaos-monkey-monolithic/blob/kotlin-chaos-monkey/kotlin-chaos-monkey/src/test/kotlin/MonoDaemonTest.kt): * ``test_only_one_command_then_status_executed`` * ``test_over_rate_limit_command_status_not_keep_added`` * ``test_in_rate_limit_commands_executed`` #### 從*寫成這樣的單元測試*看問題 在測試程式中會看到一個 ``dummyCommandCost`` 變數,用來調整 "daemon app 預計多久會處理完 command" 的時間,然後我們在這個時間過後再來檢查執行結果 **-- 因此這是個不太 OK 的單元測試**,因為這表示測試結果會受到 "測試平台、系統效能" 的影響;但是這應該是後面效能測試、混沌工程的責任了,不應該讓單元測試的結果,被執行環境影響。 **單元測試會寫成這樣,通常表示 "最小可執行單元" 還不夠小**,耦合度太高。而且這不僅僅是單元測試不好寫的問題,背後代表的問題是 "程式太難用,難用到無法被測試",也代表可維護性、應付變動的能力,還有很大的改善空間。如果專案中 "測試很難寫" 的程式夠多,也代表開發資源都浪費在修修改改、挖洞補洞上了。 ### 整合 Chaos monkey 做 Monkey Try ("我不知道我不知道的問題") #### 回到之前的問題 -- 沒有部署、遠端管理的實體環境,要怎麼做自動化的 Monkey Try?有需要做嗎? #### **實體環境**參數 * OS: Win 10, Linux * Daemon App: Kotlin/JVM * Interface: TCP #### 選擇 Chaos Monkey #### 加入 Assualt 我們第一個要加入的就是 [CPU Assault](https://codecentric.github.io/chaos-monkey-spring-boot/latest/),讓 "效能會影響結果" 的測試,從單元測試,右移到負載、壓力測試階段。 #### 加入 Watcher #### 改善單元測試 改寫單元測試,移除 runtime 狀態相依的測試變數。 :::danger -- 進度緩慢分隔線 -- :::