服务器参数调优
一、核心配置文件 my.cnf
1.1 配置文件结构
ini
[client]
# 客户端配置
[mysql]
# mysql 命令行配置
[mysqld]
# 服务器核心配置
[mysqldump]
# 备份工具配置
1.2 基础配置模板
ini
[mysqld]
# ============ 基础设置 ============
port = 3306
bind_address = 0.0.0.0
basedir = /usr/local/mysql
datadir = /var/lib/mysql
pid_file = /var/run/mysql/mysql.pid
socket = /tmp/mysql.sock
user = mysql
character_set_server = utf8mb4
collation_server = utf8mb4_unicode_ci
# ============ 连接设置 ============
max_connections = 500
max_connect_errors = 10000
wait_timeout = 600
interactive_timeout = 28800
# 连接分配
back_log = 500
# 线程缓存
thread_cache_size = 100
# ============ 存储引擎 ============
default_storage_engine = InnoDB
# ============ 日志设置 ============
log_error = /var/log/mysql/error.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = ON
# ============ Binlog ============
server_id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 500M
binlog_cache_size = 64K
sync_binlog = 1 # 每次提交都刷盘(最安全)
# ============ InnoDB 引擎 ============
# 缓冲池
innodb_buffer_pool_size = 4G
innodb_buffer_pool_instances = 4
innodb_log_file_size = 512M
innodb_log_files_in_group = 2
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_io_capacity = 2000
innodb_read_io_threads = 4
innodb_write_io_threads = 4
innodb_purge_threads = 4
# ============ 排序/临时区 ============
sort_buffer_size = 256K
join_buffer_size = 256K
tmp_table_size = 32M
max_heap_table_size = 32M
# ============ 其他 ============
max_allowed_packet = 64M
sql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
二、缓冲池调优
2.1 InnoDB Buffer Pool
这是 MySQL 最核心的内存参数,直接影响读写性能。
sql
-- 查看当前配置
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; -- 缓冲池大小
SHOW VARIABLES LIKE 'innodb_buffer_pool_instances'; -- 实例数
SHOW VARIABLES LIKE 'innodb_buffer_pool_chunk_size'; -- 块大小
-- 查看缓冲池使用状态
SHOW ENGINE INNODB STATUS\G
-- BUFFER POOL AND MEMORY 部分
-- Database pages:总页面数
-- Free pages:空闲页面数
-- Modified pages:脏页数
-- Buffer pool hit rate:缓存命中率
配置建议:
ini
# 专用 MySQL 服务器:分配物理内存的 60%~80%
# 共享服务器:分配物理内存的 30%~50%
# 16GB 内存的服务器
innodb_buffer_pool_size = 10G
innodb_buffer_pool_instances = 8 # 每个实例约 1.25G
# 32GB 内存的服务器
innodb_buffer_pool_size = 20G
innodb_buffer_pool_instances = 16
# 64GB 内存的服务器
innodb_buffer_pool_size = 40G
innodb_buffer_pool_instances = 16
监控命中率:
sql
-- 缓存命中率应 > 99%
SELECT
(1 - (innodb_buffer_pool_reads / (innodb_buffer_pool_read_requests + 1))) * 100
AS buffer_pool_hit_rate
FROM performance_schema.global_status
WHERE variable_name IN ('innodb_buffer_pool_reads', 'innodb_buffer_pool_read_requests');
2.2 Redo Log 配置
sql
-- 查看配置
SHOW VARIABLES LIKE 'innodb_log_file_size'; -- Redo log 文件大小
SHOW VARIABLES LIKE 'innodb_log_files_in_group'; -- 文件数量
SHOW VARIABLES LIKE 'innodb_log_buffer_size'; -- log 缓冲区
-- 查看写入量
SHOW ENGINE INNODB STATUS\G
-- Log sequence number:当前 LSN(已经写入的日志量)
-- Log flushed up to:已经刷盘的 LSN
配置建议:
ini
# Redo log 总大小 = innodb_log_file_size × innodb_log_files_in_group
# 建议总大小能容纳 1 小时的写入量
# OLTP 场景
innodb_log_file_size = 1G
innodb_log_files_in_group = 2
# 写入密集型
innodb_log_file_size = 2G
innodb_log_files_in_group = 3
三、连接数调优
3.1 最大连接数
sql
-- 查看当前连接数
SHOW STATUS LIKE 'Threads_connected'; -- 当前连接数
SHOW STATUS LIKE 'Threads_running'; -- 活跃连接数
SHOW STATUS LIKE 'Max_used_connections'; -- 历史最大连接数
-- 查看最大连接数配置
SHOW VARIABLES LIKE 'max_connections';
-- 如果 Max_used_connections 接近 max_connections,需要增加
-- 设置公式:max_connections = 峰值连接数 * 1.5
3.2 连接相关参数
ini
[mysqld]
# 最大连接数(默认 151)
# 如果太小:业务高峰期会报 "Too many connections"
# 如果太大:消耗内存过多
max_connections = 500
# 每个连接占用内存估算:
# sort_buffer_size + join_buffer_size + read_buffer_size + ...
# = 256K + 256K + 128K + 128K = 768K 每个连接
# 500 连接 × 768K = 384MB(连接占用总内存)
# 连接超时
wait_timeout = 600 # 非交互连接超时(秒)
interactive_timeout = 28800 # 交互连接超时(秒)
# 连接排队数
back_log = 500
# 连接线程缓存
thread_cache_size = 100
3.3 连接数监控
sql
-- 监控连接状态
SELECT
COUNT(*) AS total_connections,
SUM(CASE WHEN command = 'Sleep' THEN 1 ELSE 0 END) AS sleep,
SUM(CASE WHEN command = 'Query' THEN 1 ELSE 0 END) AS active_query,
SUM(CASE WHEN command = 'Locked' THEN 1 ELSE 0 END) AS locked
FROM information_schema.PROCESSLIST;
-- 查找长连接(超过 1 小时且处于 Sleep 状态)
SELECT id, user, host, db, time, command, state
FROM information_schema.PROCESSLIST
WHERE command = 'Sleep' AND time > 3600;
四、InnoDB 线程调优
4.1 IO 线程
ini
[mysqld]
# 读 IO 线程(负责从磁盘读取数据页)
innodb_read_io_threads = 4
# 写 IO 线程(负责将脏页写入磁盘)
innodb_write_io_threads = 4
# Purge 线程(清理 undo log)
innodb_purge_threads = 4
# IO 容量(磁盘每秒可执行 IOPS)
innodb_io_capacity = 2000 -- SSD 建议 2000~5000
innodb_io_capacity_max = 3000 -- 最大 IOPS
4.2 刷盘策略
ini
[mysqld]
# 控制脏页刷盘行为
innodb_flush_log_at_trx_commit = 1 -- 每次提交刷盘(最安全)
innodb_flush_method = O_DIRECT -- 绕过 OS 缓存,直接写磁盘
# 脏页比例(达到此比例强制刷盘)
innodb_max_dirty_pages_pct = 75
innodb_max_dirty_pages_pct_lwm = 10 -- 低于此比例停止主动刷盘
# 刷盘线程数
innodb_page_cleaners = 4
4.3 并发控制
ini
[mysqld]
# InnoDB 并发线程数上限
# 0 表示不限制(根据操作系统调度)
innodb_thread_concurrency = 0
# 并发中等待锁的事务数量
innodb_commit_concurrency = 0
# 死锁检测(默认 ON,高并发场景可关闭)
innodb_deadlock_detect = ON
五、排序/临时区调优
5.1 排序参数
sql
-- 查看文件排序比例(越低越好)
SHOW STATUS LIKE 'Sort_scan';
SHOW STATUS LIKE 'Sort_merge_passes';
-- Sort_merge_passes 过高说明 sort_buffer_size 太小
-- 查看创建的临时表情况
SHOW STATUS LIKE 'Created_tmp_tables';
SHOW STATUS LIKE 'Created_tmp_disk_tables';
-- Created_tmp_disk_tables 过多说明 tmp_table_size 太小
ini
[mysqld]
# 排序缓冲区(每个连接独占,不能太大)
sort_buffer_size = 256K
# JOIN 缓冲区
join_buffer_size = 256K
# 临时表大小
tmp_table_size = 32M
max_heap_table_size = 32M
排序调优:
sql
-- 好:用索引排序(Using index for order by 或 filesort 可以避免)
EXPLAIN SELECT * FROM users ORDER BY create_time DESC;
-- Extra: Using filesort(需要优化)
-- 优化:给排序字段建索引
CREATE INDEX idx_create_time ON users(create_time);
-- 如果无法避免 filesort,适当增大 sort_buffer_size
SET SESSION sort_buffer_size = 1M;
六、硬件与操作系统优化
6.1 硬件选择建议
| 组件 | 建议 | 说明 |
|---|---|---|
| CPU | 高频 > 多核 | MySQL 单线程能力更重要 |
| 内存 | 越大越好 | 尽量将热数据放入 Buffer Pool |
| 磁盘 | NVMe SSD | 4K 随机读写性能关键 |
| 网络 | 万兆网卡 | 主从复制和高可用依赖网络 |
6.2 操作系统优化
bash
# 1. 文件系统
# 使用 XFS 或 ext4
# 2. IO 调度器
# SSD 建议 noop 或 none
echo noop > /sys/block/sda/queue/scheduler
# 3. 磁盘预读
blockdev --setra 4096 /dev/sda
# 4. 系统限制(打开文件数)
# /etc/security/limits.conf
mysql soft nofile 65535
mysql hard nofile 65535
# 5. swap 设置
# 尽量不用 swap,或降低 swappiness
sysctl vm.swappiness=1
# 6. 大页内存(可选)
# 减少 TLB miss
echo never > /sys/kernel/mm/transparent_hugepage/enabled
七、实战案例
案例:16GB 内存服务器的 my.cnf 优化
ini
[mysqld]
# 基础
port = 3306
user = mysql
character_set_server = utf8mb4
collation_server = utf8mb4_unicode_ci
# InnoDB 核心(分配 10GB)
innodb_buffer_pool_size = 10G
innodb_buffer_pool_instances = 8
innodb_log_file_size = 1G
innodb_log_files_in_group = 2
innodb_log_buffer_size = 32M
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT
innodb_file_per_table = 1
innodb_io_capacity = 2000
innodb_read_io_threads = 4
innodb_write_io_threads = 4
innodb_purge_threads = 2
# 连接(预留 3GB 给连接和其他操作)
max_connections = 500
thread_cache_size = 100
back_log = 500
# 连接内存(每个连接约 1MB)
# sort_buffer_size = 256K
# join_buffer_size = 256K
# 查询缓存(MySQL 8.0 已废弃,不开启)
# 日志
slow_query_log = ON
long_query_time = 2
# Binlog
server_id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
expire_logs_days = 7
sync_binlog = 1
# 临时表
tmp_table_size = 64M
max_heap_table_size = 64M
# 其他
max_allowed_packet = 64M
sql_mode = STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION
open_files_limit = 65535
调优效果检查:
sql
-- 运行 1 天后检查
-- 1. Buffer Pool 命中率(应 > 99%)
SELECT CONCAT(ROUND(
(1 - (SELECT variable_value FROM performance_schema.global_status
WHERE variable_name = 'innodb_buffer_pool_reads')
/
(SELECT variable_value FROM performance_schema.global_status
WHERE variable_name = 'innodb_buffer_pool_read_requests')) * 100, 2), '%')
AS buffer_pool_hit_rate;
-- 2. 慢查询比例
SELECT
(SELECT variable_value FROM performance_schema.global_status
WHERE variable_name = 'Slow_queries') /
(SELECT variable_value FROM performance_schema.global_status
WHERE variable_name = 'Questions') * 100 AS slow_query_pct;
-- 3. 磁盘临时表比例
SELECT CONCAT(ROOT(
(SELECT variable_value FROM performance_schema.global_status
WHERE variable_name = 'Created_tmp_disk_tables')
/
(SELECT variable_value FROM performance_schema.global_status
WHERE variable_name = 'Created_tmp_tables'
AND variable_value > 0) * 100, 2), '%')
AS disk_tmp_table_pct;
-- 4. 最大连接数使用率
SELECT CONCAT(ROUND(
(SELECT variable_value FROM performance_schema.global_status
WHERE variable_name = 'Max_used_connections')
/
(SELECT variable_value FROM performance_schema.global_variables
WHERE variable_name = 'max_connections') * 100, 2), '%')
AS connection_usage;
总结
| 参数 | 建议值 | 检查指标 |
|---|---|---|
| innodb_buffer_pool_size | 物理内存 60%~80% | 命中率 > 99% |
| max_connections | 峰值 × 1.5 | 使用率 < 80% |
| innodb_log_file_size | 能装 1 小时写入量 | 不要频繁切换 |
| sort_buffer_size | 256K~1M | Sort_merge_passes 少 |
| tmp_table_size | 32M~64M | 磁盘临时表少 |
| innodb_io_capacity | SSD 2000~5000 | 脏页刷盘及时 |
| sync_binlog | 1 | 数据安全 |
| thread_cache_size | 100~200 | Threads_created 少 |