Administrator
发布于 2025-07-30 / 7 阅读
0
0

MySQL 配置优化

本文探讨不同服务器资源下 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 cachewrite()」,每秒 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 或上下文抖动。


评论