前段时间接手了一份维护老系统的任务。该系统使用了早期的 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?。