ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

堆内存溢出时自动导出 heapdump 文件

堆内存溢出时自动导出 heapdump 文件

一、 在本地服务器的测试

为了方便测试堆内存溢出,设置了堆内存空间,以及容器可使用的内存大小。

注意:堆内存空间不能大于等于容器可使用的内存,因为如果容器的内存满了会被系统kill掉,heapdump 文件来不及导出。

1. 配置dockerfile 文件

FROM openjdk:17-jdk # 设置工作目录 WORKDIR /usr/app # 复制应用Jar包 COPY ./app.jar /usr/app/ # 设置时区 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN mkdir -p /usr/app/logs && chmod 755 /usr/app/logs EXPOSE 8090 ENTRYPOINT ["java"] CMD ["-Xms256m","-Xmx256m","-XX:+UseG1GC","-XX:+HeapDumpOnOutOfMemoryError","-XX:HeapDumpPath=/usr/app/logs/heapdump.hprof","-Xlog:gc*:file=/usr/app/logs/gc.log:time,uptime,level,tags:filecount=5,filesize=10m","-jar","/usr/app/app.jar"]

2. 配置 docker-compose 文件

services: app-service: container_name: "app_service" restart: unless-stopped image: "image-name" deploy: resources: limits: cpus: '1' memory: 2G ports: - 8090:8090 volumes: - /opt/data/logs:/usr/app/logs

二、 在 aws ecs云服务器测试

因为服务是运行在 AWS 的 ECS Fargate 上的。如果发生堆内存溢出(堆内存不足导致)会导致健康检查失败,系统会关闭容器,这样就拿不到 heapdump 文件了。所以需要把 heapdump 文件导出到 EFS 文件系统上。

1. 创建一个安全组,放行 2049 端口,用于可以访问 EFS 文件系统

2. 创建 EFS 文件系统

在选择网络时,选择和 ECS 服务同一个VPC。

挂载目标选择多个可用区,这样不同可用区的 ECS 容器都可以访问这个 EFS。

安全组选择第一步创建的。其他的可以选择默认

3. 创建一个 EC2

创建EC2时,网络设置中,选择和 EFS 同一个VPC,子网选择 EFS 挂载目标时可用区里的子网

在配置存储/存储(卷)模块选择文件系统,添加共享的文件系统,挂载刚才创建的 EFS 文件系统,这样就可以通过挂载点访问 EFS 的根目录了。

登录 EC2,目录切换到 /mnt/efs/fs1,这样就可以在 EFS 文件系统上上传或下载文件了。

4. 配置 dockerfile 文件

FROM arm64v8/gradle:7.4.2-jdk17 COPY ./build/libs/app.jar /usr/app/ WORKDIR /usr/app EXPOSE 8090 ENTRYPOINT ["sh","-c","mkdir -p /var/heapdump/logs && chmod -R 775 /var/heapdump/logs && exec java -Xms256m -Xmx256m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/heapdump/logs/heapdump.hprof -Xlog:gc*:file=/var/heapdump/logs/gc.log:time,uptime,level,tags:filecount=5,filesize=10m -jar /usr/app/app.jar"]

"sh","-c","mkdir -p /var/heapdump/logs && chmod -R 775 /var/heapdump/logs的作用是镜像在容器里启动时再创建目录。

如果是 RUN mkdir -p /var/heapdump/logs && chmod -R 775 /var/heapdump/logs 这样在创建镜像时文件夹就已经创建好了,当 ECS 系统启动时,挂载的路径会覆盖掉这个路径。因为系统启动时会挂载 EFS,/var/heapdump 路径会映射 EFS 文件系统的路径,所以在挂载 EFS 后再创建文件夹,才会在 EFS 文件系统上创建,而不是在 ECS 容器上创建。

5. 修改 ECS 服务的任务定义

在存储模块选择 添加卷

定义一个卷名称,等会挂载卷时使用。

选择卷类型 EFS。

根目录是 EFS 文件系统上的目录,这个目录需要提前创建,也可以直接写 / 表示挂载 EFS 的根目录。

源卷就是上一步添加的卷

容器路径是 ECS 容器里的路径。

这样容器里的服务就可以通过 /var/heapdump 访问 EFS /heapdump 文件夹。

然后就可以了。启动服务后,当发生堆内存溢出时,JVM会自动导出 heapdump 文件到EFS文件系统,到时候就可以通过 EC2 下载该文件。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进