前言
為滿足 C++ 應用系統故障演練,阿裡媽媽安全生産團隊開源了 C++ 混沌實驗執行器,填補了 C++ 應用混沌工程實驗的空白,其遵循《混沌實驗模型》,可通過 ChaosBlade 工具直接執行。項目詳情點選
這裡! 。
本文重點介紹該執行器的架構圖、支援的實驗場景,并以 Demo 為例介紹具體的使用方式,附錄介紹了阿裡媽媽内部混沌實驗流程。
新版本 chaosblade 下載下傳位址在
!
實驗場景
目前支援的 C++ 混沌實驗場景如下,具體使用方式可詳見下文:
- 針對某個方法,或者某行代碼注入延遲故障;
- 針對某個方法,或者某行代碼注入替換變量,或者對象值,可以制造調用第三方接口傳回結果中包含錯誤碼等等故障;
- 針對某個方法,或者某行代碼注入立刻退出方法并傳回指定值(可以是錯誤值)的故障;
架構圖
解釋說明:
- C++ 混沌實驗執行器包括 8 個子產品:模型比對器子產品、應用狀态擷取子產品、流程控制子產品、在應用運作中注入故障子產品、應用未啟動狀态啟動應用并注入故障子產品、故障恢複子產品、解除安裝實驗器子產品 和 日志記錄子產品;
- 模型比對器子產品:會把使用者傳入的參數比對《混沌實驗模型》,發現不符合規範的參數,将停止執行,并傳回使用者相應提示;
- 應用狀态擷取子產品:擷取待注入故障的 C++ 應用目前的狀态;
- 流程控制子產品:可以控制整個實驗器的運作流程;
- 在應用運作中注入故障子產品:在 C++ 應用運作狀态時,在不改變應用原有代碼,和編譯檔案的情況下,直接注入故障到程序;
- 應用未啟動狀态啟動應用并注入故障子產品:在 C++ 應用未啟動狀态,在不改變應用原有代碼,和編譯檔案的情況下,啟動應用,并同時注入故障;
- 故障恢複子產品:當某一個實驗或演練場景完成,基于該子產品移除該場景的故障;
- 解除安裝實驗器子產品:當所有實驗或演練場景都完成,基于該子產品移除應用所有故障,并退出 C++ 混沌實驗執行器的程序;
- 日志記錄子產品:可以把 C++ 混沌實驗執行器運作過程中的情況記錄到日志中;
- C++ 應用:待注入故障的應用,在故障注入過程中,C++ 混沌實驗執行器通過 attach 方式把 C++ 應用做為自己的子程序進行狀态跟蹤;
- ChaosBlade:混沌實驗注入工具;
使用方法
可以通過如下三種方式對 C++ 應用注入故障:
- 登入待注入故障的機器,使用 chaosblade 提供的指令行方式實施演練;
- 登入待注入故障的機器,手動啟動 C++ 應用混沌實驗執行器,直接調用執行器提供的 api 實施演練;
- 通過混沌實驗平台,可以很友善的對多台機器,甚至整個分組叢集同時注入故障,阿裡雲 AHAS 後續會支援此執行器;
接下來,通過一個 C++ 應用混沌實驗 DEMO 給大家介紹前兩種方式怎樣實作一次 C++ 應用的混沌實驗。
C++ 應用混沌實驗DEMO
這次實驗,我們演練 linux 系統下 C++ 實作的 socket server 應用和 socket client 應用通訊的過程中,socket server 接口延遲 3 秒。接下來我們下載下傳所需要的 Socket Demo:
Socket-server.tar.gz下載下傳位址,詳情參考
!
下載下傳完成後,解壓并編譯:
g++ -g -c tcp_server.cpp -o tcp_server.o
g++ -g tcp_server.o main.cpp -I. -o server
Socket-client.tar.gz下載下傳位址,詳情參考
g++ -g -c tcp_client.cpp -o tcp_client.o
g++ -g tcp_client.o main.cpp -I. -o client
啟動 socket server:
./server 9527
啟動 socket client:
./client 127.0.0.1 9527
啟動成功以後會提示:"send message to server"
接下來輸入想傳給 socket server 内容比如:666
socket server 應用收到消息以後提示:
Received a connection from 127.0.0.1
Received message: 666
完成以上步驟表示 socket server 應用和 socket client 應用部署成功。
通過 chaosblade 的指令行方式實施演練
接下來我們要使用 blade 工具進行混沌實驗,在執行實驗前,我們需要先執行 prepare 指令,挂載所需要的 c++ agent:
./blade prepare cplus --port 8370 --wait-time 10
傳回以下結果,表示實驗準備成功:
{"code":200,"success":true,"result":"e669d57f079a00cc"}
我們開始實施混沌實驗,調用 socket server 接口延遲 3 秒,我們執行以下指令:
./blade create cplus delay --delayDuration 3 --breakLine tcp_server.cpp:33 --fileLocateAndName /home/admin/socketServer/server --forkMode child --processName server --initParams 9527 --libLoad /home/lib
傳回以下結果,表示執行成功;
{"code":200,"success":true,"result":"ec695fee1e458fc6"}
對實施實驗的指令進行解析:
- --delayDuration: 3,表示延遲 3 s;機關是 s (delay action 特有的過濾條件)
- --breakLine: tcp_server.cpp:33, 加入斷點的位置,可以是某一行,也可以是某個方法名 (對應混沌實驗模型的 Matcher:實驗規則比對器)
- --fileLocateAndName: /home/admin/socketServer/server,C++應用可執行檔案的位置和名字 (對應混沌實驗模型的 Matcher:實驗規則比對器)
- --forkMode: child,表示我們把故障注入到子程序還是父程序 (對應混沌實驗模型的 Matcher:實驗規則比對器)
- --processName: server,可以唯一辨別出C++應用程序的辨別,比如程序名 (對應混沌實驗模型的 Matcher:實驗規則比對器)
- --initParams: 9527,C++ 程序正常啟動的時候,啟動指令中執行檔案後面的參數 (對應混沌實驗模型的 Matcher:實驗規則比對器)
- --libLoad: /home/lib,如果啟動C++ 程序的時候如果需要設定類庫檔案夾位址,可以在這裡設定(比如 /home/lib),如果啟動時,不需要加載自定義類庫,該項可以填入空格 (對應混沌實驗模型的 Matcher:實驗規則比對器)
完成實驗後,可以執行如下指令停止目前延遲的混沌實驗:
./blade destroy ec695fee1e458fc6
ec695fee1e458fc6 是之前建立實驗傳回的 UID
注:接收到 destroy 請求後,會删除與 UID 相對應的混沌實驗規則。
不盡興的話,我們再實施對 server 内部變量的修改,把 server 對外開放的監聽端口 9527 改成 9529。
和剛才延遲指令參數差不多,因為相同的參數是演練 C++ 應用所需要的,不同的是沒有了 --delayDuration,多了個 --varaibleName 和 --varaibleValue 參數。我們模拟調用剛才的服務對外開放的監聽端口 9527 改成 9529:
./blade c cplus modify --varaibleName listen_port --varaibleValue 9529 --breakLine tcp_server.cpp:11 --fileLocateAndName /home/admin/socketServer/server --forkMode child --processName server --initParams 9527 --libLoad /home/lib
傳回以下結果,并在 socket client 可驗證端口是否被修改。
{"code":200,"success":true,"result":"09dd96f4c062df69"}
停止此次試驗:
./blade destroy 09dd96f4c062df69
最後,我們撤銷剛才的實驗準備,即解除安裝 c++ Agent:
./blade revoke e669d57f079a00cc
直接調用執行器提供的 api 實施演練
挂載所需要的 c++ agent:
nohup java -jar chaosblade-exec-cplus.jar --server.port=8703 --script.location=/home/staragent/plugins/monkeyking/chaosblade/lib/cplus/ &
開始故障注入,發送 url 請求:
chaosblade/create?suid=e669d57f079a00cc&target=cplus&action=delay&breakLine=tcp_server.cpp:33&fileLocateAndName=/home/admin/socketServer/server&forkMode=child&processName=server&delayDuration=3&initParams=9527&libLoad=
其中請求參數為
{
"suid": "e669d57f079a00cc",
"target": "cplus",
"action": "delay",
"breakLine": "tcp_server.cpp:33",
"fileLocateAndName": "/home/admin/socketServer/server",
"forkMode": "child",
"processName": "server",
"delayDuration": “3”,
"initParams": "9527",
"libLoad": ""
}
這種方式增加了幾個參數,解析如下:
create: 建立混沌實驗請求
suid: 請求參數,實驗的 ID,後續停止實驗會用到此 ID
target: 請求參數,實驗的元件目标,cplus 代表 針對 C++ 應用的實驗
action: 請求參數,執行實驗的場景,delay
注:
suid、target、action 是 create 請求的必要參數, breakLine、fileLocateAndName、forkMode、processName、delayDuration、initParams、libLoad 參數根據 target 和 action 的不同而不同。
接收到請求,會根據 target 和 action 調用參數校驗器,驗證參數值是否合法,如果合法,則記錄此次試驗;
對應元件埋點觸發時,如果查詢到有此元件的實驗,則擷取比對器所需參數,和下發的實驗規則進行比對,比對成功,則調用場景執行器觸發實驗。
停止此次試驗,通過發url 請求:chaosblade/destroy?suid=ec695fee1e458fc6
其中請求參數是:
{
"suid": "ec695fee1e458fc6"
}
suid: 請求參數,之前建立實驗傳回的 UID
最後,我們撤銷剛才的實驗準備,即解除安裝 c++ Agent,通過發url 請求:chaosblade/remove
後續規劃
後續會加入更多混沌實驗場景,也歡迎大家試用,提 issue、pr,star, 一起交流、探索和完善。
chaosblade github 位址點選
github 位址點選
附錄
實驗流程 & 原理
以上流程中,在實際的故障模拟演練,或突襲演練中,實驗準備階段,故障注入階段,故障恢複階段 和 實驗器解除安裝階段,為故障注入方(或藍軍)操作,故障效果采集監控項有效性驗證,故障處置階段為故障模拟成功以後,故障注入方(或藍軍)确認故障注入效果,也是故障處置方(或紅軍)接收報警,定位,并處置故障的階段;
實驗執行器底層基于 GDB 實作,故障注入階段有提到啟動 gdb 一步。
本文作者:
周鵬飛,花名鵬毅(@leonardo669),C++混沌實驗執行器作者,阿裡巴巴技術專家。