共计 4385 个字符,预计需要花费 11 分钟才能阅读完成。
行业资讯
服务器
系统运维
如何解决由 docker 容器“java.lang.OutOfMemoryError”引发的环境崩溃
本篇文章给大家分享的是有关如何解决由 docker 容器“java.lang.OutOfMemoryError”引发的环境崩溃,丸趣 TV 小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着丸趣 TV 小编一起来看看吧。
问题描述:
2019.9.16 下午 2:40 左右发现环境出现故障,功能无法正常运行。
马上进行排查
1、基础服务端口运行都是正常的
2、查看环境上最近有新发版的三个微服务,发现都在不同频率的打印这句日志:
2019-09-16 14:42:41,626 INFO [DubboMonitor.java:80] : [DUBBO] Send statistics to monitor zookeeper://192.168.1.101:2181/com.alibaba.dubbo.monitor.MonitorService?anyhost=true application=dubbo-monitor check=false delay=-1 dubbo=crud generic=false interface=com.alibaba.dubbo.monitor.MonitorService methods=lookup,collect pid=11 revision=monitors side=provider×tamp=1568598922300, dubbo version: crud, current host: 10.42.91.223
因为之前有一个微服务出现 OutOfMemoryError 的时候,就有一直打印这些日志,因此将三个容器日志导出来查看,刚刚导了两个日志,正在导第三个日志的时候,发现 docker 命令无法执行,docker 挂了???
先重新启动了 docker 服务,恢复了业务,然后查看 docker 挂掉的原因。
原因分析:1、查看 /var/log/messages 日志
将 messages 文件中跟 docker 有关的内容过滤出来,发现了这样的信息(部分日志):
Sep 16 14:43:07 rancher-node dockerd-current: time= 2019-09-16T14:43:07.982713104+08:00 level=error msg= collecting stats for 587cf4938bed5e3172868d85ae41db3af37e9c1a6cd8192f1cfa22a4e969d53b: rpc error: code = 2 desc = fork/exec /usr/libexec/docker/docker-runc-current: cannot allocate memory: \ \
Sep 16 14:45:04 rancher-node journal: Suppressed 1116 messages from /system.slice/docker.service
Sep 16 14:45:05 rancher-node dockerd-current: time= 2019-09-16T14:45:05.410928493+08:00 level=info msg= Processing signal terminated
Sep 16 14:45:05 rancher-node journal: time= 2019-09-16T06:45:05Z level=error msg= Error processing event events.Message{Status:\ kill\ , ID:\ af42628b1354b74d08b195c0064d8c5d760c826626a3ad36501a85c824d2204d\ , From:\ prod.locmn.cn/prod/locmn-drols-query-chq:latest\ , Type:\ container\ , Action:\ kill\ , ..... Error: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
就是说在 14:45 的时候,docker 就已经无法分配到内存了
然后信号终止,docker 进程被杀掉,因此 docker 的命令无法运行,所有 docker 容器也都一起挂掉了:
Sep 16 14:45:05 rancher-node dockerd-current: time= 2019-09-16T14:45:05.410928493+08:00 level=info msg= Processing signal terminated(处理信号的终止)Sep 16 14:45:05 rancher-node journal: time= 2019-09-16T06:45:05Z level=error msg= Error processing event events.Message{Status:\ kill\ , ID:\ af42628b1354b74d08b195c0064d8c5d760c826626a3ad36501a85c824d2204d\ , From:\ registry.locman.cn/sefon-online/locman-drools-query-chq:latest\ , Type:\ container\ , Action:\ kill\ , ......Error: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
可是为什么分配不到内存呢?
查看了主机,内存还有 10G 的。
2、查看业务日志
后面细查新发版的三个微服务的业务的日志,发现在 14:03 分的时候,有一个叫 cud 的服务有“java.lang.OutOfMemoryError”的报错:
2019-09-16 14:03:10,554 ERROR [ExceptionFilter.java:87] : [DUBBO] Got unchecked and undeclared exception which called by 10.42.83.124. service: com.run.locman.api.crud.service.AlarmInfoCrudService, method: add, exception: java.lang.OutOfMemoryError: unable to create new native thread, dubbo version: crud, current host: 10.42.91.223
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
......(省略部分日志内容)Exception in thread pool-1-thread-3 java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:714)
原来是这个叫 cud 服务的内存溢出了引发的故障,导致了 docker 服务被 kill 掉,所有的 docker 容器瞬间全部挂掉!
故障原因总结
和开发一起对故障进行了分析,发现有两个原因:
1、这个服务有一个线程池,在代码里面设置的最小是 8,最大限制是 2147483647,用完的线程要 1 分钟之后才能回收。这就存在两个问题:
一、业务在持续不断的发送请求,这个服务就会一直创建线程,而因为给定的线程最大值过大,相当于可以无限制的创建线程了,会一直消耗资源;
二、用完的线程 1 分钟之后才会回收,时间过长。
在这两点的影响下,程序跑一段时间,就会出现创建大量的线程,过度的消耗内存资源.
2、由于 docker 容器在最初的时候没有做容器的内存限制,所以默认情况下容器使用的资源是不受限制的。
也就是可以使用主机内核调度器所允许的最大资源,因此当主机发现内存不够用的时候,也会抛出内存溢出的错误。而且会开始杀死一些进程用于释放内存空间。可怕的是任何进程都可能成为内核猎杀的对象,包括 docker daemon 和宿主机上的其它一些重要的程序。更危险的是如果某个支持系统运行的重要进程被 kill 掉了,整个系统也就宕掉了。
这次的 docker 服务进程就被杀掉了。
解决方案
1、开发优化代码,包括限制线程池的最大线程数量和线程回收的时间,重新发布代码打补丁,后面观察到目前,没有再出现类这个问题了;
2、限制 docker 内存。重新优化了 docker 容器,限制了 docker 内存的使用量,减少 docker 容器过度占用宿主机资源的风险;
3、加强对 docker 容器的监控与告警;
总结
1、docker 限制内存,非常重要!
2、限制内存的方式(放一个别人写的修改内存的步骤):
方法一:静态修改 -m
- m 参数:限制 docker 容器最大使用内存
例如:$ docker run -it -m 300M –memory-swap -1 –name con1 u-stress /bin/bash
上面的 docker run 命令中通过 -m 选项限制容器使用的内存上限为 300M。
同时设置 memory-swap 值为 -1,它表示容器程序使用内存的受限,而可以使用的 swap 空间使用不受限制(宿主机有多少 swap 容器就可以使用多少)。
方法二:动态修改 docker update
docker update 动态修改 docker 容器内存
例如:把一个运行着 gitlab 的容器内存限制在 2048M 以内
docker update –memory 2048m –memory-swap -1 gitlab
以上就是如何解决由 docker 容器“java.lang.OutOfMemoryError”引发的环境崩溃,丸趣 TV 小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注丸趣 TV 行业资讯频道。