Java Web项目部署在2核2G的服务器上需要优化哪些参数?

在 2 核 2G(2 vCPU, 2GB RAM)的服务器上部署 Java Web 项目,资源非常紧张。如果直接运行默认配置的 JVM 和中间件,极易出现 OOM(内存溢出)、Full GC 频繁甚至服务假死。

以下是针对该配置需要重点优化的参数和策略,按优先级排序:

1. JVM 核心参数优化(最关键)

Java 进程是内存消耗大户。在 2GB 总内存下,操作系统和中间件(如 Tomcat/Nginx)需要预留空间,留给 JVM 的实际可用内存通常只有 1GB ~ 1.4GB

A. 堆内存设置 (-Xms-Xmx)

  • 原则:堆内存必须小于物理总内存的 60%-70%,防止操作系统因交换分区(Swap)导致性能急剧下降。
  • 推荐值
    • -Xms512m -Xmx512m(或最大不超过 768m
    • 注意:将初始堆和最大堆设置为相同值,避免 JVM 动态调整堆大小带来的性能抖动。

B. 元空间 (-XX:MetaspaceSize)

  • 背景:JDK 8+ 使用 Metaspace 存储类元数据,默认会随应用加载类数量增长。
  • 优化:限制其上限,防止无限占用内存。
  • 推荐值-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m

C. GC 垃圾回收器选择

  • 问题:默认的 Parallel GC 或 CMS 在低内存下可能产生较长的 STW(Stop-The-World)。
  • 优化
    • JDK 8:推荐使用 G1 GC(虽然 G1 在极小内存下开销略大,但可控性更好),或者保持默认但开启并发标记。
    • JDK 11+:G1 是默认且推荐的选择。
    • 命令示例-XX:+UseG1GC
  • 进阶:如果应用对延迟极其敏感且内存极低,可尝试 ZGC(JDK 11+),但在 2G 机器上需谨慎测试。

D. 线程栈大小 (-Xss)

  • 原理:每个线程占用固定栈内存。2 核 CPU 意味着并发线程数不宜过多。
  • 优化:减小默认值(通常为 1MB),以支持更多线程。
  • 推荐值-Xss256k-Xss512k

E. 关闭不必要的诊断功能

  • 生产环境建议关闭堆转储文件生成,避免磁盘 IO 压力。
  • 命令-XX:+DisableExplicitGC (防止代码中手动调用 System.gc())

2. 中间件参数优化

A. Tomcat / Jetty

  • Connector 线程池
    • maxThreads:默认 200,2G 机器建议降至 50-100
    • minSpareThreads:建议设为 10-20
    • acceptCount:队列长度,建议 50-100
  • HTTP/2:如果不需要 HTTP/2 特性,请禁用以减少内存开销。
  • NIO vs BIO:确保使用 NIO 模式(默认),并适当调优 selectorTimeout

B. 数据库连接池 (Druid/HikariCP)

  • HikariCP
    • maximumPoolSize:这是关键。2 核 CPU 无法处理高并发 DB 请求,建议设为 10-20。过大不仅抢 CPU,还会导致上下文切换频繁。
    • minimumIdle:设为与 maximumPoolSize 一致或略小,避免频繁创建销毁连接。
  • Druid
    • maxActive:同样限制在 20 以内。
    • 开启 removeAbandoned 检测泄露连接。

3. 操作系统层面优化

A. 虚拟内存 (Swap)

  • 现状:2G 机器如果没有 Swap,一旦内存吃紧会触发 OOM Killer 杀死进程。
  • 操作:务必创建 1GB – 2GB 的 Swap 分区作为缓冲。
    # 示例:创建 2G swap 文件
    dd if=/dev/zero of=/swapfile bs=1M count=2048
    chmod 600 /swapfile
    mkswap /swapfile
    swapon /swapfile
  • 注意:调整 vm.swappiness 参数,让系统更倾向于使用物理内存,仅在必要时才用 Swap(例如设为 10 或 60,视具体负载而定)。

B. 文件描述符限制 (ulimit)

  • Java 应用在高并发下会打开大量文件和网络连接。
  • 操作:修改 /etc/security/limits.conf
    * soft nofile 65535
    * hard nofile 65535

C. 内核参数 (sysctl.conf)

  • 增加 TCP 端口范围,减少 TIME_WAIT 状态的影响。
    net.ipv4.ip_local_port_range = 1024 65535
    net.core.somaxconn = 1024
    net.ipv4.tcp_tw_reuse = 1

4. 架构与应用层优化

如果单机资源实在无法满足需求,仅靠参数调整有极限,必须考虑架构降级:

  1. 启用压缩:在 Nginx 或 Tomcat 开启 Gzip 压缩,减少网络传输量,降低 CPU 计算压力(需权衡 CPU 与带宽)。
  2. 静态资源分离:将图片、CSS、JS 托管到 CDN 或对象存储(OSS/S3),不要让 Web 服务器处理这些 I/O。
  3. 缓存策略
    • 引入 Redis(如果内存允许,Redis 本身也需要约 200-300MB,若不行则使用本地缓存如 Caffeine/Guava Cache)。
    • 开启数据库查询结果缓存。
  4. JVM 日志监控
    • 开启 GC 日志:-Xloggc:/path/to/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps
    • 定期分析日志,观察 Full GC 频率。如果 Full GC 频繁(如每几分钟一次),说明堆内存依然不足或存在内存泄漏。

总结配置示例 (JDK 8+)

# 启动脚本示例
JAVA_OPTS="-server 
-Xms512m -Xmx512m 
-Xss256k 
-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m 
-XX:+UseG1GC 
-XX:MaxGCPauseMillis=200 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/var/log/java_heap.hprof 
-XX:+DisableExplicitGC 
-Djava.awt.headless=true"

# 结合 Tomcat 配置
# catalina.sh 中 export JAVA_OPTS="$JAVA_OPTS ..."
# server.xml 中 Connector maxThreads="80" minSpareThreads="10" acceptCount="100"

最后建议:在正式部署前,务必进行压测(如使用 JMeter),观察 CPU 使用率、GC 频率和响应时间,根据实际数据微调上述参数。2 核 2G 属于“勉强够用”的配置,任何突发流量都可能导致服务雪崩,因此限流(Rate Limiting)也是必要的防御手段。