1.問題背景:
我們項目里用到了dubbo分布式框架,使用了redis注冊中心,當服務shutdown時,沒有向注冊中心注銷服務,也沒有向consumer unregister;導致在服務重啟后,第一次連接繼續連接老的服務ip上並無法連接;
2.問題原因:
①阿里雲的托管k8s集群當時還不支持shutdown hook,以及shutdown gracefully;
②kubelet發送kill命令(TERM signal)給容器類的1號進程,如果你運行的程序在別的進程上,那么就接受不到kill命令。
③啟動服務使用 $ sh script.sh 命令在sh腳本中直接用 java -jar 命令啟動,導致java進程不是1號進程。
3.解決辦法:
第一步,切換為支持shutdown gracefully的k8s集群
第二步,還是使用 $ sh script.sh 方式啟動程序,不過啟動命令改為 exec java -jar,讓java程序運行在1號進程。
4.知識點:
①Linux kill命令
Linux kill命令用於刪除執行中的程序或工作;
kill [-s <信息名稱或編號>][程序PID] 或 kill [-l <信息編號>]
執行kill(默認kill -15)命令,系統會發送一個SIGTERM信號給對應的程序。當程序接收到該signal信號后,一般會先釋放資源,然后自行停止進程;當然也可能最終阻塞住沒有結束;
執行kill -9 命令,系統給對應程序發送的信號是SIGKILL,即exit。會強制終結進程,不會有任何其他操作;
②Kubernetes優雅停機策略
Kubernetes在終結pods的時候,默認會向每個container的1號進程發送TERM signal,優雅停機默認會容許30秒的停機周期;於此同時負載均衡也會將正在終結的pod從Endpoint中移除,這樣就不會有新的流量流進將會被移除的pod
③shell,exec,source的區別
$ sh script.sh 執行腳本時,當前shell是父進程,生成一個子shell進程,在子shell中執行腳本。腳本執行完畢,退出子shell,回到當前shell
$ source script.sh 方式,在當前上下文中執行腳本,不會生成新的進程。腳本執行完畢,回到當前shell
exec command 方式,會用command進程替換當前shell進程,並且保持PID不變。執行完畢,直接退出,不回到之前的shell環境。
