奋斗
努力

2G内存云服务器如何优化Tomcat和MySQL配置以避免OOM?

云计算

在仅 2GB 内存 的云服务器上同时运行 Tomcat(Java Web 应用)和 MySQL,极易因内存超限触发 OOM(Out of Memory),尤其在并发稍高或应用未优化时。以下是务实、可落地的优化方案,聚焦「避免 OOM」这一核心目标,兼顾稳定性与基本可用性:


⚠️ 前提原则(务必遵守)

  1. 关闭所有非必要服务:如 Redis、Nginx(若非必需)、监控X_X等;
  2. 应用精简:部署单个轻量级应用(如 Spring Boot 管理后台),禁用 DevTools、Actuator(或仅暴露健康端点);
  3. 禁止 swap 用于 Java 进程(Linux swappiness=1vm.swappiness=1),避免 GC 卡死;
  4. 监控先行:部署 htopjstat -gc <pid>mysqladmin status,每小时检查内存/堆使用率。

✅ 一、Tomcat 优化(JVM 内存严格控制)

1. JVM 参数(关键!设为固定堆,禁用动态扩容)

# 修改 $CATALINA_HOME/bin/setenv.sh(无则新建),添加:
export JAVA_OPTS="-Xms512m -Xmx512m 
  -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m 
  -XX:+UseG1GC -XX:MaxGCPauseMillis=200 
  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tomcat/heap.hprof 
  -Djava.security.egd=file:/dev/./urandom"
  • 堆内存锁定为 512MB-Xms512m -Xmx512m):避免动态扩容导致内存碎片或超限;
  • 元空间限制 128MB:防止 ClassLoader 泄漏(常见于热部署);
  • G1 GC + 低延迟目标:比 Parallel GC 更适合小内存场景;
  • -Djava.security.egd=...:提速 Tomcat 启动(避免熵池阻塞)。

💡 若应用极轻(纯静态+简单 Servlet),可降至 -Xms384m -Xmx384m,为系统/Mysql 留更多余量。

2. Tomcat 自身配置($CATALINA_HOME/conf/server.xml)

<!-- 减少连接数 & 缩短超时 -->
<Connector port="8080" protocol="HTTP/1.1"
           maxThreads="50"          <!-- 关键!默认200→50 -->
           minSpareThreads="10"
           maxConnections="200"     <!-- 默认8192→200 -->
           connectionTimeout="20000"
           keepAliveTimeout="15000"
           maxKeepAliveRequests="100"
           acceptCount="50"         <!-- 队列长度,避免堆积 -->
           compression="on"
           compressionMinSize="1024"
           noCompressionUserAgents="gozilla, traviata" />
  • maxThreads=50:每个线程约占用 1MB 栈内存 → 50×1MB = 50MB,可控;
  • acceptCount=50:避免请求队列过大耗尽内存。

3. 其他

  • 删除 $CATALINA_HOME/webapps/ 下所有示例应用(docs, examples, manager, host-manager);
  • 禁用 session 持久化(<Manager pathname="" />);
  • 使用 logback 替代 java.util.logging,降低日志内存开销。

✅ 二、MySQL 优化(内存精打细算)

✅ 目标:MySQL 总内存 ≤ 600MB(含缓冲池+连接内存)

