项目场景:
k8s部署的微服务应用,线上环境某个微服务应用异常了,怎么办,如何处理?
问题描述
1.前段时间,公司的采集服务,老是异常,导致线上功能用不了,甚至报错
2.尝试重启服务解决,但过几个小时,又来了。应用日志也不明显,找不到根本原因
3.为此,仅仅只是重启远远不够的,需要追究根本原因
4.那么,k8s部署的微服务应用,线上环境某个微服务应用异常了,怎么办,如何处理?
原因分析:
1.查看采集服务日志
[root@master ~]# kubectl get pod |grep collect
data-collector-service-zhizhi-5fb9df9586-shrhc 1/1 Running 0 41d
[root@master ~]# kubectl logs -f --tail=400 data-collector-service-zhizhi-5fb9df9586-shrhc
#关键日志如下,33030为eureka端口
Caused by: org.apache.http.NoHttpResponseException: 192.168.5.12:33030 failed to respond
由此判断,连接注册中心超时了,查看异常时,也从注册中心掉线了。但实际上服务不健康的时候就会导致连接不上eureka,所以这里的日志也只是表面日志,继续观察
2.查看zabbix节点负载情况,内存有徒增情况,但这只是节点级别的,这个节点有很多pod不能精准定位是哪个pod导致 的
3.于是通过promethues查看pod监控信息,发现异2个异常点
看图发现网络带宽徒增,貌似有问题
看图发现pod内存暴增到30G,平常正常的最多只用到2个G
4.判断分析,主要是由哪个指标导致的异常。
分析:首先这个是内网环境,节点之间网络传输达到几十M都是正常现象,所以网络带宽徒增并不是我们的问题所在。如果是公网环境还可以归根一下网络带宽是有问题的。故排除内网环境,带宽徒增导致的异常。
5.既然是内存暴增引起的,会不会是OOM导致的呢或者是jvm参数不够导致的,虽然日志并没有报错OOM,系统日志/var/log/messages也没有查到oom相关信息
[root@node01 ~]# grep -i oom /var/log/messages
[root@node01 ~]#
#说明没有oom系统报错
#进到master主机看看jvm设置
[root@master ~]# cat collect_deployment.yml
env:
- name: JAVA_OPTS
value: '-Xmx4096m'
#将这个增大到10倍后再观察,但不能大于本机物理内存
[root@master ~]# cat collect_deployment.yml
env:
- name: JAVA_OPTS
value: '-Xmx40960m'
6.很不辛,增大了,过了几个小时,异常还是复现了。最高到了30个G的内存使用
7.这个时候,日志不明显,重启又会经常复现,也没有oom,那我们只能导出jvm。常见的jvm工具很多,jmap,jstack等,我们这里演示使用jstack
8.基础镜像,保证有jstack命令,我这个环境没有jstack命令,需要改造基础镜像。
#改造过程中可能遇到问题,像这样
/ # jstack 1
1: Unable to get pid of LinuxThreads manager thread
#百度解决一下吧
9.将改造好的镜像上传到私服harbor,这里不演示了
10.重启微服务后,编写自动化脚本,避免凌晨还要自己去手动处理,直接自动化处理
#!/bin/bash
#function:此脚本通过检测pod内存指标,来备份坏的pod,启动新的好的pod。并通过检测是否下线来做出相应的重启操作,支持多实例的pod。脚本有前提条件,部署了kube-promethues才可以使用kubectl top命令哦
for i in `kubectl get pod --show-labels |grep collect|grep -v zhizhi-bak|awk '{print $1}'` ;
do
pod_mem=`kubectl top pod $i |awk 'NR>1 {print $3}'|awk -F 'M' '{print $1}'`
#echo ${pod_mem}
if [ "$pod_mem" -gt 27648 ];then
date && echo $i 内存大于 27648 准备隔离pod
kubectl label pod $i app=data-collector-service-zhizhi-bak --overwrite
#保留3个bak标签的pod
j=0
while [ $j -lt 1 ]
do
bak_num=`kubectl get pod --show-labels --sort-by=.metadata.creationTimestamp |grep collect|grep zhizhi-bak|wc -l`
if [ $bak_num -gt 3 ];then
kubectl delete pod `kubectl get pod --show-labels --sort-by=.metadata.creationTimestamp |grep collect|grep zhizhi-bak |tail -2 |head -1 |awk '{print $1}'`
else j=1
fi
done
sleep 120
fi
a=`curl -s http://user:password@192.168.5.12:33030/eureka/apps/你的注册中心的服务名 |grep -i status`
echo $a |grep -i up
if [ "$?" != 0 ] ; then
echo " 注册 failed"
kubectl delete pod `kubectl get pod --show-labels |grep collect|grep -v zhizhi-bak|grep Running|awk '{print $1}'`
fi
done
11.解释一下脚本的算法,因为发现异常时,有时候会看到内存暴增现象,有时候会发现服务从注册中心掉线,所以对这2个情况都做了判断。循环只写了2层,避免了逻辑的复杂性。sleep时间,你自己根据你的环境进行调整即可,其他内容服务名,svc都要改成你的。
12.创建定时任务
[root@master data-collector]# chmod +x /root/test_pod_mem.sh
[root@master data-collector]# crontab -e
#添加这一行后保存
*/4 * * * * /bin/bash /root/test_pod_mem.sh >>/root/test_pod_mem.log &
13.坐等异常发生,后使用jstack命令导出堆栈信息
[root@容器id data-collector]# top
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
6 1 root S 3929m 44% 2 0% java -javaagent:/usr/skywalking/agent/skywalking-agent.jar
85 0 root S 1528 0% 2 0% /bin/sh
1 0 root S 1520 0% 1 0% /bin/sh -c java $JAVA_OPTS -jar /collect.jar
91 85 root R 1516 0% 2 0% top
[root@容器id data-collector]# jstack 6 >> dump.log
#退出容器,将文件cp出来
[root@master ~]# kubectl cp data-collector-service-zhizhi-5fb9df9586-shrhc:/opt/data-collector/dump.log /root/dump.log
14.分析堆栈信息,如果你功力深厚可以直接根据线程排查到具体代码,像这样:
jstack排查java堆栈异常
15.当然,别人的代码你可能不想看,那自己把这个文件给研发排查吧
解决方案:
解决方案已在第二部分给出,请自提,还望网友斧正
原文地址请注明出处