努力
加油

在2GB内存的CentOS/Ubuntu服务器上部署Spring Boot和MySQL,有哪些关键性能调优步骤?

2GB 内存的服务器跑 Spring Boot + MySQL,属于典型的“极限操作”。在云计算环境下,这通常意味着你的业务处于初期阶段,或者对成本极其敏感。如果不做调优,大概率会出现 OOM(Out Of Memory)或者数据库锁死导致服务不可用。

核心原则只有一个:极致压缩 JVM 堆内存,严格限制 MySQL 缓冲池,利用 Swap 作为最后防线,并开启高效缓存。

以下是具体的、可落地的调优步骤:

一、 Spring Boot (JVM) 调优

在 2GB 总内存中,OS 本身需要占用约 300-400MB(取决于系统负载),MySQL 需要预留空间,留给 JVM 的空间非常有限。建议将 JVM 最大堆内存控制在 512MB – 768MB 之间。不要贪多,小堆内存反而能减少 Full GC 的频率和时间。

1. 启动参数配置

推荐使用 G1 垃圾回收器(Java 8u212+ 或 Java 11+),它对低延迟和堆大小适应更好。

java -server 
-Xms512m 
-Xmx512m 
-XX:+UseG1GC 
-XX:MaxGCPauseMillis=200 
-XX:MetaspaceSize=128m 
-XX:MaxMetaspaceSize=128m 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/var/log/java/oom.hprof 
-jar app.jar
  • -Xms512m -Xmx512m: 初始堆和最大堆设为相同值,避免运行时动态扩容带来的性能抖动。512M 是平衡点,如果应用特别轻量(如纯 API 网关),可以尝试 256M,但需监控 Metaspace。
  • -XX:MetaspaceSize=128m: 元空间设置不宜过小,否则频繁触发类加载卸载会导致 CPU 飙升。
  • -XX:+HeapDumpOnOutOfMemoryError: 必须开启,方便排查问题。

2. 应用层优化

  • 连接池:使用 HikariCP,它是目前最快的 JDBC 连接池。确保 maximumPoolSize 不要设置过大。对于 2GB 机器,建议设置为 (CPU核数 * 2) + 有效磁盘数。如果是单核 2GB 机器,设为 5-10 足够。
  • 日志级别:生产环境务必关闭 DEBUG 日志,仅保留 INFO 或 WARN。日志输出是 I/O 密集型操作,会严重拖慢响应速度。
  • 线程池隔离:如果使用了异步任务,务必为不同业务场景配置独立的线程池,防止一个阻塞任务耗尽所有线程,导致主接口无响应。

二、 MySQL 调优

MySQL 是内存大户。在 2GB 服务器上,innodb_buffer_pool_size 是关键中的关键。

1. 核心配置文件 (my.cnf 或 mysqld.cnf)

[mysqld]
# 基础设置
user=mysql
port=3306
socket=/var/lib/mysql/mysql.sock

# 字符集
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

# --- 内存核心调优 ---
# 物理内存 2GB,减去 OS(400MB) 和 JVM(512MB),剩余约 1GB 给 MySQL 比较安全
# 建议设置为物理内存的 40%-50%
innodb_buffer_pool_size = 512M 

# 如果数据量极小(< 100MB),可以稍微降低到 256M,释放更多内存给其他进程
# innodb_buffer_pool_instances = 1  # 单实例即可,减少锁竞争开销

# 日志相关
innodb_log_file_size = 64M      # 增大重做日志,提升写入性能
innodb_log_buffer_size = 8M     # 默认 16M 有点大,改为 8M 节省内存
innodb_flush_log_at_trx_commit = 2 # 如果允许丢失 1 秒数据,设为 2 可大幅提升性能;若要求强一致,保持 1

# 连接与线程
max_connections = 100           # 根据实际并发调整,不要设太大
thread_cache_size = 8           # 缓存线程,减少创建销毁开销

# 查询缓存 (注意:MySQL 5.7 已废弃,8.0 移除。如果是 5.7 以下版本可开启,否则忽略)
# query_cache_type = 1
# query_cache_size = 32M

# 临时表
tmp_table_size = 16M
max_heap_table_size = 16M

2. 关键指标解释

  • innodb_buffer_pool_size: 这是最重要的参数。它决定了多少数据可以留在内存中。设置为 512M 是一个安全的起步值。观察 Innodb_buffer_pool_read_requests 和 Innodb_buffer_pool_reads 的比例,如果命中率低于 99%,且内存有余量,可适当增加;如果经常 OOM,则需减小。
  • max_connections: 2GB 机器扛不住高并发连接。每个连接至少消耗几 MB 内存。设置为 100 左右,配合连接池使用,足以应对大多数中小流量场景。

三、 操作系统层面 (Linux Kernel)

1. 启用 Swap 分区

这是救命稻草。 即使你做了上述优化,突发流量仍可能导致内存瞬时不足。没有 Swap,进程会被直接 Kill (OOM Killer)。有 Swap,系统会将不常用的页面换出到磁盘,虽然慢,但能保证服务不崩溃。

  • 创建 2GB-4GB 的 Swap 文件。
  • 调整 swappiness:
    vm.swappiness=10

    设置为 10 表示只有当物理内存使用率超过 90% 时,才倾向于使用 Swap。这样既避免了过度使用磁盘 I/O,又提供了兜底保障。

2. 文件系统优化

  • 如果使用 SSD,确保挂载选项包含 noatime,减少不必要的 inode 访问时间戳更新,降低 I/O 压力。
  • 检查 vm.dirty_ratio 和 vm.dirty_background_ratio,适当调低可以让脏页更早刷盘,避免最后时刻集中写入导致的卡顿。

3. 网络参数

  • 启用 TCP 快速打开 (TFO) 和 TIME_WAIT 回收,提升短连接性能。
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_fin_timeout = 30

四、 监控与告警 (至关重要)

在 2GB 这种资源受限的环境下,没有监控等于盲飞。你必须知道什么时候该扩容或优化。

  1. 部署轻量级监控 Agent:推荐 Prometheus + Node Exporter + Grafana。资源占用极低。
  2. 关注以下指标:
    • JVM: Heap Used, GC Pause Time, Thread Count。
    • MySQL: Buffer Pool Hit Rate (>99%), Connections Used, QPS/TPS, Slow Queries。
    • System: Load Average, Disk I/O Wait, Swap Usage。
  3. 慢查询日志:开启 MySQL 慢查询日志 (slow_query_log = 1, long_query_time = 1),定期分析并优化 SQL。一条全表扫描的 SQL 就能让 2GB 服务器彻底瘫痪。

五、 总结与建议

  1. 架构解耦:如果可能,强烈建议将 MySQL 迁移到独立的高配云数据库(RDS)。2GB 服务器同时跑应用和数据库,是反模式。即使只买最便宜的 RDS 实例,也能获得更好的稳定性、备份和自动调优能力。
  2. CDN 提速:静态资源全部上 CDN,减轻服务器带宽和 I/O 压力。
  3. 灰度发布:上线前务必进行压测,了解系统在 512MB Heap 下的真实表现。

最终结论:在 2GB 内存下,Spring Boot + MySQL 的核心在于 “克制”。JVM 堆不超过 512M,MySQL Buffer Pool 不超过 512M,启用 Swap 兜底,开启慢查询日志。这套组合拳能让你的应用在低成本下稳定运行数月甚至更久。