MySQL 硬件优化和操作系统优化
MySQL 体系结构:https://blog.csdn.net/a18792721831/article/details/156569942
MySQL 主从复制:https://blog.csdn.net/a18792721831/article/details/146117935
MySQL Binlog:https://blog.csdn.net/a18792721831/article/details/146606305
MySQL Redo Log:https://blog.csdn.net/a18792721831/article/details/149862528
MySQL 索引优化:https://blog.csdn.net/a18792721831/article/details/150282163
MySQL 锁:https://blog.csdn.net/a18792721831/article/details/154197322
MySQL 事务:https://blog.csdn.net/a18792721831/article/details/156461289
MySQL 硬件优化和操作系统优化
- [MySQL 硬件优化和操作系统优化](#MySQL 硬件优化和操作系统优化)

数据库性能优化是一个系统工程,除了 SQL 优化、索引优化、参数调优之外,硬件选型 和操作系统配置同样至关重要。很多时候,硬件和 OS 层面的优化能带来比 SQL 优化更显著的性能提升。
本文将从硬件选择、RAID 配置、文件系统、内核参数、多实例资源隔离等方面,深入讲解 MySQL 的底层优化策略。
硬件优化
硬件选择
MySQL 是一个 I/O 密集型 + CPU 密集型 的应用,硬件选择需要综合考虑 CPU、内存、存储三个维度。
CPU 选择
CPU 对 MySQL 性能的影响:
| 场景 | CPU 需求 | 说明 |
|---|---|---|
| OLTP(在线事务处理) | 高主频 | 单条 SQL 执行依赖单核性能 |
| OLAP(在线分析处理) | 多核心 | 复杂查询可并行执行 |
| 高并发连接 | 多核心 | 每个连接一个线程 |
| 排序/聚合操作 | 高主频 + 大缓存 | 计算密集型操作 |
选择建议:
-
OLTP 场景优先选择高主频 CPU
- MySQL 的大部分操作是单线程的(一条 SQL 由一个线程执行)
- 主频越高,单条 SQL 执行越快
- 推荐:Intel Xeon Platinum 8255C(2.5GHz)或更高主频
-
核心数根据并发量选择
- 一般 8-16 核足够大多数场景
- 高并发场景可选择 32 核以上
- MySQL 8.0 对多核优化更好
-
开启超线程(Hyper-Threading)
- 可提升 15-30% 的并发处理能力
- 但对于 CPU 密集型查询,效果有限
bash
# 查看 CPU 信息
lscpu
# 查看 CPU 主频
cat /proc/cpuinfo | grep "MHz"
# 查看是否开启超线程
cat /sys/devices/system/cpu/smt/active

内存选择
内存对 MySQL 性能的影响:
内存是 MySQL 性能的关键因素。InnoDB 的 Buffer Pool 越大,能缓存的数据越多,磁盘 I/O 越少。
内存配置原则:
| 配置项 | 建议值 | 说明 |
|---|---|---|
| 总内存 | 尽可能大 | 数据库服务器的核心资源 |
| Buffer Pool | 物理内存的 50-80% | InnoDB 最重要的内存区域 |
| 预留给 OS | 至少 2-4GB | 文件系统缓存、OS 运行 |
| 每连接内存 | 约 1-4MB | sort_buffer、join_buffer 等 |
计算公式:
可用于 MySQL 的内存 = 总内存 - OS 预留 - 其他应用
Buffer Pool = 可用内存 × 70-80%
示例:
对于 32GB 内存的服务器:
- OS 预留:4GB
- 可用于 MySQL:28GB
- Buffer Pool:20-22GB(
innodb_buffer_pool_size = 20G)
sql
-- 查看 Buffer Pool 大小
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- 查看 Buffer Pool 使用情况
SELECT
POOL_ID,
POOL_SIZE,
FREE_BUFFERS,
DATABASE_PAGES,
PAGES_MADE_YOUNG,
HIT_RATE
FROM information_schema.INNODB_BUFFER_POOL_STATS;



内存类型选择:
- 优先选择 DDR4 或 DDR5
- 选择支持 ECC(Error Correcting Code) 的内存
- 多通道配置可提升内存带宽
存储选择
存储是 MySQL 性能的最大瓶颈。选择合适的存储设备至关重要。
存储类型对比:
| 存储类型 | 随机读 IOPS | 随机写 IOPS | 顺序读带宽 | 延迟 | 价格 |
|---|---|---|---|---|---|
| HDD(机械硬盘) | 100-200 | 100-200 | 100-200 MB/s | 5-10ms | 低 |
| SATA SSD | 50,000-100,000 | 30,000-80,000 | 500-550 MB/s | 0.1ms | 中 |
| NVMe SSD | 500,000-1,000,000 | 200,000-500,000 | 3-7 GB/s | 0.02ms | 高 |
| Intel Optane | 500,000+ | 500,000+ | 2-3 GB/s | 0.01ms | 很高 |
选择建议:
-
OLTP 场景必须使用 SSD
- 随机 I/O 性能是 HDD 的 100-1000 倍
- 推荐 NVMe SSD
-
数据文件和日志文件分离
- Redo Log 放在高性能 SSD(写密集)
- 数据文件可放在普通 SSD
-
考虑写入寿命(TBW)
- 数据库写入量大,选择企业级 SSD
- 关注 DWPD(Drive Writes Per Day)指标
bash
# 查看磁盘信息
lsblk -d -o NAME,SIZE,ROTA,TYPE
# ROTA=0 表示 SSD,ROTA=1 表示 HDD
# 使用 fio 测试磁盘性能
# 随机读测试
fio --name=randread --ioengine=libaio --iodepth=32 --rw=randread \
--bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --filename=/data/fio_test
# 随机写测试
fio --name=randwrite --ioengine=libaio --iodepth=32 --rw=randwrite \
--bs=4k --direct=1 --size=1G --numjobs=4 --runtime=60 --filename=/data/fio_test

RAID 的选择
RAID(Redundant Arrays of Independent Disks,独立磁盘冗余阵列) 是通过多块磁盘组合来提升性能和可靠性的技术。
常见 RAID 级别对比
| RAID 级别 | 最少磁盘数 | 数据冗余 | 读性能 | 写性能 | 空间利用率 | 适用场景 |
|---|---|---|---|---|---|---|
| RAID 0 | 2 | 无 | 最高 | 最高 | 100% | 临时数据、缓存 |
| RAID 1 | 2 | 镜像 | 高 | 中 | 50% | 系统盘、日志 |
| RAID 5 | 3 | 1块校验 | 高 | 中 | (n-1)/n | 读多写少 |
| RAID 6 | 4 | 2块校验 | 高 | 低 | (n-2)/n | 高可靠性 |
| RAID 10 | 4 | 镜像+条带 | 最高 | 高 | 50% | 数据库推荐 |
MySQL RAID 配置建议
┌─────────────────────────────────────────────────────────┐
│ MySQL RAID 架构 │
├─────────────────────────────────────────────────────────┤
│ │
│ 系统盘 (OS + MySQL 二进制) │
│ └─ RAID 1 (2块 SSD) │
│ - 高可靠性 │
│ - 系统启动快 │
│ │
│ 数据盘 (数据文件 + 索引) │
│ └─ RAID 10 (4块或更多 SSD) │
│ - 高性能 + 高可靠性 │
│ - 随机 I/O 性能最佳 │
│ │
│ 日志盘 (Redo Log + Binlog) │
│ └─ RAID 1 (2块高性能 SSD) │
│ - 顺序写为主 │
│ - 写入性能关键 │
│ │
└─────────────────────────────────────────────────────────┘
配置建议:
-
数据文件使用 RAID 10
- 兼顾性能和可靠性
- 随机读写性能最佳
- 可承受单块磁盘故障
-
Redo Log 使用 RAID 1 或单独的高性能 SSD
- 顺序写为主,RAID 1 足够
- 写入延迟要求高
-
Binlog 可与 Redo Log 共用或单独存放
- 顺序写为主
- 对延迟要求不如 Redo Log 高
-
开启 RAID 卡的写缓存(BBU/电池保护)
- 显著提升写入性能
- 必须有电池保护,防止断电数据丢失
bash
# 查看 RAID 信息(以 MegaRAID 为例)
megacli -LDInfo -Lall -aALL
# 查看 RAID 卡缓存策略
megacli -LDGetProp -Cache -Lall -aALL
# 查看 BBU 状态
megacli -AdpBbuCmd -GetBbuStatus -aALL

RAID 写惩罚
不同 RAID 级别的写操作开销不同:
| RAID 级别 | 写惩罚 | 说明 |
|---|---|---|
| RAID 0 | 1 | 无冗余,直接写 |
| RAID 1 | 2 | 写入两份镜像 |
| RAID 5 | 4 | 读旧数据+读校验+写数据+写校验 |
| RAID 6 | 6 | 比 RAID 5 多一次校验计算 |
| RAID 10 | 2 | 每条带写两份镜像 |
计算实际 IOPS:
实际写 IOPS = 磁盘总 IOPS / 写惩罚
例如:4 块 SSD(每块 50000 IOPS)组成 RAID 10
- 总 IOPS:200000
- 写惩罚:2
- 实际写 IOPS:100000
操作系统的优化
文件系统的选择
文件系统的选择直接影响 MySQL 的 I/O 性能。
常见文件系统对比
| 文件系统 | 特点 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|---|
| XFS | 高性能、可扩展 | 大文件性能好、并发写入优秀 | 删除大量小文件慢 | MySQL 推荐 |
| ext4 | 稳定、成熟 | 兼容性好、小文件性能好 | 大文件性能不如 XFS | 通用场景 |
| Btrfs | 写时复制、快照 | 支持快照、压缩 | 性能不稳定 | 不推荐生产 |
| ZFS | 企业级特性 | 数据完整性、压缩、快照 | 内存占用大 | 特殊场景 |
MySQL 文件系统推荐
推荐使用 XFS,原因如下:
-
大文件性能优秀
- InnoDB 数据文件通常很大
- XFS 对大文件的顺序读写优化好
-
并发写入性能好
- 支持延迟分配(delayed allocation)
- 多线程写入不会相互阻塞
-
在线扩容
- 支持在线扩展文件系统大小
-
Linux 内核原生支持
- RHEL/CentOS 7+ 默认文件系统
XFS 挂载选项优化:
bash
# 推荐的 XFS 挂载选项
/dev/vdb /data xfs defaults,noatime,nodiratime,nobarrier 0 0
| 选项 | 说明 |
|---|---|
noatime |
不更新文件访问时间,减少写操作 |
nodiratime |
不更新目录访问时间 |
nobarrier |
禁用写屏障(需要 RAID 卡有 BBU) |
注意: nobarrier 选项在有电池保护的 RAID 卡上可以安全使用,否则可能导致数据丢失。
bash
# 查看当前挂载选项
mount | grep /data
# 查看文件系统类型
df -T /data
# 创建 XFS 文件系统
mkfs.xfs -f /dev/vdb
# 挂载 XFS
mount -o defaults,noatime,nodiratime /dev/vdb /data
系统参数的选择
Linux 内核参数对 MySQL 性能有重要影响。以下是关键参数的优化建议。
内存相关参数
1. vm.swappiness
控制系统使用 swap 的倾向。
bash
# 查看当前值
sysctl vm.swappiness
# 推荐设置为 1-10(MySQL 场景)
sysctl -w vm.swappiness=1
# 永久生效
echo "vm.swappiness = 1" >> /etc/sysctl.conf

| 值 | 说明 |
|---|---|
| 0 | 仅在内存不足时使用 swap |
| 1-10 | MySQL 推荐,尽量避免 swap |
| 60 | 默认值,积极使用 swap |
| 100 | 积极使用 swap |
为什么 MySQL 要避免 swap?
- swap 会导致严重的性能下降
- InnoDB Buffer Pool 被 swap 出去会导致大量磁盘 I/O
- 宁可 OOM 也不要 swap
2. vm.dirty_ratio 和 vm.dirty_background_ratio
控制脏页(dirty page)的刷新策略。
bash
# 查看当前值
sysctl vm.dirty_ratio
sysctl vm.dirty_background_ratio
# 推荐设置
sysctl -w vm.dirty_ratio=10
sysctl -w vm.dirty_background_ratio=5
# 永久生效
echo "vm.dirty_ratio = 10" >> /etc/sysctl.conf
echo "vm.dirty_background_ratio = 5" >> /etc/sysctl.conf
| 参数 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
vm.dirty_ratio |
40 | 10 | 脏页占内存比例达到此值时,进程阻塞等待刷盘 |
vm.dirty_background_ratio |
10 | 5 | 脏页占内存比例达到此值时,后台开始刷盘 |
3. vm.overcommit_memory
控制内存过量分配策略。
bash
# 查看当前值
sysctl vm.overcommit_memory
# 推荐设置为 0 或 2
sysctl -w vm.overcommit_memory=0
| 值 | 说明 |
|---|---|
| 0 | 默认,启发式过量分配 |
| 1 | 总是允许过量分配(危险) |
| 2 | 不允许过量分配,限制为 swap + 物理内存 × ratio |
透明大页(Transparent Huge Pages)
必须禁用透明大页!
透明大页(THP)会导致 MySQL 性能问题:
- 内存分配延迟增加
- 内存碎片化
- 随机的性能抖动
bash
# 查看当前状态
cat /sys/kernel/mm/transparent_hugepage/enabled
cat /sys/kernel/mm/transparent_hugepage/defrag
# 临时禁用
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 永久禁用(添加到 /etc/rc.local 或 systemd 服务)

永久禁用方法(systemd):
创建 /etc/systemd/system/disable-thp.service:
ini
[Unit]
Description=Disable Transparent Huge Pages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=mysqld.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag'
[Install]
WantedBy=basic.target
bash
# 启用服务
systemctl daemon-reload
systemctl enable disable-thp
systemctl start disable-thp
I/O 调度器
I/O 调度器决定了磁盘 I/O 请求的处理顺序。
常见 I/O 调度器:
| 调度器 | 特点 | 适用场景 |
|---|---|---|
| mq-deadline | 保证请求延迟,适合数据库 | SSD + MySQL 推荐 |
| none/noop | 不做调度,直接下发 | NVMe SSD |
| bfq | 公平带宽分配 | 桌面系统 |
| kyber | 低延迟优化 | 高性能 SSD |
bash
# 查看当前调度器
cat /sys/block/vda/queue/scheduler
# 临时修改
echo mq-deadline > /sys/block/vda/queue/scheduler
# 永久修改(添加到 /etc/udev/rules.d/60-scheduler.rules)
ACTION=="add|change", KERNEL=="sd*", ATTR{queue/scheduler}="mq-deadline"
ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="none"

对于 NVMe SSD:
- 推荐使用
none或mq-deadline - NVMe 本身有硬件队列,内核调度意义不大
文件描述符限制
MySQL 需要大量文件描述符(每个连接、每个表文件都需要)。
bash
# 查看当前限制
ulimit -n
# 查看系统最大值
cat /proc/sys/fs/file-max
# 修改用户限制(/etc/security/limits.conf)
mysql soft nofile 65535
mysql hard nofile 65535
# 修改系统最大值
sysctl -w fs.file-max=6553560

推荐配置:
bash
# /etc/security/limits.conf
mysql soft nofile 65535
mysql hard nofile 65535
mysql soft nproc 65535
mysql hard nproc 65535
网络参数优化
对于高并发 MySQL 服务器,网络参数也需要优化:
bash
# /etc/sysctl.conf
# 增加 TCP 连接队列
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# 增加端口范围
net.ipv4.ip_local_port_range = 1024 65535
# TCP 连接复用
net.ipv4.tcp_tw_reuse = 1
# 增加网络缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
完整的 sysctl 配置示例
bash
# /etc/sysctl.conf - MySQL 优化配置
# 内存相关
vm.swappiness = 1
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.overcommit_memory = 0
# 文件系统
fs.file-max = 6553560
fs.aio-max-nr = 1048576
# 网络相关
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# 应用配置
sysctl -p
MySQL 多实例资源隔离优化
在同一台服务器上运行多个 MySQL 实例时,需要进行资源隔离,避免实例之间相互影响。
资源隔离的必要性
| 问题 | 影响 | 解决方案 |
|---|---|---|
| CPU 争抢 | 某实例 CPU 占用过高影响其他实例 | CPU 绑定/cgroups |
| 内存争抢 | OOM 或 swap 影响所有实例 | 内存限制 |
| I/O 争抢 | 磁盘 I/O 带宽被某实例占满 | I/O 限制 |
| 网络争抢 | 网络带宽被某实例占满 | 网络 QoS |
cgroups 资源隔离
cgroups(Control Groups) 是 Linux 内核提供的资源隔离机制。
cgroups v1 vs v2:
| 特性 | cgroups v1 | cgroups v2 |
|---|---|---|
| 层级结构 | 多层级,每个控制器独立 | 单一层级 |
| 配置方式 | 各控制器目录分散 | 统一目录结构 |
| 资源控制 | 各控制器独立配置 | 统一接口 |
| 推荐版本 | 旧系统 | 新系统推荐 |
检查 cgroups 版本:
bash
# 检查是否支持 cgroups v2
cat /sys/fs/cgroup/cgroup.controllers 2>/dev/null && echo "cgroups v2" || echo "cgroups v1"
# 查看挂载的 cgroups
mount | grep cgroup

cgroups v1 配置(传统方式)
CPU 限制:
bash
# 创建 cgroup
mkdir -p /sys/fs/cgroup/cpu/mysql_instance1
# 限制 CPU 使用率为 50%(相对于单核)
echo 50000 > /sys/fs/cgroup/cpu/mysql_instance1/cpu.cfs_quota_us
echo 100000 > /sys/fs/cgroup/cpu/mysql_instance1/cpu.cfs_period_us
# 绑定到特定 CPU 核心
mkdir -p /sys/fs/cgroup/cpuset/mysql_instance1
echo "0-3" > /sys/fs/cgroup/cpuset/mysql_instance1/cpuset.cpus
echo "0" > /sys/fs/cgroup/cpuset/mysql_instance1/cpuset.mems
# 将进程加入 cgroup
echo <mysql_pid> > /sys/fs/cgroup/cpu/mysql_instance1/tasks
内存限制:
bash
# 创建 cgroup
mkdir -p /sys/fs/cgroup/memory/mysql_instance1
# 限制内存为 4GB
echo 4294967296 > /sys/fs/cgroup/memory/mysql_instance1/memory.limit_in_bytes
# 限制内存 + swap 总量
echo 4294967296 > /sys/fs/cgroup/memory/mysql_instance1/memory.memsw.limit_in_bytes
# 将进程加入 cgroup
echo <mysql_pid> > /sys/fs/cgroup/memory/mysql_instance1/tasks
I/O 限制:
bash
# 创建 cgroup
mkdir -p /sys/fs/cgroup/blkio/mysql_instance1
# 限制读写带宽(设备号:major:minor 读带宽 字节/秒)
# 查看设备号:ls -l /dev/vdb
echo "253:16 104857600" > /sys/fs/cgroup/blkio/mysql_instance1/blkio.throttle.read_bps_device
echo "253:16 52428800" > /sys/fs/cgroup/blkio/mysql_instance1/blkio.throttle.write_bps_device
# 限制 IOPS
echo "253:16 1000" > /sys/fs/cgroup/blkio/mysql_instance1/blkio.throttle.read_iops_device
echo "253:16 500" > /sys/fs/cgroup/blkio/mysql_instance1/blkio.throttle.write_iops_device
cgroups v2 配置(推荐)
cgroups v2 提供了统一的接口,配置更简洁。
启用 cgroups v2:
bash
# 在 GRUB 中添加参数
# /etc/default/grub
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"
# 更新 GRUB
grub2-mkconfig -o /boot/grub2/grub.cfg
# 重启系统
reboot
创建和配置 cgroup:
bash
# 创建 cgroup
mkdir -p /sys/fs/cgroup/mysql_instance1
# 启用控制器
echo "+cpu +memory +io" > /sys/fs/cgroup/cgroup.subtree_control
# CPU 限制(50% of 4 cores = 200000/100000)
echo "200000 100000" > /sys/fs/cgroup/mysql_instance1/cpu.max
# 内存限制(4GB)
echo "4294967296" > /sys/fs/cgroup/mysql_instance1/memory.max
echo "4294967296" > /sys/fs/cgroup/mysql_instance1/memory.swap.max
# I/O 限制(设备号 读带宽 写带宽 读IOPS 写IOPS)
echo "253:16 rbps=104857600 wbps=52428800 riops=1000 wiops=500" > /sys/fs/cgroup/mysql_instance1/io.max
# 将进程加入 cgroup
echo <mysql_pid> > /sys/fs/cgroup/mysql_instance1/cgroup.procs
cgroups v2 配置文件说明:
| 文件 | 说明 | 示例 |
|---|---|---|
cpu.max |
CPU 限制(quota period) | 200000 100000 = 200% CPU |
memory.max |
内存硬限制 | 4294967296 = 4GB |
memory.high |
内存软限制(触发回收) | 3221225472 = 3GB |
io.max |
I/O 带宽和 IOPS 限制 | 253:16 rbps=100M wbps=50M |
NUMA 绑定优化
NUMA(Non-Uniform Memory Access) 是多处理器系统的内存架构。在 NUMA 系统中,每个 CPU 有自己的本地内存,访问本地内存比访问远程内存更快。
查看 NUMA 拓扑:
bash
# 查看 NUMA 节点信息
numactl --hardware
# 查看 NUMA 统计
numastat
# 查看进程的 NUMA 分布
numastat -p <pid>

NUMA 绑定策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
--cpunodebind |
绑定到指定 NUMA 节点的 CPU | 限制 CPU 使用 |
--membind |
绑定到指定 NUMA 节点的内存 | 限制内存分配 |
--interleave |
内存交错分配到所有节点 | 大内存应用 |
--preferred |
优先使用指定节点,不够时使用其他 | 一般场景 |
MySQL NUMA 绑定示例:
bash
# 将 MySQL 绑定到 NUMA node 0
numactl --cpunodebind=0 --membind=0 mysqld
# 或者使用 Docker 启动时绑定
docker run -d \
--cpuset-cpus="0-3" \
--cpuset-mems="0" \
--name mysql-numa \
-e MYSQL_ROOT_PASSWORD=root \
mysql:8.0
# 查看容器的 NUMA 绑定状态
docker inspect mysql-numa --format "CPUSet: {{.HostConfig.CpusetCpus}}, MemSet: {{.HostConfig.CpusetMems}}"
NUMA 优化建议:
-
单实例场景
- 如果 MySQL 内存需求小于单个 NUMA 节点的内存,绑定到一个节点
- 如果内存需求大,使用
--interleave=all
-
多实例场景
- 每个实例绑定到不同的 NUMA 节点
- 避免跨节点内存访问
-
InnoDB 配置
- 设置
innodb_numa_interleave=1(MySQL 5.7.9+) - Buffer Pool 会交错分配到所有 NUMA 节点
- 设置
sql
-- 查看 NUMA 相关配置
SHOW VARIABLES LIKE '%numa%';

Docker 资源限制
在 Docker 中运行 MySQL 时,可以通过 Docker 的资源限制功能实现隔离。
CPU 限制:
bash
# 限制 CPU 使用率(相对于所有核心)
docker run -d \
--cpus="2.0" \
mysql:8.0
# 绑定到特定 CPU 核心
docker run -d \
--cpuset-cpus="0-3" \
mysql:8.0
# CPU 份额(相对权重)
docker run -d \
--cpu-shares=1024 \
mysql:8.0
内存限制:
bash
# 限制内存为 4GB
docker run -d \
--memory=4g \
--memory-swap=4g \
mysql:8.0
# 内存预留(软限制)
docker run -d \
--memory=4g \
--memory-reservation=2g \
mysql:8.0
I/O 限制:
bash
# 限制块设备读写带宽
docker run -d \
--device-read-bps /dev/vdb:100mb \
--device-write-bps /dev/vdb:50mb \
mysql:8.0
# 限制块设备 IOPS
docker run -d \
--device-read-iops /dev/vdb:1000 \
--device-write-iops /dev/vdb:500 \
mysql:8.0
完整的 Docker MySQL 资源限制示例:
bash
docker run -d \
--name mysql_instance1 \
--cpus="4.0" \
--cpuset-cpus="0-3" \
--memory=8g \
--memory-swap=8g \
--device-read-bps /dev/vdb:200mb \
--device-write-bps /dev/vdb:100mb \
-e MYSQL_ROOT_PASSWORD=password \
-v /data/mysql/instance1/data:/var/lib/mysql \
-v /data/mysql/instance1/conf:/etc/mysql/conf.d \
-p 3306:3306 \
mysql:8.0
docker-compose 配置示例:
yaml
version: '3.8'
services:
mysql_instance1:
image: mysql:8.0
container_name: mysql_instance1
deploy:
resources:
limits:
cpus: '4.0'
memory: 8G
reservations:
cpus: '2.0'
memory: 4G
environment:
MYSQL_ROOT_PASSWORD: password
volumes:
- /data/mysql/instance1/data:/var/lib/mysql
- /data/mysql/instance1/conf:/etc/mysql/conf.d
ports:
- "3306:3306"
cpuset: "0-3"
资源隔离最佳实践
┌─────────────────────────────────────────────────────────┐
│ MySQL 多实例资源隔离架构 │
├─────────────────────────────────────────────────────────┤
│ │
│ 服务器配置:32 核 CPU,128GB 内存,2 个 NUMA 节点 │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ MySQL 实例 1 │ │ MySQL 实例 2 │ │
│ │ │ │ │ │
│ │ NUMA Node: 0 │ │ NUMA Node: 1 │ │
│ │ CPU: 0-7 │ │ CPU: 16-23 │ │
│ │ Memory: 32GB │ │ Memory: 32GB │ │
│ │ I/O: 100MB/s │ │ I/O: 100MB/s │ │
│ │ │ │ │ │
│ │ Buffer Pool: │ │ Buffer Pool: │ │
│ │ 24GB │ │ 24GB │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ 预留资源: │
│ - OS + 监控:8 核 CPU,32GB 内存 │
│ - CPU 8-15, 24-31 用于其他服务 │
│ │
└─────────────────────────────────────────────────────────┘
配置清单:
| 配置项 | 实例 1 | 实例 2 |
|---|---|---|
| NUMA 节点 | 0 | 1 |
| CPU 核心 | 0-7 | 16-23 |
| 内存限制 | 32GB | 32GB |
| Buffer Pool | 24GB | 24GB |
| I/O 带宽 | 100MB/s | 100MB/s |
| 端口 | 3306 | 3307 |
性能测试与验证
优化效果需要通过性能测试来验证。以下介绍常用的测试工具和方法。
sysbench 基准测试
sysbench 是最常用的 MySQL 基准测试工具。
安装 sysbench:
bash
# CentOS/RHEL
yum install -y sysbench
# Ubuntu/Debian
apt-get install -y sysbench
# 验证安装
sysbench --version
OLTP 测试流程:
bash
# 1. 准备测试数据
sysbench oltp_read_write \
--mysql-host=127.0.0.1 \
--mysql-port=3306 \
--mysql-user=root \
--mysql-password=password \
--mysql-db=sbtest \
--tables=10 \
--table-size=1000000 \
prepare
# 2. 运行测试
sysbench oltp_read_write \
--mysql-host=127.0.0.1 \
--mysql-port=3306 \
--mysql-user=root \
--mysql-password=password \
--mysql-db=sbtest \
--tables=10 \
--table-size=1000000 \
--threads=16 \
--time=300 \
--report-interval=10 \
run
# 3. 清理测试数据
sysbench oltp_read_write \
--mysql-host=127.0.0.1 \
--mysql-port=3306 \
--mysql-user=root \
--mysql-password=password \
--mysql-db=sbtest \
--tables=10 \
cleanup
测试类型说明:
| 测试类型 | 说明 | 适用场景 |
|---|---|---|
oltp_read_only |
只读测试 | 读密集型应用 |
oltp_write_only |
只写测试 | 写密集型应用 |
oltp_read_write |
混合读写 | 通用 OLTP 场景 |
oltp_point_select |
主键查询 | 测试索引性能 |
oltp_insert |
插入测试 | 测试写入性能 |
关键指标解读:
SQL statistics:
queries performed:
read: 1400000
write: 400000
other: 200000
total: 2000000
transactions: 100000 (333.33 per sec.) # TPS
queries: 2000000 (6666.67 per sec.) # QPS
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
Latency (ms):
min: 2.35
avg: 47.99 # 平均延迟
max: 512.34
95th percentile: 89.16 # P95 延迟
sum: 4799000.00
| 指标 | 说明 | 优化目标 |
|---|---|---|
| TPS | 每秒事务数 | 越高越好 |
| QPS | 每秒查询数 | 越高越好 |
| avg latency | 平均延迟 | 越低越好 |
| 95th percentile | P95 延迟 | 越低越好 |
Docker 优化配置对比测试
使用 Docker 启动两个 MySQL 实例,对比默认配置和优化配置的性能差异。
启动默认配置 MySQL:
bash
docker run -d --name mysql-default \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=sbtest \
-p 3316:3306 \
mysql:8.0
启动优化配置 MySQL:
bash
docker run -d --name mysql-optimized \
--cpuset-cpus='0-3' \
--memory=4g \
--memory-swap=4g \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=sbtest \
-p 3317:3306 \
mysql:8.0 \
--innodb_buffer_pool_size=2G \
--innodb_log_file_size=512M \
--innodb_flush_log_at_trx_commit=2 \
--innodb_flush_method=O_DIRECT \
--max_connections=500

默认配置 sysbench 测试结果:

优化配置 sysbench 测试结果:

性能对比:
| 指标 | 默认配置 | 优化配置 | 提升幅度 |
|---|---|---|---|
| TPS | 620.61 | 900.81 | +45.1% |
| QPS | 12412.12 | 18016.17 | +45.1% |
| 平均延迟 | 12.89ms | 8.88ms | -31.1% |
| P95 延迟 | 17.63ms | 11.87ms | -32.7% |
通过 CPU 绑定(--cpuset-cpus)、内存限制(--memory)和 InnoDB 参数优化,性能提升显著。
fio 磁盘性能测试
fio 用于测试磁盘 I/O 性能。
bash
# 随机读测试(模拟数据库随机查询)
fio --name=randread \
--ioengine=libaio \
--iodepth=32 \
--rw=randread \
--bs=4k \
--direct=1 \
--size=1G \
--numjobs=4 \
--runtime=60 \
--group_reporting \
--filename=/data/fio_test
# 随机写测试(模拟数据库写入)
fio --name=randwrite \
--ioengine=libaio \
--iodepth=32 \
--rw=randwrite \
--bs=4k \
--direct=1 \
--size=1G \
--numjobs=4 \
--runtime=60 \
--group_reporting \
--filename=/data/fio_test
# 混合随机读写(70% 读,30% 写)
fio --name=randrw \
--ioengine=libaio \
--iodepth=32 \
--rw=randrw \
--rwmixread=70 \
--bs=4k \
--direct=1 \
--size=1G \
--numjobs=4 \
--runtime=60 \
--group_reporting \
--filename=/data/fio_test
监控指标采集
系统级监控:
bash
# CPU 使用率
vmstat 1
# 内存使用
free -h
# 磁盘 I/O
iostat -x 1
# 网络流量
sar -n DEV 1


MySQL 级监控:
sql
-- 查看 InnoDB 状态
SHOW ENGINE INNODB STATUS\G
-- 查看 Buffer Pool 命中率
SHOW STATUS LIKE 'Innodb_buffer_pool%';
-- 查看连接数
SHOW STATUS LIKE 'Threads%';
-- 查看慢查询
SHOW STATUS LIKE 'Slow_queries';



总结
MySQL 的硬件和操作系统优化是一个系统工程,需要从多个维度进行考虑:
硬件选择:
- CPU:OLTP 优先高主频,高并发选择多核心
- 内存:越大越好,Buffer Pool 配置为物理内存的 50-80%
- 存储:必须使用 SSD,推荐 NVMe,数据和日志分离
RAID 配置:
- 数据文件使用 RAID 10
- 日志文件使用 RAID 1 或高性能单盘
- 开启 RAID 卡写缓存(需要 BBU 保护)
文件系统:
- 推荐 XFS 文件系统
- 使用 noatime、nodiratime 挂载选项
- 有 BBU 的 RAID 卡可使用 nobarrier
内核参数:
- vm.swappiness = 1,避免 swap
- 禁用透明大页(THP)
- I/O 调度器使用 mq-deadline 或 none
- 增加文件描述符限制
多实例资源隔离:
- 使用 cgroups 限制 CPU、内存、I/O
- NUMA 绑定优化内存访问
- Docker 资源限制简化管理
在实际工作中,需要根据具体的业务场景和硬件配置,选择合适的优化策略。优化是一个持续的过程,需要不断监控和调整。