# 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
-- 進度緩慢分隔線 --
:::