目录
故障现象:
前端web页面显示正常,但是用户无法通过任何方式登陆,报504。
检查k8s集群各node节点状态—>均为ready
检查k8s各pod状态—>均为running
检查控制台监控中各服务器的负载:
master01:正常
master02:正常
master03:CPU使用率接近100%
node01:正常
立刻登陆master03,查找CPU使用率高的原因。
发现master03上user模块占用的CPU和内存都超出正常范围,于是手动curl该模块
curl nodeip:nodeport/api/user/v1/version
返回超时
至此,用户登录504的直接原因已找到,需要立即回复业务,
在下面找出导致user模块异常的根本原因
查找user模块故障根本原因
疑点:
1、确认当时user模块占用的资源是超出正常范围的
调取日志如下
0时区5月13日22:59(北京时间5月14日早6:59)日志记录了OOM
2、系统有剩余内存,为什么会报OOM
查阅资料得知:
因为在没有限制java容器可占用最大内存的情况下,jvm有默认值 ;
取值为容器创建时系统可用内存的25%;
所以报OOM的是user模块,因为它触到上限了,
而系统有剩余内存,则不会报OOM;
3、导致user模块占用内存过大的原因是什么?
暂时没有结论,需要开发同事帮助一起找原因。
4、为什么模块OOM了,且服务已经不可用了,容器没有因异常而退出
4.1 仅仅OOM容器是不会直接down掉的,
而如果占用的内存碰到了“硬上限”,容器才会在OOM时执行kill process
这里的“硬上限”可以是容器运行是配置的-m参数决定,也可以是系统本身的最大内存
前者的优先级高于后者
4.2我们目前用于运行jar包的容器镜像内,真正提供服务的依然是tomcat,如下图
请教了有经验的前辈得知
tomcat在OOM时大多数情况下不会直接退出,而是GC;这样的情形在跑多线程的程序时更加常见,
这个观点正好解释了为什么我们master03的CPU使用率很高—>因为系统忙着给user模块GC;
5、今后如何避免类似问题
可供选择的方案如下:
5.1 给容器配置JVM最大占用内存,同时也要给容器设置硬上限,只要碰到硬上限就迫使容器退出,同时依靠k8s重新拉起新的容器
5.2 在JVM中添加 如下参数,只要报oom就迫使容器退出,同时依靠k8s重新拉起新的容器;
-XX:+ExitOnOutOfMemoryError
只要报oom就将内存快照保存
-XX:+HeapDumpOnOutOfMemoryError
保存位置
-XX:HeapDumpPath=/the/way/to/save/heapdump.hprof
5.3 打包镜像的时候加入heathcheck,
FROM yourimages:latest
HEALTHCHECK --interval=5s --timeout=2s --retries=12 \
CMD curl --silent --fail localhost:9200/_cluster/health || exit 1
–interval=<间隔>:两次健康检查的间隔,默认为 30 秒。
–timeout=<间隔>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒。
–retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。
–start-period=<间隔>: 应用的启动的初始化时间,在启动过程中的健康检查失效不会计入,默认 0 秒
5.4 在user模块的yaml文件中加入存活指针的声明,
例如
apiVersion: v1
kind: Pod
metadata:
namespace: ctg
name: kubia-unhealthy
labels:
name: kubia-unhealthy
spec:
containers:
- image: luksa/kubia-unhealthy
name: kubia
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 15 # 在k8s第一次探测前等待15s.
delays: 延迟,delays=0s,表示在容器启动后立即开始探测
timeout: 超时,timeout=1s,表示容器必须在1s内进行响应,否则这次探测记作失败
period: 周期,period=10s,表示每10s探测一次容器
failure: 失败,failure=3,连续3次失败后重启容器