前段時間接手了一份維護老系統的任務。該系統使用了早期的 Spring Cloud 全家桶,其中有一個微服務隨着時間運行會出現大量 CLOSE_WAIT 狀態的 socket 鏈接以致於堵塞網關,檢查後發現與 HttpClient 相關(可參考 解決:HttpClient致使應用出現過多Close_Wait的問題 這篇博文),可是因爲沒有完整的源碼,沒法經過博文裏提到的方法解決。所以考慮經過外部手段檢測並重啓服務來恢復網關與服務的通信,簡單的檢測手段是經過發起 HTTP 請求看超時狀況:html
$ curl --connect-timeout 10 -m 10 <host>:<port>
咱們使用了 Kubernetes 做爲部署環境,它使用存活探測器來知道何時要重啓容器。存活探測器有三種類型:shell
因爲咱們須要檢測的服務的問題是容器內存在大量的 CLOSE_WAIT 狀態鏈接,此時新的 socket 鏈接已經沒法連通,使用 HTTP 存活探測時其超時檢查沒法做用於 socket 超時,所以應該使用 TCP 存活探測。json
參照 Kubernetes 官方文檔提供的示例便可配置相關探測器:ubuntu
apiVersion: v1 kind: Pod metadata: name: goproxy labels: app: goproxy spec: containers: - name: goproxy image: k8s.gcr.io/goproxy:0.1 ports: - containerPort: 8080 readinessProbe: tcpSocket: port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 15 periodSeconds: 20
注意 :更多信息參見 定義 TCP 的存活探測 。api
通過一段的運行後,Kubernetes 自帶的存活探測工做良好,可是客戶但願能獲悉服務實例重啓的信息,即每當服務實例重啓時發送消息至羣聊。app
一開始考慮使用 BOTKUBE 收集服務實例重啓信息,可是有幾個小問題:curl
可是客戶但願能在釘釘羣裏中獲悉 「N 個實例中重啓了 M 個」 信息以進行評估穩定性。socket
若是經過 Webhook 接入 BOTKUBE,則須要在一個短暫的週期內維護服務的總實例數與週期內重啓實例數量。相關編碼工做量太大,因而咱們經過編寫簡單的腳本並配置 cron 定時任務來完成該需求。tcp
假定咱們要檢查的服務名稱爲 service 。
export KUBECONFIG=/path/to/your/kubernetes.yaml pods="" total=`/usr/local/bin/kubectl --kubeconfig=$KUBECONFIG get pods -o wide | grep service | sed -n '$='` # 1 for pod in `/usr/local/bin/kubectl --kubeconfig=$KUBECONFIG get pods -o wide | grep service | awk '{print $1 "_" $6}'` # 2 do name=`echo $pod | awk -F_ '{print $1}'` ip=`echo $pod | awk -F_ '{print $2}'` sname=`echo $name | awk -F- '{print $5}'` curl -s --connect-timeout 10 -m 10 $ip:8672 > /dev/null # 3 if [ $? -ne 0 ]; then # 4 /usr/local/bin/kubectl delete pod $name pods="$pods$sname ×, " else pods="$pods$sname √, " fi done pods="${pods%??}" # 5 success=`echo $pods | awk -F"√" '{print NF-1}'` # 6 if [ $success -ne $total ]; then # 7 curl 'https://oapi.dingtalk.com/robot/send?access_token=***' \ -H 'Content-Type: application/json' \ -d '{ "msgtype": "text", "text": { "content": "檢查結果 ['"$success"'/'"$total"'] :\n'"${pods}"'" } }' fi
kubectl delete
刪除它,還須要 pod 的虛擬 ip 地址以經過 curl
測試鏈接狀況;curl
的鏈接狀態信息和鏈接成功後的資源下載進度信息,所以經過 -s
參數和重定向到空設備來 靜音 ;curl
因 socket 鏈接超時返回非 0 值時刪除該容器;,<空格>
;效果:ide
檢查結果 [11/12] : wdqdd ×, 5xwpz √, rgmc7 √, 8cf4f √, spttn √, dvw2l √, tg9lw √, kzrc2 √, fpk9s √, 9plpt √, dpkpf √, gnhrl √
咱們使用的是 Ubuntu Server 18,經過 crontab -e
配置定時任務:
*/10 8-22 * * * /path/to/your/script.sh
使用 cron 執行腳本須要注意幾個問題:
chmod +x script.sh
);export
指定路徑,但咱們內部使用且從簡處理,選擇直接指定絕對路徑 /usr/local/bin/kubectl
;更多關於配置 cron 的注意事項能夠參考 Why crontab scripts are not working?。