"I don’t care if it works on your machine! We are not shipping your machine!" - Vidiu Platon
「我才不管它能不能在你的機器上執行捏!我們又不會給你提供機器!」 —— 韋都·柏拉圖
隨著微服務架構風格的推廣應用,開發人員的本地開發和偵錯成本大大提高,甚至不堪重負。動不動就要依賴一攬子東西,註冊中心、Redis、MQ、基礎服務ABC……等等。
開發人員如果手工在本地啟停多個基礎服務和中介軟體,將會浪費大量時間,降低開發效率。
Docker
和Kubernetes
,不缺錢也不缺人的首選。什麼雙活、負載均衡統統來個四五套,把寒氣也傳給運維人員。
為了節約成本,當然是要在本地啟動一整套系統節點啦,畢竟記憶體成本比人力成本低得多。但是手工啟停太浪費時間了,這樣會導致本來就不多的摸魚時間所剩無幾。人生苦短,我用指令碼。
確定了方案,我就開始著手編排了,以一個Zookeeper + Redis(一主二從三哨兵)的啟停指令碼為目標,設定過程就略過了,著重解決啟停的問題。
@echo off
color 5f
title fake-docker
echo ^>^>^>^>^>^>^>^>bootstrapping redis...
start "redis-master" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.master-1.conf"
start "redis-slaver-1" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.slaver-1.conf"
start "redis-slaver-2" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.slaver-2.conf"
start "redis-sentinel-1" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.sentinel-1.conf" --sentinel
start "redis-sentinel-2" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.sentinel-2.conf" --sentinel
start "redis-sentinel-3" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.sentinel-3.conf" --sentinel
echo ^>^>^>^>^>^>^>^>done!
echo ^>^>^>^>^>^>^>^>bootstrapping zookeeper...
start "zookeeper-dev" "c:\dev\apache-zookeeper-3.6.3-bin\bin\zkServer.cmd"
echo ^>^>^>^>^>^>^>^>system is hot!
@echo off
color 5f
echo ^>^>^>^>^>^>^>^>shutdowning...
taskkill /t /f /fi "imagename eq redis-server.exe" >nul
taskkill /t /f /fi "windowtitle eq zookeeper-dev" >nul
echo ^>^>^>^>^>^>^>^>system is down!
pause>nul
第一個版本,解決了啟動和停止的問題,但是是手動檔的,重啟中介軟體的話要執行兩個指令碼。待改進的問題有兩個:
第一個問題容易解決,先停後起,先執行停止指令,再把應用拉起來。
第二個問題有點麻煩,一開始想嘗試無視窗啟動,反覆嘗試未果,後來採用了折中方案,在CMD
的start
命令幫助中有如下描述:
C:\Users\Master>help start
啟動一個單獨的視窗以執行指定的程式或命令。
START ["title"] [/D path] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED]
[/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL]
[/NODE] [/AFFINITY ] [/WAIT] [/B]
[command/program] [parameters]"title" 在視窗標題列中顯示的標題。 path 啟動目錄。 B 啟動應用程式,但不建立新視窗。 應用程式已忽略 ^C 處理。除非應用程式 啟用 ^C 處理,否則 ^Break 是唯一可以中斷 該應用程式的方式。 I 新的環境將是傳遞 給 cmd.exe 的原始環境,而不是當前環境。 MIN 以最小化方式啟動視窗。 MAX 以最大化方式啟動視窗。 SEPARATE 在單獨的記憶體空間中啟動 16 位 Windows 程式。 SHARED 在共用記憶體空間中啟動 16 位 Windows 程式。 LOW 在 IDLE 優先順序類中啟動應用程式。 NORMAL 在 NORMAL 優先順序類中啟動應用程式。 HIGH 在 HIGH 優先順序類中啟動應用程式。 REALTIME 在 REALTIME 優先順序類中啟動應用程式。 ABOVENORMAL 在 ABOVENORMAL 優先順序類中啟動應用程式。 BELOWNORMAL 在 BELOWNORMAL 優先順序類中啟動應用程式。 NODE 將首選非一致性記憶體結構(NUMA)節點指定為 十進位制整數。 AFFINITY 將處理器關聯掩碼指定為十六進位制數位。
根據描述,如果start
時帶上/b
引數,就能讓多個程式在一個視窗中寄宿。修改後得到最終版本:
@echo off
color 5f
title %date%
echo ^>^>^>^>^>^>^>^>cleaning up context...
echo ^>^>^>^>^>^>^>^>killing previous runner...
taskkill /t /f /fi "imagename eq redis-server.exe" >nul
taskkill /t /f /fi "windowtitle eq fake-docker*" >nul
timeout /t 3 /nobreak >nul
rd /s /q "c:\tmp\zookeeper">nul
echo ^>^>^>^>^>^>^>^>clean up context done!
title fake-docker
echo ^>^>^>^>^>^>^>^>bootstrapping redis...
start /b "redis-master" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.master-1.conf"
start /b "redis-slaver-1" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.slaver-1.conf"
start /b "redis-slaver-2" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.slaver-2.conf"
start /b "redis-sentinel-1" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.sentinel-1.conf" --sentinel
start /b "redis-sentinel-2" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.sentinel-2.conf" --sentinel
start /b "redis-sentinel-3" "c:\dev\redis-x64-3.2.100\redis-server.exe" "c:/dev/redis-x64-3.2.100/redis.sentinel-3.conf" --sentinel
echo ^>^>^>^>^>^>^>^>done!
echo ^>^>^>^>^>^>^>^>bootstrapping zookeeper...
start /b "zookeeper-dev" "c:\dev\apache-zookeeper-3.6.3-bin\bin\zkServer.cmd"
echo ^>^>^>^>^>^>^>^>system is hot!
最終版本,實現了一鍵啟停,只會產生一個命令列視窗,屬於能用的範疇了。在此基礎上,可以根據專案情況,自行新增其他中介軟體或基礎服務的啟停命令。
分散式應用偵錯和部署不可避免會面臨幾個問題:
通常由於架構的原因,為了偵錯某個中間節點或上游應用的功能,需要把相關的應用都啟動起來,如果手工啟停,無疑是痛苦的。
如果不能把整個系統都在本地啟動起來,那麼本地就會有一部分服務依賴於外部公共環境,它們通常不止一個人甚至不止一個團隊在用。 一旦外部服務不可用,就會影響到原生的開發和測試。
因此準備一個微型本地開發環境是有必要的,至少在開發和偵錯階段。況且如果最困難的啟停問題被解決了,何樂不為呢?