背景:
应用的部署结构是这样的:使用rancher管理的Docker集群,有三台物理主机,二十多个Docker容器,
提供的功能是问题跟踪(JIRA),文档管理(Confluence),代码托管(svn,gitlab),持续集成(jenkins,gitlab-ci + Docker),代码质量管理(Sonar),构件管理(nexus3)和测试管理(TestLink)的功能.服务于1400多个研发人员前端
前端使用Apache来对后端的服务进行反向代理,同时Apache集成了CAS和LDAP 提供了单点登陆的功能java
某天下午,用户反馈,应用访问的速度很是的慢,登陆的请求也没法响应了.git
到Apache所在的主机上看资源的占用,,发现CPU占用率超过500%,apache没有足够的CPU资源来处理请求apache
经过在主机上ps这个CPU超过500%的进程,发现是一个java的进程,对应的是JIRA的容器后端
主机上显示的进程号,和容器里边的进程号是不同的jvm
在容器里,JIRA对应的java进程是进程号为1的进程svn
进入JIRA容器gitlab
dump出来这个进程的全部的线程栈性能
jstack 1 > jirastack.log测试
查看这个进程中的占cpu最高的线程
top -Hp 1
获得的结果以下:
能够看到,有8个线程的CPU占用都超过了70左右,合计起来是 500%多
前边的 49,53之类的是和线程栈里边的线程的nxID对应的,只不过,nxID是用十六进制来表示的
咱们把这些十进制的数字也变成十六进制
从dump出来的线程栈里边找到了对应的线程:
从线程栈里边搜索 nid=0x31,搜到了如下的线程
咱们能够看到,这些都是垃圾回收的线程,垃圾回收的线程占据了全部的CPU的时间
查看JIRA的参数设置,发现了内存的设置较小 -Xms1024m -XmX2048m,使用的垃圾收集器是ParallelGC,由于主机的CPU有8个内核,因此就默认启动了8个垃圾收集器的线程
系统的用户大概有1.4K人,都是开发和测试人员来使用,对比另外一个应用 confluence的内存配置(6G的堆大小,G1垃圾收集器),JIRA的堆的配置是有点小了,因此把JIRA的堆内存设置为4G(主机所在的内存还有不少没有使用)而后针对增大的这个堆,启用G1垃圾收集器,而后打印了垃圾收集的日志信息到一个日志文件里边
配置以下:
JVM_MINIMUM_MEMORY 和 JVM_MAXIMUM_MEMORY的值都是4096m
而后,为了防止某个容器占用的资源过多,影响其余的容器(就是开头的时候咱们遇到的问题,JIRA占用的CPU过多,致使了apache没法响应请求,其余的应用都没法访问了),因此,咱们在rancher上对容器的资源作了一些限制
JIR的jvm参数设置不当和没有对容器占用的主机的资源进行隔离这两个缘由共同致使了这个问题的发生
在使用容器做为生产环境的时候,要对本身在容器内所部署的应用的性能和配置参数等有足够的了解,
对Docker容器所在的物理机的CPU和内存等资源所能支撑的容器的数量进行合理的预估,对容器所占用的物理机的资源进行限制,防止容器因配置不当占满物理机的资源,影响其余容器