2019.9.16下午2:40左右发现环境出现故障,功能没法正常运行。java
立刻进行排查
一、基础服务端口运行都是正常的
二、查看环境上最近有新发版的三个微服务,发现都在不一样频率的打印这句日志:node
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挂了???git
先从新启动了docker服务,恢复了业务,而后查看docker挂掉的缘由。docker
将messages文件中跟docker有关的内容过滤出来,发现了这样的信息(部分日志):api
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容器也都一块儿挂掉了:bash
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的。app
后面细查新发版的三个微服务的业务的日志,发如今14:03分的时候,有一个叫cud的服务有“java.lang.OutOfMemoryError”的报错:ide
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容器瞬间所有挂掉!微服务
和开发一块儿对故障进行了分析,发现有两个缘由:
一、这个服务有一个线程池,在代码里面设置的最小是8,最大限制是2147483647 ,用完的线程要1分钟以后才能回收。这就存在两个问题:
1、业务在持续不断的发送请求,这个服务就会一直建立线程,而由于给定的线程最大值过大,至关于能够无限制的建立线程了,会一直消耗资源;
2、用完的线程1分钟以后才会回收,时间过长。
在这两点的影响下,程序跑一段时间,就会出现建立大量的线程,过分的消耗内存资源.gitlab
二、因为docker容器在最初的时候没有作容器的内存限制,因此默认状况下容器使用的资源是不受限制的。
也就是可使用主机内核调度器所容许的最大资源,所以当主机发现内存不够用的时候,也会抛出内存溢出的错误。并且会开始杀死一些进程用于释放内存空间。可怕的是任何进程均可能成为内核猎杀的对象,包括 docker daemon 和宿主机上的其它一些重要的程序。更危险的是若是某个支持系统运行的重要进程被kill掉了,整个系统也就宕掉了。
此次的docker服务进程就被杀掉了。
一、开发优化代码,包括限制线程池的最大线程数量和线程回收的时间,从新发布代码打补丁,后面观察到目前,没有再出现类这个问题了;
二、限制docker内存。从新优化了docker容器,限制了docker内存的使用量,减小docker容器过分占用宿主机资源的风险;
三、增强对docker容器的监控与告警;
一、docker限制内存,很是重要!
二、限制内存的方式(放一个别人写的修改内存的步骤):
方法一:静态修改 -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