MySQL在Linux环境下的性能调优

📊 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

诊断脚本

复制代码
-- 查看当前锁等待情况
SELECT
    r.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; do
    delay=$(mysql -h slave_host -e "SHOW SLAVE STATUS\G" | grep "Seconds_Behind_Master" | awk '{print $2}')
    if [ "$delay" -gt 60 ]; then
        echo "WARNING: Replication delay is ${delay} seconds"
        # 发送告警
    fi
    sleep 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: 15s
  metrics_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; then
        send_alert "MySQL服务异常"
        return 1
    fi
    
    # 检查连接数
    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 ]; then
        send_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" ]; then
        send_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存储

    • • 增加内存容量

    • • 使用万兆网卡

    1. 操作系统层面
    • • 内核参数优化

    • • 文件系统选择

    • • I/O调度器调整

    1. MySQL配置层面
    • • InnoDB参数调优

    • • 连接池配置

    • • 缓存参数设置

    1. 应用层面
    • • SQL语句优化

    • • 索引设计优化

    • • 业务逻辑优化

避免的常见误区

误区1 :盲目增加连接数上限

正确做法:分析连接使用模式,优化应用连接池

误区2 :查询缓存设置过大

正确做法:MySQL 8.0已移除查询缓存,使用Redis替代

误区3 :忽略慢查询日志分析

正确做法:定期分析慢查询,持续优化SQL

相关推荐
Jonariguez11 分钟前
Mysql InnoDB存储引擎
数据库·mysql
一只小bit2 小时前
Linux网络:阿里云轻量级应用服务器配置防火墙模板开放端口
linux·网络·阿里云
何传令2 小时前
SQL优化系统解析
数据库·sql·mysql
嘉琪0013 小时前
实现视频实时马赛克
linux·前端·javascript
帽儿山的枪手3 小时前
HVV期间,如何使用SSH隧道绕过内外网隔离限制?
linux·网络协议·安全
邹诗钰-电子信息工程4 小时前
嵌入式基础知识复习(C语言)
linux·c语言·vim
瀚高PG实验室5 小时前
CentOS 8 安装HGDB V4.5 psql命令执行报错
linux·运维·centos·瀚高数据库
小醉你真好5 小时前
6、CentOS 9 安装 Docker
linux·docker·centos
Jonariguez5 小时前
Mysql缓冲池和LRU
数据库·mysql
@Jackasher6 小时前
MySQL的存储引擎
数据库·mysql