结论是:生产环境的my.cnf必须按服务器内存、业务特征和引擎行为反推配置,错配innodb_buffer_pool_size或max_connections最易引发性能雪崩;前者应设为剩余内存的60%~75%(如32G内存留4G后配18G~22G),并配innodb_buffer_pool_instances(每1G一个实例,最多8个);后者应设为峰值连接数的1.5倍,且需同步调大open_files_limit和thread_cache_size(10%~20%,≤64),同时必须开启skip_name_resolve=ON并用IP授权,innodb_file_per_table应保持ON以保障空间回收与运维灵活性。

直接说结论:生产环境的 my.cnf 不是抄来的,而是根据服务器内存、业务读写特征、连接模型和存储引擎行为反推出来的 —— 错配 innodb_buffer_pool_size 或 max_connections 是最常导致性能雪崩的两个点。
怎么确定 innodb_buffer_pool_size 的值?
这个参数决定 InnoDB 能缓存多少数据页,直接影响 90% 以上的热查询响应速度。设小了频繁刷盘,设大了挤占系统内存导致 OOM。
- 先查服务器总内存:
free -h,假设为 32G - 留出至少 4G 给 OS + 其他进程(MySQL 本身也需额外内存)
- 剩余内存的 60%~75% 分给缓冲池:即
innodb_buffer_pool_size = 18G~22G - 若
innodb_buffer_pool_size > 1G,必须配innodb_buffer_pool_instances(建议按每 1G 一个实例,最多 8 个),否则单实例锁争用严重 - 验证是否生效:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';,单位是字节,别看错成 MB
max_connections 和 thread_cache_size 怎么配才不炸?
连接数不是“越多越好”。盲目调高 max_connections 会放大 thread_cache_size 不足带来的线程创建开销,甚至触发 OS 级文件描述符限制。
- 先看当前峰值连接:
SHOW GLOBAL STATUS LIKE 'Threads_connected';,观察业务高峰时的值 -
max_connections设为峰值的 1.5 倍较安全(比如峰值 600 → 设 900),别直接设 10000 -
thread_cache_size不是越大越好,典型值是max_connections的 10%~20%,但上限建议 ≤ 64;超过后缓存命中率提升极小,反而增加管理开销 - 检查 OS 限制:
cat /proc/$(pidof mysqld)/limits | grep "open files",确保open_files_limit≥max_connections × 2 - 如果应用用连接池(如 HikariCP),实际 MySQL 并发连接远低于
max_connections,这时可适当降低该值避免资源浪费
为什么 skip_name_resolve 必须开,且不能只写在注释里?
不开它,每个新连接都会触发 DNS 反向解析 —— 即使你只用 IP 连接,MySQL 仍会尝试把客户端 IP 解析成 hostname。一旦 DNS 延迟或超时,连接就会卡住 30 秒以上,现象是 Connecting 状态堆积。
- 确认已启用:
SHOW VARIABLES LIKE 'skip_name_resolve';返回ON - 必须写在
[mysqld]段下,且值为1或ON,写成skip-name-resolve = true无效(MySQL 只认布尔字面量或数字) - 开启后,所有
GRANT语句里的 host 必须用 IP 或%,不能再用域名(否则权限不生效) - 重启生效,改完不重启等于没改
innodb_file_per_table 开关影响什么?
这个开关决定表数据是存进共享表空间(ibdata1)还是独立 .ibd 文件。MySQL 5.6.6+ 默认 ON,但很多老迁移环境仍是 OFF,后果很隐蔽。
- ON(推荐):删表/清空表能真正释放磁盘空间;
ALTER TABLE重建时不会膨胀ibdata1;单表恢复更灵活 - OFF:所有表共用
ibdata1,即使删光所有表,ibdata1也不会变小;TRUNCATE表只是标记空间可重用,不归还 OS - 动态切换风险高:
SET GLOBAL innodb_file_per_table = ON;只对新建表生效,已有表仍留在共享空间;要彻底迁移需导出再导入 - 确认状态:
SELECT @@innodb_file_per_table;,返回 1 表示开启
真正难的不是参数本身,而是理解每个参数背后的数据流向和资源竞争点 —— 比如 innodb_log_file_size 太小会导致频繁 checkpoint,太大又拖慢崩溃恢复;tmp_table_size 和 max_heap_table_size 必须相等,否则内存临时表会无声降级到磁盘。这些细节不跑真实负载压测根本暴露不出来。


















