故障发现
6.3 日上午起床后发现自己闲置的服务器出现了告警(自己搭建的告警体系),立即查看监控系统,看看是什么原因。
故障分析
首先查看主机整体监控
看到明显的磁盘占用空间上升,凌晨和傍晚有两次磁盘读写尖峰,伴随 CPU 占用上升。
立即怀疑是否是某中间件发生了频繁的 GC、以及不停打印 GC 日志导致,于是打开容器监控:
发现 kibana 占用特别高,非常反常,因为正常来说 es 的占用会高于 kibana,且监控上并没有 es 的数据,猜测 es 挂掉,导致 kibana 连不上,不断重试,并打印失败日志。打开7日监控验证猜测
发现几天前大量容器突然关闭,kibana 的 CPU 占用才升高,那应该就是猜测的,再去服务器上验证好了;docker ps -a
查看容器有没有异常死掉的且启动失败的
docker stats
查看容器占用
好家伙,kibana 占了 30 的CPU,查看他日志
果不其然,占了 2.3 G
清除故障
清理即可
cat /dev/null > xxx.log
再看监控
磁盘占用恢复,CPU 下降,恢复正常
总结分析
一且原因是因为 4 天前一次折腾,浪费了太多的内存,导致服务器上运行的容器崩溃,其中 es 的启动是这样的
--restart=on-failure:3
即容器挂掉后尝试重启,最多重试 3 次,而 kibana 的配置为 always。
此次之后,将 kibana 的重试次数改为3次。
为什么不让容器启动失败后一直重试?
重要的中间件是可以这样的,如 nginx 对我来说重要,而 es 很少使用,故对我来说不需要一直重试,因为大部分容器时会比运行时消耗更多的 CPU 资源,而中间件挂掉的原因很大概率就是 CPU 不够用,如果此时所有中间件选择总是重试,那么必定会导致服务器雪崩,将原来不受影响的低资源占用的容器一并拖垮,并相继拖垮所有容器,导致服务器 CPU 暴增,甚至无法执行命令、登录,从而崩溃,只能重启!
举例
服务器可给容器使用的资源有 7
A 容器启动占用 4,运行后占用 3
B 容器启动占用 3,运行后占用 2
C 容器启动占用 2,运行后占用 1
在之前已经将 A、B、C 容器依次启动,并长时间正常运行,且剩余 1 闲置资源可用
此时启动一个容器 D 启动消耗 0.5,运行消耗 1.5 ,而服务器无法满足 D 的需要,决定杀掉了占用资源最多的 A,并将 D 启动;
此时服务器剩余 2 闲置资源可用,而 A 容器执行自动重启逻辑,而此时服务器又无法满足 A 重启所需资源,故又杀掉一个占用最高的 B,A 容器继续执行重启
A 重启还没完全启动,B被杀掉了,也触发启动逻辑,这时会和 A 争抢资源,A重启失败,又触发重启…
此时 A、B 都无法重启,服务器决定杀掉 C,触发 C 的重启逻辑
如此循环,服务器并为对外界提供服务,CPU 却一直超出占用,导致服务器空跑无意义的重复循环启动…无解死循环,除非断电重启,而断电重启必然丢失一部分数据
故不能一味的将容器的重启策略全部置为 always,推荐将不重要容器设置重启次数甚至不重启,当然最好的选择是提升配置满足容器的资源需求;另一个思路是限制资源占用,保证留有一定的 CPU 来处理登录与执行命令,这样在服务器崩溃的时候可以人工干预从而解决。