“故障注入 Sidecar“——爲您的微服務注入故障以驗證集羣性能! 由於導師和實驗室師兄們的科研需要,本人專門以 Sidecar
的模式設計了一個用於錯誤注入的微服務模塊。該模塊可以與任何微服務應用共同部署運行,爲其模擬cpu、內存等錯誤。 本項目的 Github
地址: https://github.com/iscas-micr...
我的聯繫方式: [email protected] || 或直接留言 歡迎您提出問題批評指點!
項目背景
目前,本人正在中科院軟件所的微服務研究組從事部分研究工作。由於本人所在科研小組的研究內容( 微服務自動擴縮容相關 ),需要經常使微服務應用處於"高 CPU 利用率" 和 "高內存使用"的狀態。因此,爲了方便導師和實驗室的各位師兄進行實驗,本人特地開發了一個可以注入進 Pod 中的錯誤注入容器,來模擬上述的高負載狀態。
導師和師兄們使用後對我的工作給予了肯定,因此我準備將開發過程和簡單使用方法寫成文章做個記錄( 也就是本文 ),一來方便自己日後工作學習,二來也方便有類似實驗需求的其他同仁們使用這個小項目,爲大家的研究節省時間。更具體的安裝和使用方法,可以移步本項目 Github 的代碼倉庫,其中有非常詳細的說明。
知識儲備
什麼是微服務中的"Sidecar 運行模式?"
上圖: 以 Sidecar 模式部署並運行的微服務單元
Sidecar 運行模式是最近兩年比較火的一種微服務部署和運行方法,它由目前流行的 ServiceMesh(服務網格) 架構推廣而來。
具體而言,Sidecar 運行模式是一種"將不屬於業務應用的功能以獨立的容器運行於業務容器旁邊",在 K8s 中表現出的樣子就是將具有不同功能的模塊封裝成不同的鏡像,並以不同的容器運行在同一個 Pod 中。這種說法非常形象,因爲 Sidecar 這個單詞的本意就是三輪摩托側面的"跨鬥",這裏形容獨立於業務應用但又與業務應用部署在一起非常合適。
上圖: Sidecar ,中文意思爲摩托車的跨鬥,不由讚歎命名的非常生動
主要設計思想
架構設計
本項目的錯誤注入模塊也採用了 Sidecar 這種設計思想,將用於模擬 CPU、內存等故障的模塊獨立封裝成一個鏡像,並在 Pod 啓動時以 Sidecar 的形式運行在主業務容器旁邊。這樣,不用它時他就會安安靜靜地當個美男子,完全不用擔心它會影響到正常業務的運行;一旦需要它模擬錯誤產生,由於與業務容器同處於一個 Pod 之中(而 K8s 又以 Pod 爲基本單元),因此他模擬出的錯誤亦被 K8s 集羣視爲業務應用所在 Pod 產生而被監測到。
上圖: Pod 中的每個容器都有自己的端口映射到外部主機,因此不會相互影響
注入方式設計
本項目在設計之初是採用“在容器內修改環境變量”的方式對容器注入故障的,但事實證明這種方法太low,而且非常麻煩。因此在後續設計和實現中採用了目前較爲流行的通過 REST API 傳遞 POST 請求的方式使容器模擬錯誤,這樣就極大地方便了師兄們展開實驗,而且也可以模擬出“微服務間調用而產生錯誤”的場景( 上游服務調用錯誤注入的 API 而模擬下游服務產生錯誤 )。
多進程模擬故障產生
此外,原本該項目的實現是單進程的,故每注入一個錯誤都要等待錯誤結束後才能獲得應答並注入下一個錯誤,這十分不利於實驗的進行。因此在後面我們改爲了多進程運行,即每當一個錯誤產生時,程序都會建立一個子進程用於運行錯誤故障,而原來的進程則立刻產生注入是否成功的應答並繼續監聽相應的服務端口,從而滿足應答實時彙報和多種錯誤同時注入的功能需求。
上圖: 該程序的主要運行流程-以 “A 進程監聽服務端口”的狀態爲起點
使用說明( 故障注入的方法 )
啓動服務
本應用以 Web 服務的方式運行,並封裝爲鏡像保存於 DockerHub 上。因此使用之前需要先以容器的形式運行鏡像。以 docker 命令運行本應用的參考命令如下所示:
# 使用 docker 命令簡單測試該應用( 測試版本爲 docker 18.03-ce )
docker run --rm -it -d --name fault-injection-server -p 5000:5000 xinyaotian/micro-fault-injection:1.0.0
待容器就緒後,訪問您啓動該容器的主機 IP 的 5000 號端口,如果出現了使用指引界面,就表明您的服務啓動成功,可以參考使用說明進行錯誤注入了。
上圖: 爲了方便師兄們和大家的使用, 特地在服務首頁製作了簡易的使用方法指引, 爲大家節省查 Github 文檔的時間
錯誤注入
本項目主要支持四種故障類型: cpu、內存、磁盤和網絡,均通過 POST 請求向 /fault-inject 搭配相應參數進行注入。具體的注入方法如下所示( 注意更改 IP 和端口號 ):
1.注入 CPU 故障
# fault_type=cpu 指定錯誤故障類型(此處爲 cpu 類型)
# thread_num=4 觸發該錯誤的線程數(此處爲 4 個線程)
# duration=15 故障持續時間,單位爲秒(此處爲 15 秒)
curl -X POST -d 'fault_type=cpu&thread_num=4&duration=15' http://localhost:5000/fault-inject
2. 注入內存故障
# fault_type=mem 指定錯誤故障類型(此處爲 mem 類型)
# mem_size=120M 指定內存泄露的數值(此處爲 120M ,注意 M 不能省略)
# thread_num=4 觸發該錯誤的線程數(此處爲 4 個線程)
# duration=15 故障持續時間,單位爲秒(此處爲 15 秒)
curl -X POST -d 'fault_type=mem&mem_size=120M&thread_num=4&duration=15' http://localhost:5000/fault-inject
3.注入磁盤故障
# fault_type=disk 指定錯誤故障類型(此處爲 disk 類型)
# io_times=4
# duration=15 故障持續時間,單位爲秒(此處爲 15 秒)
curl -X POST -d 'fault_type=disk&io_times=4&duration=15' http://localhost:5000/fault-inject
4.注入網絡故障
# fault_type=net 指定錯誤故障類型(此處爲 net 類型)
# net_port=100
curl -X POST -d 'fault_type=net&net_port=100' http://localhost:5000/fault-inject
在 K8s 或 Istio 上運行( 基於 yaml )
本項目的鏡像將作爲原本微服務應用的 Sidecar 獨立部署運行, 因此在 K8s 環境中其應該與業務應用部署於同一個 Pod 之中。
您可以利用 yaml 啓動一個單獨的 Pod 來初步體驗一下這個應用。快讀啓動的 yaml 如下所示( Istio 同樣可以這樣寫, K8s 版本爲 1.13.1, Istio 版本爲 1.0.6 ):
---
# 爲 fault injection 創建 service 分配端口 #
---
apiVersion: v1
kind: Service
metadata:
name: single-fault-injection
namespace: default
spec:
selector:
# deployment identifier
# 這個標籤要與 deployment 中相對應
app: fault-injection
ports:
- protocol: TCP
port: 5000 # 容器內端口爲 5000
nodePort: 30050 # 映射至主機的 30050 端口
type: NodePort # 映射方式爲 NodePort
---
# 將該模塊作爲一個獨立的 Pod 在 K8s 上進行部署 #
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: single-fault-injection
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
# svc identifier
# 這個標籤要與 service 中相對應
app: fault-injection
spec:
containers:
# 錯誤注入模塊的 container
- name: fault-injection-container
image: xinyaotian/micro-fault-injection:1.0.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
# 該容器的資源限制, 錯誤注入可使其達到峯值 #
resources:
limits:
cpu: "0.4"
memory: 128Mi
如果您希望以 Sidecar 的形式將本應用部署在其他微服務的 Pod 之中同樣可行,這也是本項目的設計初衷。在 K8s 環境下部署和啓動的 yaml 如下所示意( Istio 同樣可以這樣寫, K8s 版本爲 1.13.1, Istio 版本爲 1.0.6 ):
---
# 爲 fault injection 創建 service 分配端口 #
---
apiVersion: v1
kind: Service
metadata:
name: your-microapp-with-faultinjection
namespace: default
spec:
selector:
# deployment identifier
# 這個標籤要與 deployment 中相對應
app: sidecar-fault-injection
ports:
- protocol: TCP
port: 5000
nodePort: 30050
type: NodePort
---
# 相應的 deployment 配置( 與原應用配置在一起 )
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: your-microapp-with-faultinjection
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
# svc identifier
# 這個標籤要與 service 中相對應
app: sidecar-fault-injection
spec:
containers:
# 你原來應用的 container 信息
- name: your-micro-app
image: your-docker-name/project:1.0
imagePullPolicy: IfNotPresent
env:
- name: PATH_VALUE
value: "example"
ports:
- containerPort: 80
# ------------------- #
# Sidecar 錯誤注入模塊的 container
- name: fault-injection-sidecar
image: xinyaotian/micro-fault-injection:1.0.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
# ------------------- #
---
在我自己的實驗集羣上,利用 Istio 啓動該服務,並對其注入內存故障後,可以在 Grafana 監控面板上清晰地看到微服務 Pod 的內存忽高忽低,非常有趣。 錯誤注入的結果如下圖所示。
上圖: 注入內存故障後, 我自己的 Istio 集羣監測微服務資源面板的可視化展現
後續版本開發展望
項目到這裏已經滿足了實驗室內師兄們絕大部分的科研需求。在之後的迭代中預計還會加入故障的產生速率( 例如 CPU 使用率會呈線性或指數上漲等 ),相應的 API 也會採用向前兼容的形式進行擴充( 添加更多的可選參數,不填則設置爲默認值 ),以確保這個版本或之前版本使用者的代碼無需改變而可繼續使用後續版本。
此外,簡單的用戶控制面板也會在後續版本中開發。通過提供的用戶界面,使用者可以在界面上輸入參數並通過按鈕進行錯誤注入,而不再僅僅通過發送 POST 請求( 雖然底層原理還是本地請求 )。相信用戶界面會在彙報演示時爲導師和師兄們帶來諸多便利。
小結
本項目主要以 Sidecar 的方式開發了一個用於錯誤注入的實驗鏡像,並通過在 docker 和 k8s 上運行從而達到對微服務單元注入故障的目標,爲研究集羣自動擴縮容、微服務自動擴縮容等課題提供了前提保障和研究條件。
致謝
感謝您的閱讀,如果您對這個項目有什麼更好的建議,或指出哪裏設計有問題,我都會非常歡迎,洗耳恭聽。非常希望於讀完本文的您進行交流,歡迎您在下方留言。
如果您的科研團隊也有類似需求,也非常歡迎與我們進行合作,並對針對本項目提出寶貴的改進意見。