本文探讨不同服务器资源下 MySQL 配置的优化思路。
MySQL:5.7
一、my.cnf 参数解释
(1) innodb_flush_log_at_trx_commit
1:默认取值。每次事务提交 立即把 redo log fsync 到磁盘。符合 ACID,零失误丢失。金融、银行必须设为 1。
0:事务提交不写 redo log「write()」也不 fsync,由后台线程每秒一次把 redo log buffer 刷盘。性能最高,最多丢失 1s 事务,只用于可容忍丢数据的测试/日志库。
2:事务提交时 只把 redo log buffer 写到 OS page cache 「write()」,每秒 fsync 一次。比 0 稍安全,仅 OS 崩溃会丢 1s 数据,MySQL 崩溃不丢。大多数 Web 应用可以选择此方案,选择此方案业务层面要确认:
少量支付:TPS < 1 k,丢 1s 最多丢几十条,财务对账可以容忍。
B2B:没有 C 端秒到诉求,客户可以接受 T+0/ T+1 到账即可。(T+0第一个工作日,T+1第二个)
机器掉电风险:UPS 等手段。如果真丢,也能通过上游渠道补单。
二、12 核 24 G
场景:24G 内存、InnoDB 为主、并发 500 ~ 1000 的典型 OLTP 场景
阿里云 ESSD Entry 云盘(2121 IOPS)
1、内存分配方案
(1)JVM
Top 查看到 JVM 稳定占用 30% 内存(约 7.2G),留 3G 余量。
IOPS 分配 30%
(2)MySQL 内存分配
MySQL 每连接 ≈ 0.5 x 4 + 0.5 x 4 + 1 + 2M = 5MB
公式解释:
1、0.5 x 4
0.5 MB = 512 KB,就是 sort_buffer_size 等四个参数的值
4 表示在一次复杂查询中,经常会有 4 条不同的缓冲区被同时用到:
sort_buffer(order by / group by)
read_buffer(全表/全索引顺序读)
read_rnd_buffer(排序后的随机回表)
join_buffer(无索引 JOIN)
2、+1
1 MB ≈ 线程栈(thread_stack 256 KB)+ 网络缓冲区(net_buffer_length 16 KB + 扩容余量)+ 少量内部结构,经验上取 1MB 做顶包估算。
3、2M:余量
500 并发:500 x 5 MB = 2.5G
10 GB Buffer Pool(根据热数据评估)+ 2.5GB ≈ 12.5GB
(3)MySQL IOPS 分配
IOPS 分配 70%,2120 x 0.7 ≈ 1480
innodb_io_capacity = 1400 # 日常刷脏上限
innodb_io_capacity_max = 2000 # 紧急时接近云盘极限(留 5 % 余量)
(4)最终分配
OS + Page Cache:2G(给 Linux 做文件缓存,防止 swap)
JVM:10G
MySQL InnoDB Buffer Pool:10G(仍然是 MySQL 最大头)
MySQL 其余(连接、日志、字典等):2G(按经验值)
预留 buffer:0G(防止突发)
2、推荐配置
1、内存(核心)
innodb_buffer_pool_size:10G
innodb_buffer_pool_instances:8(10 GB/每实例 1.25 GB,减少锁竞争)
key_buffer_size:64M(MyISAM 很少用,64M 足够)
2、连接
max_connections:500(留余量,配合连接池)
thread_cache_size:100(256 过高,够用即可)
3、会话缓冲区
sort_buffer_size:512KB(单线程独占,保守,防止“连接数 x 缓冲区”爆内存)
read_buffer_size:512KB(同上)
read_rnd_buffer_size:512KB(同上)
join_buffer_size:1M(用于无索引 join)
tmp_table_size:64M(与 max_heap_table_size 成对)
max_heap_table_size:64M(避免内存临时表落盘)
query_cache_size:0(实时写入为主,关闭)
4、InnoDB IO
innodb_log_file_size:1G(redolog 大小。可以提高检查点间隔,减少写抖动)
innodb_log_buffer_size:64M(256 MB 太大,64 MB 足够)
innodb_flush_log_at_trx_commit:1(有支付业务必须 1)
innodb_flush_method:O_DIRECT(避免双缓冲)
innodb_io_capacity:1400(与 SSD 实际 IOPS 相匹配「留余量给 Tomcat 日志」)
innodb_io_capacity_max:2000(紧急时接近云盘极限「留 5% 余量」)
innodb_read_io_threads:6(匹配 12 核)
innodb_write_io_threads:6(同上)
5、日志和监控
slow_query_log:1(必开)
long_query_time:0.5(快速定位慢 SQL,看情况配置)
log_queries_not_using_indexes:1(同上)
6、其他建议
query_cache_size 在 MySQL 8 已废弃;5.7 建议关闭或 < 32M。
sort/read_buffer 不能调太大,容易挤爆连接内存
3、操作建议
1、分批生效:先调整 innodb_buffer_pool_size / max_connections / innodb_log_file_size 并重启;其余在线 SET GLOBAL 测试。
2、压测验证:sysbench / tpcc-mysql 跑 30 min,观察
SHOW ENGINE INNODB STATUS 中 Buffer pool hit rate > 99 %
SHOW STATUS LIKE 'Threads_created' 增长趋缓
SHOW STATUS LIKE 'Created_tmp_disk_tables' 不暴涨
3、监控闭环:接入 Prometheus mysqld_exporter 或 Performance Schema,持续观察 QPS、95% RT、Buffer Pool hit ratio 等关键指标。
4、一句话总结
把 InnoDB 缓冲池拉到 10 GB、连接/线程参数与 CPU 核数匹配、会话级缓冲区保守配置,就能在 24GB 内存的机器上把 CPU 和 SSD 都吃满,而不会出现 OOM 或上下文抖动。