SpringBoot应用在Kubernetes中内存持续上涨问题咨询
问题描述
我通过Jib工具将SpringBoot应用部署到Kubernetes集群中,服务启动时内存占用约300MB,但随时间推移会逐渐增长至1.3GB。目前API网关未对用户开放,应用仅处于空闲运行状态,内存仍持续增加。我需要解决无业务负载下的内存增长问题,同时确保内存使用被限制在1GB以内——当前Kubernetes会在内存超出1GB时销毁Pod。
Kubernetes部署配置
# Source: services/charts/login/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubernetes.io/instance: release-name app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: login app.kubernetes.io/version: 1.16.0 name: login spec: selector: matchLabels: app.kubernetes.io/instance: release-name app.kubernetes.io/name: login template: metadata: labels: app.kubernetes.io/instance: release-name app.kubernetes.io/name: login spec: containers: - env: - name: APP_NAME value: login-release-name - name: JAVA_TOOL_OPTIONS value: -Dspring.profiles.active=prod image: dockerregistry.com/login:1.0.0 imagePullPolicy: Always lifecycle: preStop: exec: command: - sh - -c - sleep 10 livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 name: login ports: - containerPort: 8080 name: http protocol: TCP readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 resources: limits: cpu: 2000m memory: 1Gi requests: cpu: 100m memory: 1Gi imagePullSecrets: - name: regcred terminationGracePeriodSeconds: 60
Kubernetes环境下的SpringBoot配置
server.port=8080 server.shutdown=graceful spring.lifecycle.timeout-per-shutdown-phase=45s server.tomcat.accept-count=100 server.tomcat.max-connections=8000 server.tomcat.connection-timeout=10000 server.tomcat.max-threads=200 server.tomcat.min-spare-threads=10 spring.datasource.url=jdbc:postgresql://${DB_HOST:#{"postgres"}}/postgres spring.datasource.username=${DB_USER:#{"postgres"}} spring.datasource.password=${DB_PASSWORD:#{"na"}} spring.datasource.type=org.springframework.jdbc.datasource.DriverManagerDataSource spring.datasource.driver-class-name=org.postgresql.Driver
Jib镜像构建命令
mvn compile com.google.cloud.tools:jib-maven-plugin:3.3.0:dockerBuild -Dimage=login -DskipTests
解决方案
1. 强制限制JVM内存
当前部署未配置JVM内存参数,JVM会根据容器内存自动调整堆大小,可能导致内存持续增长直至触及Kubernetes的1Gi限制。修改JAVA_TOOL_OPTIONS环境变量,添加JVM内存约束:
- name: JAVA_TOOL_OPTIONS value: "-Dspring.profiles.active=prod -Xmx800m -Xms300m -XX:+UseContainerSupport -XX:MaxRAMPercentage=80.0"
-Xmx800m:设置最大堆内存为800MB,预留足够空间给JVM非堆内存(如Metaspace、直接内存),避免整体内存超过1Gi。-Xms300m:设置初始堆内存为启动时的实际占用值,减少JVM动态扩容的开销。-XX:+UseContainerSupport:让JVM感知容器内存限制,而非宿主机内存。
2. 排查内存泄漏
无负载下内存持续增长大概率是内存泄漏,可通过以下方式定位:
- 启用Spring Boot Actuator的堆转储功能:在配置文件中添加
访问management.endpoints.web.exposure.include=heapdump,health management.endpoint.heapdump.enabled=true/actuator/heapdump下载堆快照,用MAT(Memory Analyzer Tool)分析对象引用链,找出未释放的资源(如数据库连接、线程、缓存对象)。 - 在Kubernetes中执行命令直接分析:
kubectl exec -it <pod-name> -- jmap -dump:format=b,file=/tmp/heap.hprof <pid> kubectl cp <pod-name>:/tmp/heap.hprof ./heap.hprof
3. 优化数据源与Tomcat配置
- 替换数据源:当前使用
DriverManagerDataSource,这是无连接池的简单数据源,频繁创建/销毁连接可能导致资源泄漏。替换为HikariCP(Spring Boot默认连接池),并配置合理的连接池参数:spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.idle-timeout=600000 spring.datasource.hikari.connection-timeout=30000 - 调整Tomcat线程配置:增加空闲线程超时时间,减少无负载下的空闲线程占用:
server.tomcat.threads.max-idle-time=60000
4. 优化Jib镜像构建
- 使用轻量JRE镜像:Jib默认使用OpenJDK镜像,可指定更轻量的镜像如Eclipse Temurin的JRE版本,减少镜像体积和内存开销。修改pom.xml中的Jib配置:
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>3.3.0</version> <configuration> <from> <image>eclipse-temurin:17-jre-alpine</image> </from> </configuration> </plugin> - 清理不必要的依赖:检查pom.xml,移除未使用的依赖,减少应用加载的类数量,降低Metaspace内存占用。
内容的提问来源于stack exchange,提问作者PRAJIN PRAKASH
相关产品推荐
相关产品推荐

