外观
MySQL 存储 IO 优化
存储设备选择与规划
1. 存储设备类型
机械硬盘 (HDD)
- 特点:容量大、成本低、IOPS 较低
- 适用场景:历史数据归档、低频访问数据
- 注意事项:避免用于高并发写入场景
固态硬盘 (SSD)
- 特点:IOPS 高、延迟低、成本高
- 类型:SATA SSD、NVMe SSD、PCIe SSD
- 适用场景:高并发数据库、频繁读写的业务
- 注意事项:关注写入寿命,选择合适的擦除寿命 (TBW)
存储阵列
- 特点:高可靠性、可扩展性强、提供多种 RAID 级别
- 适用场景:企业级数据库、关键业务系统
- 注意事项:选择合适的 RAID 级别,考虑读写性能平衡
2. RAID 级别选择
RAID 0
- 优点:读写性能高
- 缺点:无冗余,一块硬盘故障导致数据丢失
- 适用场景:对性能要求极高、有其他备份机制的场景
RAID 1
- 优点:读性能好、冗余性高
- 缺点:写性能一般、容量利用率低 (50%)
- 适用场景:对数据安全性要求高的场景
RAID 5
- 优点:容量利用率高 (n-1/n)、读性能好
- 缺点:写性能一般、重建时间长
- 适用场景:读多写少、容量要求较高的场景
RAID 6
- 优点:允许两块硬盘同时故障、容量利用率较高 (n-2/n)
- 缺点:写性能较差、重建时间长
- 适用场景:对数据安全性要求极高的场景
RAID 10
- 优点:读写性能优异、冗余性高、重建时间短
- 缺点:容量利用率低 (50%)
- 适用场景:高并发、对性能和可靠性要求都高的场景
3. 存储规划建议
- 数据与日志分离:将数据文件和日志文件存储在不同的物理设备上
- 热数据与冷数据分离:将频繁访问的数据存储在高性能设备上
- 考虑未来扩展性:预留足够的存储空间,考虑存储设备的扩展能力
- 监控存储健康状态:定期检查存储设备的健康状况,及时更换故障设备
文件系统优化
1. 文件系统选择
EXT4
- 优点:成熟稳定、广泛使用、支持大文件
- 适用场景:一般 MySQL 部署
XFS
- 优点:高性能、支持更大的文件系统和文件、并发性能好
- 适用场景:大型数据库、高并发场景
Btrfs
- 优点:支持快照、校验和、动态扩展
- 缺点:稳定性相对较差
- 适用场景:需要快照功能的场景
2. 文件系统挂载参数优化
noatime:禁止更新文件的访问时间,减少 IO 操作
nodiratime:禁止更新目录的访问时间,减少 IO 操作
discard:启用 TRIM 功能,提高 SSD 性能和寿命
barrier=0:关闭写屏障,提高写性能(注意:可能影响数据安全性)
data=writeback:数据写回模式,提高写性能(注意:可能影响数据一致性)
挂载示例:
bash# EXT4 文件系统挂载参数 /dev/sda1 /var/lib/mysql ext4 noatime,nodiratime,barrier=0,data=writeback 0 2 # XFS 文件系统挂载参数 /dev/sdb1 /var/lib/mysql xfs noatime,nodiratime,discard 0 2
3. 文件系统调优
EXT4 调优:
bash# 调整文件系统块大小(创建文件系统时设置) mkfs.ext4 -b 4096 /dev/sda1 # 调整预留空间比例(默认 5%,可减少至 1%) tune2fs -m 1 /dev/sda1XFS 调优:
bash# 创建文件系统时设置合适的 blocksize mkfs.xfs -b size=4096 /dev/sdb1 # 调整日志大小 xfs_growfs -L 512m /dev/sdb1
存储引擎配置优化
1. InnoDB 存储引擎优化
1.1 缓冲池配置
innodb_buffer_pool_size:设置 InnoDB 缓冲池大小,建议为系统内存的 50%-70%
innodb_buffer_pool_instances:将缓冲池划分为多个实例,减少锁竞争
- 建议:每个实例大小不小于 1GB
- 公式:innodb_buffer_pool_instances = innodb_buffer_pool_size / 1GB
innodb_buffer_pool_chunk_size:缓冲池块大小,影响缓冲池的动态调整
配置示例:
ini# 8GB 内存服务器配置 innodb_buffer_pool_size = 5G innodb_buffer_pool_instances = 5 innodb_buffer_pool_chunk_size = 128M
1.2 日志配置
innodb_log_file_size:设置 redo log 文件大小,建议为 256MB-2GB
- 考虑因素:更大的日志文件减少 checkpoint 频率,提高写性能
- 注意事项:过大的日志文件会增加崩溃恢复时间
innodb_log_files_in_group:设置 redo log 文件组数量,建议为 2-4
innodb_log_buffer_size:设置 redo log 缓冲大小,建议为 16MB-128MB
配置示例:
iniinnodb_log_file_size = 1G innodb_log_files_in_group = 2 innodb_log_buffer_size = 64M
1.3 写入策略
innodb_flush_log_at_trx_commit:控制 redo log 刷新策略
- 0:每秒刷新到磁盘,可能丢失最多 1 秒数据
- 1:每次事务提交刷新到磁盘,最安全但性能最低
- 2:每次事务提交写入 OS 缓存,每秒刷新到磁盘
innodb_flush_method:控制数据文件和日志文件的刷新方法
- fsync:使用 fsync() 刷新数据和日志
- O_DIRECT:直接写入磁盘,绕过 OS 缓存(适合使用 RAID 或硬件缓存的场景)
- O_DSYNC:写入日志时使用 O_SYNC,写入数据时使用 O_DIRECT
innodb_doublewrite:双写缓冲区,提高数据安全性
- 建议:生产环境启用,测试环境可禁用以提高性能
1.4 并发控制
- innodb_write_io_threads:设置写入 IO 线程数,建议为 8-64
- innodb_read_io_threads:设置读取 IO 线程数,建议为 8-64
- innodb_purge_threads:设置 purge 线程数,建议为 4-16
- innodb_page_cleaners:设置页面清理线程数,建议与缓冲池实例数相同
2. MyISAM 存储引擎优化
- key_buffer_size:设置 MyISAM 索引缓冲大小,建议为系统内存的 10%-20%
- myisam_sort_buffer_size:设置 MyISAM 索引排序缓冲大小
- myisam_max_sort_file_size:设置 MyISAM 索引排序临时文件的最大大小
- myisam_repair_threads:设置 MyISAM 表修复时的线程数
缓存优化
1. OS 缓存优化
vm.swappiness:控制内核交换内存的倾向
- 建议:设置为 0-10,减少 MySQL 进程被换出的可能性
- 配置:
sysctl -w vm.swappiness=10
vm.dirty_ratio:设置脏页比例阈值,达到后触发同步写盘
- 建议:设置为 20-30
- 配置:
sysctl -w vm.dirty_ratio=25
vm.dirty_background_ratio:设置后台写脏页的比例阈值
- 建议:设置为 5-10
- 配置:
sysctl -w vm.dirty_background_ratio=5
vm.dirty_expire_centisecs:设置脏页过期时间(百分之一秒)
- 建议:设置为 3000(30秒)
- 配置:
sysctl -w vm.dirty_expire_centisecs=3000
2. MySQL 缓存设置
query_cache_type:查询缓存开关
- 注意:MySQL 8.0 已移除查询缓存
- 建议:高并发场景下禁用,因为会导致锁竞争
query_cache_size:查询缓存大小
- 建议:如果启用,设置为 64MB-256MB
- 注意:过大的查询缓存会增加维护开销
磁盘 IO 调度策略
1. 调度策略类型
CFQ (Completely Fair Queueing):公平调度,默认策略
- 特点:为每个进程维护一个 IO 队列,轮询处理
- 适用场景:通用场景,适合 HDD
NOOP (No Operation):简单的 FIFO 队列
- 特点:不进行排序,直接转发 IO 请求
- 适用场景:SSD、存储阵列等本身具备调度能力的设备
Deadline:按截止时间排序
- 特点:为读请求设置更短的截止时间,优先处理读请求
- 适用场景:读多写少的场景,适合 HDD
Kyber:基于令牌桶的调度策略
- 特点:低延迟,适合混合读写场景
- 适用场景:现代 SSD 和 HDD
2. 调度策略设置
查看当前调度策略:
bashcat /sys/block/sda/queue/scheduler临时设置调度策略:
bash# 为 SSD 设置 NOOP 策略 echo noop > /sys/block/sda/queue/scheduler # 为 HDD 设置 Deadline 策略 echo deadline > /sys/block/sdb/queue/scheduler永久设置调度策略(通过 grub 配置):
bash# 编辑 grub 配置文件 vi /etc/default/grub # 在 GRUB_CMDLINE_LINUX 中添加 GRUB_CMDLINE_LINUX="... elevator=noop" # 更新 grub 配置 update-grub
表结构与数据访问优化
1. 表结构优化
选择合适的数据类型:
- 使用最小的合适数据类型
- 避免使用 TEXT/BLOB 存储频繁访问的数据
- 使用 VARCHAR 代替 CHAR,节省存储空间
合理设置主键:
- 使用自增主键,减少页分裂
- 避免使用 UUID 作为主键,因为会导致随机 IO
- 主键长度不宜过长,影响二级索引大小
分区表设计:
- 按时间或范围分区,减少单表数据量
- 热点数据放在一个分区,提高查询性能
- 注意事项:分区键的选择至关重要
2. 数据访问优化
减少全表扫描:
- 为查询条件创建合适的索引
- 使用 LIMIT 限制返回结果数量
- 避免 SELECT * 查询
优化 JOIN 查询:
- 小表驱动大表
- 为 JOIN 条件创建索引
- 避免过多的表 JOIN
批量操作优化:
- 使用批量插入代替单行插入
- 使用 LOAD DATA INFILE 导入大量数据
- 批量更新时使用适当的 WHERE 条件
IO 性能监控与诊断
1. 系统层面监控
iostat:查看磁盘 IO 统计信息
bash# 每秒刷新一次,显示扩展统计信息 iostat -x 1iotop:实时查看进程 IO 使用情况
bash# 按 IO 使用排序 iotop -ovmstat:查看虚拟内存和 IO 统计信息
bashvmstat 1
2. MySQL 层面监控
SHOW ENGINE INNODB STATUS:查看 InnoDB 状态信息
sqlSHOW ENGINE INNODB STATUS\GINNODB_METRICS:查看 InnoDB 性能指标
sql-- 查看 IO 相关指标 SELECT name, value FROM information_schema.innodb_metrics WHERE name LIKE '%io%';PERFORMANCE_SCHEMA:查看详细的性能统计信息
sql-- 查看文件 IO 统计 SELECT * FROM performance_schema.file_summary_by_instance;
3. 常见 IO 性能问题诊断
IO 利用率过高:
- 检查是否有大量全表扫描
- 检查是否有频繁的写入操作
- 考虑增加缓存或使用 SSD
IO 延迟过高:
- 检查存储设备健康状况
- 检查 RAID 控制器缓存设置
- 考虑更换为更快的存储设备
读写不平衡:
- 分析读写比例
- 调整存储设备或 RAID 级别
- 考虑读写分离架构
不同 MySQL 版本的差异
MySQL 5.7
InnoDB 改进:
- 支持原生表空间加密
- 改进了缓冲池管理
- 支持更多的缓冲池实例
性能提升:
- 改进了查询执行计划
- 优化了连接管理
- 提高了并发处理能力
MySQL 8.0
InnoDB 增强:
- 支持即时添加列
- 改进了死锁检测
- 优化了缓冲池的动态调整
新特性:
- 移除了查询缓存
- 支持窗口函数
- 支持通用表表达式
IO 相关优化:
- 改进了 redo log 写入机制
- 优化了数据页的读写
- 支持并行查询
常见问题(FAQ)
Q1: 如何确定合适的 innodb_buffer_pool_size?
A1: 建议设置为系统内存的 50%-70%,具体需要考虑:
- 系统运行的其他服务占用的内存
- MySQL 的连接数和每个连接占用的内存
- 操作系统缓存需要的内存
- 可以通过监控 innodb_buffer_pool_pages_free 指标来调整
Q2: SSD 和 HDD 应该选择哪种调度策略?
A2: 建议:
- SSD:使用 NOOP 或 Kyber 调度策略
- HDD:使用 Deadline 或 CFQ 调度策略
- 存储阵列:使用 NOOP 调度策略,因为阵列本身具备调度能力
Q3: 如何优化大量小文件的 IO 性能?
A3: 优化建议:
- 合并小文件,减少文件数量
- 使用合适的文件系统(如 XFS)
- 调整文件系统的 inode 数量
- 考虑使用 innodb_file_per_table=OFF(但不推荐,不利于管理)
Q4: 如何减少 MySQL 的写 IO?
A4: 减少写 IO 的方法:
- 优化 SQL,减少不必要的更新操作
- 合理设置 innodb_flush_log_at_trx_commit 参数
- 使用批量插入代替单行插入
- 启用二进制日志压缩(MySQL 8.0+)
- 优化索引,减少索引维护带来的写 IO
Q5: 为什么有时候增加 innodb_buffer_pool_size 性能反而下降?
A5: 可能的原因:
- 缓冲池过大导致系统内存不足,产生 swap
- 缓冲池实例数量不足,导致锁竞争
- 缓冲池块大小设置不合理
- 缓存了大量不常用的数据,导致缓存命中率下降
Q6: 如何监控 MySQL 的 IO 性能?
A6: 监控方法:
- 使用 iostat、iotop 等系统工具
- 查看 InnoDB 状态信息
- 使用 Performance Schema 收集详细的 IO 统计
- 使用监控工具如 Prometheus+Grafana、Zabbix 等
Q7: 分区表能提高 IO 性能吗?
A7: 分区表的优势:
- 减少单表数据量,提高查询性能
- 可以将热点数据放在单独的分区
- 方便管理,如快速删除旧数据
- 注意:分区键的选择至关重要,不合理的分区可能导致性能下降
Q8: 如何优化 InnoDB 的日志性能?
A8: 优化建议:
- 设置合适的 innodb_log_file_size 和 innodb_log_files_in_group
- 合理设置 innodb_log_buffer_size
- 考虑将 redo log 放在单独的存储设备上
- 根据业务需求选择合适的 innodb_flush_log_at_trx_commit 值
Q9: 什么是 InnoDB 双写缓冲区?是否可以禁用?
A9: InnoDB 双写缓冲区是一个安全机制,防止部分写失败导致数据损坏。
- 生产环境建议启用
- 测试环境可以禁用以提高性能
- 配置参数:innodb_doublewrite=ON/OFF
Q10: 如何选择合适的 RAID 级别?
A10: 选择建议:
- 高性能要求:RAID 0、RAID 10
- 高可靠性要求:RAID 1、RAID 6
- 平衡性能和可靠性:RAID 5
- 大型数据库:RAID 10
- 成本敏感:RAID 5
