📊 MySQL性能基准测试:知己知彼
建立性能基线的关键指标
# 核心性能指标监控脚本
#!/bin/bash
echo "=== MySQL Performance Baseline ==="
mysql -e "SHOW GLOBAL STATUS LIKE 'Questions';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Uptime';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_running';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read_requests';"
mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_reads';"
QPS计算公式:QPS = (Questions - 上次Questions值) / 时间间隔
性能测试工具组合拳
1. sysbench - 全方位压测之王
# 准备测试数据
sysbench /usr/share/sysbench/oltp_read_write.lua \--mysql-host=localhost \--mysql-user=test \--mysql-password=password \--mysql-db=testdb \--tables=10 \--table-size=1000000 \prepare# 执行混合读写测试
sysbench /usr/share/sysbench/oltp_read_write.lua \--mysql-host=localhost \--mysql-user=test \--mysql-password=password \--mysql-db=testdb \--tables=10 \--table-size=1000000 \--threads=16 \--time=300 \--report-interval=10 \run
2. mysqlslap - MySQL官方利器
# 模拟100个并发用户,执行1000次查询
mysqlslap --user=root --password=password \--host=localhost \--concurrency=100 \--iterations=1000 \--create-schema=testdb \--query="SELECT * FROM users WHERE id = FLOOR(RAND() * 100000);" \--verbose
⚙️ Linux系统层面优化:基础决定上层建筑
内核参数调优黄金配置
# /etc/sysctl.conf 优化配置
# 网络层优化
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 0# 内存管理优化
vm.swappiness = 1 # 尽量避免使用swap
vm.dirty_ratio = 15 # 脏页占用内存比例
vm.dirty_background_ratio = 5# 文件系统优化
fs.file-max = 1000000 # 系统最大文件句柄数
磁盘I/O优化策略
1. 文件系统选择与挂载参数
# ext4文件系统最佳实践
mount -o noatime,data=writeback,barrier=0,nobh /dev/sdb1 /var/lib/mysql# XFS文件系统(推荐用于大数据量)
mount -o noatime,attr2,inode64,noquota /dev/sdb1 /var/lib/mysql
2. I/O调度器优化
# 对于SSD,使用deadline调度器
echo deadline > /sys/block/sdb/queue/scheduler# 对于机械硬盘,使用cfq调度器
echo cfq > /sys/block/sda/queue/scheduler
内存分配策略
# 计算合理的buffer pool大小
# 规则:物理内存的70-80%分配给InnoDB
total_mem=$(free -m | awk 'NR==2{print $2}')
buffer_pool_size=$((total_mem * 75 / 100))
echo "建议InnoDB buffer pool大小: ${buffer_pool_size}M"
🔧 MySQL配置文件深度调优
my.cnf黄金配置模板
[mysqld]
# 基础配置
port = 3306
socket = /var/lib/mysql/mysql.sock
pid-file = /var/lib/mysql/mysql.pid
datadir = /var/lib/mysql
tmpdir = /tmp# 连接配置
max_connections = 1000
max_connect_errors = 10000
connect_timeout = 60
wait_timeout = 28800
interactive_timeout = 28800# InnoDB引擎优化 - 核心重点
innodb_buffer_pool_size = 6G # 内存的75%
innodb_buffer_pool_instances = 8 # CPU核心数
innodb_log_file_size = 1G # 日志文件大小
innodb_log_files_in_group = 2
innodb_log_buffer_size = 64M
innodb_flush_log_at_trx_commit = 2 # 性能优先设置
innodb_flush_method = O_DIRECT # 避免双重缓冲
innodb_file_per_table = 1
innodb_io_capacity = 2000 # SSD设置更高
innodb_io_capacity_max = 4000
innodb_read_io_threads = 8
innodb_write_io_threads = 8
innodb_thread_concurrency = 0# 查询缓存(5.7及以下版本)
query_cache_type = 1
query_cache_size = 256M
query_cache_limit = 2M# 临时表优化
tmp_table_size = 256M
max_heap_table_size = 256M# 慢查询日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 1# 二进制日志
log-bin = mysql-bin
binlog_format = ROW
binlog_cache_size = 4M
max_binlog_cache_size = 8M
max_binlog_size = 1G
expire_logs_days = 7# 复制优化
relay_log_recovery = 1
slave_skip_errors = 1062,1053,1146
动态参数调优技巧
-- 运行时调整关键参数
SETGLOBAL innodb_buffer_pool_size =8*1024*1024*1024; -- 8GB
SETGLOBAL max_connections =2000;
SETGLOBAL innodb_io_capacity =3000;
SETGLOBAL query_cache_size =512*1024*1024; -- 512MB-- 查看当前配置
SHOW VARIABLES LIKE'innodb_buffer_pool_size';
SHOW VARIABLES LIKE'max_connections';
🔍 SQL查询优化:从根本解决性能问题
慢查询分析神器
1. 慢查询日志分析
# 使用mysqldumpslow分析慢查询
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log # 按查询次数排序
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log # 按平均时间排序
mysqldumpslow -s l -t 10 /var/log/mysql/slow.log # 按锁定时间排序
2. pt-query-digest深度分析
# 安装Percona Toolkit
yum install percona-toolkit# 分析慢查询日志
pt-query-digest /var/log/mysql/slow.log > slow_query_analysis.txt
索引优化实战技巧
1. 复合索引设计原则
-- 错误示例:索引顺序不当
CREATE INDEX idx_wrong ON orders (status, create_time, user_id);-- 正确示例:遵循选择性递减原则
CREATE INDEX idx_correct ON orders (user_id, status, create_time);-- 分析索引使用情况
EXPLAIN SELECT*FROM orders
WHERE user_id =12345AND status ='paid'
ORDERBY create_time DESC LIMIT 10;
2. 覆盖索引应用
-- 创建覆盖索引,避免回表操作
CREATE INDEX idx_covering ON users (email, status, create_time, username);-- 查询直接从索引获取数据
SELECT username FROM users
WHERE email = 'user@example.com' AND status = 'active';
EXPLAIN执行计划解读
-- 详细执行计划分析
EXPLAIN FORMAT=JSON
SELECT u.username, o.total_amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active' AND o.create_time > '2024-01-01';
关键指标解读:
•
type
: 访问类型,system > const > eq_ref > ref > range > index > ALL•
key
: 实际使用的索引•
rows
: 扫描行数,越少越好•
Extra
: 额外信息,"Using filesort"和"Using temporary"需要优化
🚨 故障诊断实战案例
Case 1: 连接数耗尽故障
故障现象:
ERROR 1040 (HY000): Too many connections
诊断过程:
-- 查看当前连接状态
SHOW PROCESSLIST;
SHOW STATUS LIKE'Threads_connected';
SHOW STATUS LIKE'Max_used_connections';
SHOW VARIABLES LIKE'max_connections';-- 分析连接来源
SELECT host, db, user, info, time
FROM information_schema.processlist
WHEREtime>300; -- 查找长时间运行的连接
解决方案:
# 临时增加连接数
mysql -e "SET GLOBAL max_connections = 2000;"# 优化连接池配置(应用层)
# connection_pool_size = 20
# max_idle_time = 300
Case 2: InnoDB锁等待超时
故障现象:
ERROR 1205 (HY000): Lock wait timeout exceeded
诊断脚本:
-- 查看当前锁等待情况
SELECTr.trx_id waiting_trx_id,r.trx_mysql_thread_id waiting_thread,r.trx_query waiting_query,b.trx_id blocking_trx_id,b.trx_mysql_thread_id blocking_thread,b.trx_query blocking_query
FROM information_schema.innodb_lock_waits w
INNERJOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNERJOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;-- 杀死阻塞事务
KILL 12345; -- 替换为实际的thread_id
Case 3: 主从复制延迟
监控脚本:
#!/bin/bash
# 主从延迟监控脚本
while true; dodelay=$(mysql -h slave_host -e "SHOW SLAVE STATUS\G" | grep "Seconds_Behind_Master" | awk '{print $2}')if [ "$delay" -gt 60 ]; thenecho "WARNING: Replication delay is ${delay} seconds"# 发送告警fisleep 10
done
优化措施:
-- 从库优化配置
SET GLOBAL slave_parallel_workers = 8;
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
SET GLOBAL binlog_group_commit_sync_delay = 1000;
📈 监控告警体系建设
Prometheus + Grafana监控配置
# prometheus.yml MySQL监控配置
- job_name: 'mysql'static_configs:- targets: ['localhost:9104']scrape_interval: 15smetrics_path: /metrics
关键监控指标:
• 连接数使用率:
mysql_global_status_threads_connected / mysql_global_variables_max_connections
• 缓冲池命中率:
(mysql_global_status_innodb_buffer_pool_read_requests - mysql_global_status_innodb_buffer_pool_reads) / mysql_global_status_innodb_buffer_pool_read_requests
• 慢查询增长率:
rate(mysql_global_status_slow_queries[5m])
自动化告警脚本
#!/bin/bash
# MySQL健康检查脚本
DB_HOST="localhost"
DB_USER="monitor"
DB_PASS="password"check_mysql_health() {# 检查MySQL是否运行if ! mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -e "SELECT 1" > /dev/null 2>&1; thensend_alert "MySQL服务异常"return 1fi# 检查连接数connections=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -e "SHOW STATUS LIKE 'Threads_connected'" | awk 'NR==2{print $2}')if [ $connections -gt 800 ]; thensend_alert "MySQL连接数过高: $connections"fi# 检查主从状态slave_status=$(mysql -h $DB_HOST -u $DB_USER -p$DB_PASS -e "SHOW SLAVE STATUS\G" | grep "Slave_IO_Running" | awk '{print $2}')if [ "$slave_status" != "Yes" ]; thensend_alert "MySQL主从复制异常"fi
}send_alert() {message="$1"# 发送到钉钉/企业微信curl -X POST "webhook_url" -d "{\"text\": \"$message\"}"
}check_mysql_health
🛠️ 高可用架构最佳实践
MHA自动故障切换配置
# MHA Manager配置示例
[server default]
manager_log=/var/log/masterha/app1/manager.log
manager_workdir=/var/log/masterha/app1
master_binlog_dir=/var/lib/mysql
user=mha
password=mhapassword
ssh_user=root
repl_user=repl
repl_password=replpassword
ping_interval=3
shutdown_script=/usr/local/bin/power_manager
master_ip_failover_script=/usr/local/bin/master_ip_failover[server1]
hostname=mysql-master
port=3306[server2]
hostname=mysql-slave1
port=3306
candidate_master=1[server3]
hostname=mysql-slave2
port=3306
ProxySQL读写分离配置
-- ProxySQL配置读写分离
INSERT INTO mysql_servers(hostgroup_id, hostname, port, weight) VALUES
(0, '192.168.1.10', 3306, 1000), -- 主库
(1, '192.168.1.11', 3306, 900), -- 从库1
(1, '192.168.1.12', 3306, 900); -- 从库2-- 配置查询规则
INSERT INTO mysql_query_rules(rule_id, active, match_pattern, destination_hostgroup, apply) VALUES
(1, 1, '^SELECT.*', 1, 1), -- 读请求路由到从库
(2, 1, '^INSERT|UPDATE|DELETE.*', 0, 1); -- 写请求路由到主库LOAD MYSQL SERVERS TO RUNTIME;
SAVE MYSQL SERVERS TO DISK;
💡 性能调优总结与建议
调优优先级排序
1. 硬件层面(投入产出比最高)
• 使用SSD存储
• 增加内存容量
• 使用万兆网卡
2. 操作系统层面
• 内核参数优化
• 文件系统选择
• I/O调度器调整
3. MySQL配置层面
• InnoDB参数调优
• 连接池配置
• 缓存参数设置
4. 应用层面
• SQL语句优化
• 索引设计优化
• 业务逻辑优化
避免的常见误区
❌ 误区1:盲目增加连接数上限
✅ 正确做法:分析连接使用模式,优化应用连接池
❌ 误区2:查询缓存设置过大
✅ 正确做法:MySQL 8.0已移除查询缓存,使用Redis替代
❌ 误区3:忽略慢查询日志分析
✅ 正确做法:定期分析慢查询,持续优化SQL