在 2 核 2GB 的服务器上运行 Spring Boot + MySQL,资源非常紧张。优化的核心思路是:降低 MySQL 内存占用、减少连接数消耗、提升查询效率以及避免 Java 端 OOM。
以下是针对该配置的关键优化参数和建议:
1. MySQL 服务端优化 (my.cnf / my.ini)
这是最关键的部分。默认的 MySQL 配置通常会预留大量内存给 Buffer Pool,这在 2GB 总内存下会导致系统频繁 Swap(交换分区),直接拖垮性能甚至导致进程被杀。
建议将 /etc/my.cnf (Linux) 或 my.ini (Windows) 中的 [mysqld] 部分修改如下:
[mysqld]
# 基础设置
basedir=/usr/local/mysql
datadir=/var/lib/mysql
port=3306
socket=/tmp/mysql.sock
# 字符集
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
# --- 核心内存优化 (关键) ---
# 总内存 2GB,建议分配给 MySQL 最多 512MB - 768MB,留出空间给 OS 和 JVM
# innodb_buffer_pool_size: 默认通常太大,需手动限制
innodb_buffer_pool_size = 512M
# 如果业务主要是读多写少,可适当调高到 600M;如果是纯测试/开发,512M 足够
# 其他内存相关参数 (防止内存溢出)
innodb_log_file_size = 256M # 日志文件大小,不宜过大
innodb_flush_log_at_trx_commit = 2 # 牺牲一点数据安全性换取写入性能 (生产环境慎用,开发/测试推荐设为 2)
max_connections = 50 # 限制最大连接数,防止连接风暴耗尽 CPU/内存
# 连接与线程
thread_cache_size = 10 # 缓存线程,减少创建开销
table_open_cache = 400 # 表缓存数量
open_files_limit = 1024 # 文件句柄限制
# 查询优化
sort_buffer_size = 256K # 每个连接排序缓冲区,默认可能很大,必须减小
read_buffer_size = 256K # 每个连接读取缓冲区
read_rnd_buffer_size = 256K # 随机读取缓冲区
join_buffer_size = 256K # 连接缓冲区
# 临时表
tmp_table_size = 32M
max_heap_table_size = 32M
# 日志与监控
log_error = /var/log/mysql/error.log
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 # 超过 2 秒的慢查询记录
注意:
- Swap 处理:确保服务器开启了 Swap 分区(至少 2GB),作为最后一道防线,防止 MySQL 因内存不足直接被 OOM Killer 杀死。
- 重启生效:修改后需执行
systemctl restart mysqld。
2. Spring Boot 应用层优化 (application.yml / properties)
Spring Boot 默认的连接池(HikariCP)在某些场景下配置不够保守,需要针对小内存环境调整。
A. 数据库连接池配置 (HikariCP)
在 application.yml 中显式配置:
spring:
datasource:
url: jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
# HikariCP 配置
hikari:
minimum-idle: 5 # 最小空闲连接,保持少量活跃连接即可
maximum-pool-size: 20 # 最大连接数,不要超过 MySQL 的 max_connections
idle-timeout: 600000 # 空闲超时时间 (分钟)
connection-timeout: 30000 # 获取连接超时时间
max-lifetime: 1800000 # 连接最大存活时间
leak-detection-threshold: 60000 # 开启泄漏检测,发现未关闭连接报错
B. JVM 内存参数启动
由于物理内存只有 2GB,JVM 不能占用太多。建议在启动脚本中指定 -Xmx 和 -Xms:
java -jar -Xms256m -Xmx512m -XX:+UseG1GC your-app.jar
-Xmx512m: 限制堆内存最大为 512MB,留给 MySQL 和其他系统进程足够的空间。-XX:+UseG1GC: G1 垃圾回收器在处理小堆内存时通常表现更好,停顿更短。
3. 代码与架构层面的建议
除了改参数,代码逻辑对资源的消耗同样致命:
- 避免 N+1 查询:
- 使用
@EntityGraph或JOIN FETCH在 JPQL/HQL 中一次性加载关联数据,避免循环查询数据库。
- 使用
- 分页查询:
- 永远不要一次性
findAll()加载大表数据。务必使用分页(Pageable),且每页条数控制在合理范围(如 20-50)。
- 永远不要一次性
- 索引优化:
- 检查
EXPLAIN执行计划。在低配服务器上,全表扫描是致命的。确保WHERE、ORDER BY、JOIN字段都有合适的索引。
- 检查
- SQL 简化:
- 避免在 SQL 中进行复杂的计算或函数操作(如
WHERE YEAR(create_time) = 2023会导致索引失效),尽量在应用层处理逻辑。
- 避免在 SQL 中进行复杂的计算或函数操作(如
- 缓存策略:
- 引入 Redis 或本地缓存(Caffeine/Guava Cache)。对于热点数据(如配置信息、字典表),直接从缓存读取,减少 MySQL 压力。
4. 监控与排查
上线后,务必监控以下指标,以便动态调整:
- MySQL 状态:使用
SHOW STATUS LIKE 'Threads_connected';观察连接数是否接近上限。 - 慢查询:定期查看
slow_query_log,优化耗时超过 1s 的 SQL。 - 系统负载:使用
top或htop观察si(swap in) 和so(swap out)。如果 swap 读写频繁,说明内存依然不足,需进一步降低 MySQL 的innodb_buffer_pool_size或增加 Swap。
总结
在 2 核 2GB 环境下,“保守”是唯一的真理。
- MySQL:强制限制
innodb_buffer_pool_size为 512M,max_connections为 50。 - Java:限制 Heap 为 512M,连接池最大 20。
- 代码:严格分页,杜绝全表扫描,善用索引。
如果业务流量稍大,这种配置只能勉强维持,建议考虑升级到 4GB 内存的实例或使用云数据库 RDS 服务以释放运维压力。
云知道CLOUD