1. 关键配置(/etc/my.cnf/etc/mysql/my.cnf

[mysqld]
# 内存相关(重点!)
innodb_buffer_pool_size = 384M    # 必须 ≤ 40% 总内存(2G×40%=800M,留余量→384M)
innodb_log_file_size = 64M        # 日志文件大小,384M BP → 64M 合理
innodb_flush_method = O_DIRECT    # 避免双缓冲

# 连接与缓存(严控)
max_connections = 50              # 每连接约 2-3MB 内存 → 50×2.5≈125MB
table_open_cache = 400            # 默认2000→400,减少 open_tables 开销
sort_buffer_size = 256K           # 每连接排序缓冲,勿超512K
read_buffer_size = 128K
read_rnd_buffer_size = 256K
join_buffer_size = 256K
tmp_table_size = 32M               # 内存临时表上限
max_heap_table_size = 32M

# 禁用非必要功能
skip-log-bin                      # 关闭 binlog(除非需主从/恢复)
skip-performance_schema           # 关闭性能库(省100MB+)
skip-innodb_doublewrite             # 仅测试环境可关(生产慎用)

2. 启动后验证

-- 检查实际内存使用(近似值)
SELECT 
  (SELECT variable_value FROM information_schema.global_variables WHERE variable_name = 'innodb_buffer_pool_size') / 1024 / 1024 AS ibp_mb,
  (SELECT variable_value FROM information_schema.global_variables WHERE variable_name = 'max_connections') * 2.5 / 1024 AS conn_mb;
-- 应显示:ibp_mb ≈ 384, conn_mb ≈ 125 → 总计约 500MB+

3. 其他建议

  • 使用 mysqltuner.pl 定期分析(curl https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl | perl);
  • 定期 OPTIMIZE TABLE(对小表);
  • 避免 SELECT *、大结果集分页(用游标分页替代 OFFSET);
  • 表引擎统一用 InnoDB(MyISAM 不支持事务且内存管理差)。

✅ 三、系统级协同优化

项目 推荐配置 说明
Linux swappiness echo 'vm.swappiness=1' >> /etc/sysctl.conf && sysctl -p 防止内核过度交换,避免 Java GC 卡顿
系统预留内存 确保 free -h 显示 ≥300MB 可用内存 Tomcat(512M)+MySQL(600M)+OS(300M)+Buffer≈1.4G,留 600MB 余量
日志轮转 logrotate 配置 Tomcat/MySQL 日志(每日+压缩) 防止 /var/log 填满磁盘(间接导致 OOM)
启动顺序 先启 MySQL → 等 10s → 再启 Tomcat 避免 Tomcat 启动时连不上 DB 导致重试风暴

✅ 四、应急与监控(救命措施)

  1. OOM 发生时快速定位

    # 查看谁占内存最多
    ps aux --sort=-%mem | head -10
    # 检查 Tomcat GC 日志(启用 -Xlog:gc*:file=/var/log/tomcat/gc.log)
    # 检查 MySQL 连接数
    mysql -e "SHOW STATUS LIKE 'Threads_connected';"
  2. 自动保护脚本(crontab 每5分钟执行)

    # /usr/local/bin/oom-guard.sh
    #!/bin/bash
    MEM_USAGE=$(free | awk 'NR==2{printf "%.0f", $3*100/$2}')
    if [ "$MEM_USAGE" -gt 90 ]; then
     echo "$(date) High memory: ${MEM_USAGE}%" >> /var/log/oom-guard.log
     systemctl restart mysql  # 或先 kill 高内存进程
     sleep 10
     systemctl restart tomcat
    fi

    ⚠️ 生产慎用 restart,建议先 kill -9 $(pgrep -f "java.*tomcat") 再重启。

  3. 必须开启的监控项

    • free -h(内存)
    • jstat -gc <tomcat_pid>(Eden/Survivor/Old 区使用率)
    • mysqladmin extended-status | grep -E "Threads_connected|Created_tmp_disk_tables"

🚫 绝对禁止的操作(2G机器雷区)

  • Xmx1024m(堆设太大,MySQL 无内存可吃);
  • innodb_buffer_pool_size=1G(直接挤爆系统);
  • ❌ 开启 slow_query_log + general_log(I/O 和内存双杀);
  • ❌ 在 Tomcat 中部署多个 WAR(每个应用至少 200MB+ 堆需求);
  • ❌ 使用 Hibernate 二级缓存(ehcache/redis)且未设 size limit。

✅ 最终内存分配参考(2GB 总内存)

组件 分配内存 说明
Linux OS ~300MB 内核、sshd、cron 等基础
Tomcat JVM 512MB 堆+元空间+线程栈
MySQL ~600MB Buffer Pool + 连接缓冲
余量 ~600MB 应对峰值、Page Cache、临时对象

✅ 实测:此配置可稳定支撑 20~30 并发用户(简单 CRUD 场景),日均请求 1w+。


如果提供你的具体场景(如:Spring Boot 版本、MySQL 版本、是否用连接池、QPS 估算),我可进一步定制参数。小内存不是不能用,而是必须像嵌入式开发一样“斤斤计较”每一MB。

需要我帮你生成完整的 setenv.sh / my.cnf 文件模板,或写一个一键检测脚本吗?

未经允许不得转载:云服务器 » 2G内存云服务器如何优化Tomcat和MySQL配置以避免OOM?