文章

MySQL 硬件优化和操作系统优化

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/a18

MySQL 硬件优化和操作系统优化

文章信息

  • 原文链接:https://jiayq.blog.csdn.net/article/details/156576804
  • 发布时间:2026-09-17 16:18:24
  • 标签:#mysql, #大数据, #技术分享, ##NUMA, ##系统参数

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

思维导图

数据库性能优化是一个系统工程,除了 SQL 优化、索引优化、参数调优之外,硬件选型操作系统配置 同样至关重要。很多时候,硬件和 OS 层面的优化能带来比 SQL 优化更显著的性能提升。

本文将从硬件选择、RAID 配置、文件系统、内核参数、多实例资源隔离等方面,深入讲解 MySQL 的底层优化策略。

硬件优化

硬件选择

MySQL 是一个 I/O 密集型 + CPU 密集型 的应用,硬件选择需要综合考虑 CPU、内存、存储三个维度。

CPU 选择

CPU 对 MySQL 性能的影响:

场景CPU 需求说明
OLTP(在线事务处理)高主频单条 SQL 执行依赖单核性能
OLAP(在线分析处理)多核心复杂查询可并行执行
高并发连接多核心每个连接一个线程
排序/聚合操作高主频 + 大缓存计算密集型操作

选择建议:

  1. OLTP 场景优先选择高主频 CPU

    • MySQL 的大部分操作是单线程的(一条 SQL 由一个线程执行)
    • 主频越高,单条 SQL 执行越快
    • 推荐:Intel Xeon Platinum 8255C(2.5GHz)或更高主频
  2. 核心数根据并发量选择

    • 一般 8-16 核足够大多数场景
    • 高并发场景可选择 32 核以上
    • MySQL 8.0 对多核优化更好
  3. 开启超线程(Hyper-Threading)

    • 可提升 15-30% 的并发处理能力
    • 但对于 CPU 密集型查询,效果有限
1
2
3
4
5
6
7
8
9
# 查看 CPU 信息
lscpu

# 查看 CPU 主频
cat /proc/cpuinfo | grep "MHz"

# 查看是否开启超线程
cat /sys/devices/system/cpu/smt/active

查看 CPU 信息

内存选择

内存对 MySQL 性能的影响:

内存是 MySQL 性能的关键因素。InnoDB 的 Buffer Pool 越大,能缓存的数据越多,磁盘 I/O 越少。

内存配置原则:

配置项建议值说明
总内存尽可能大数据库服务器的核心资源
Buffer Pool物理内存的 50-80%InnoDB 最重要的内存区域
预留给 OS至少 2-4GB文件系统缓存、OS 运行
每连接内存约 1-4MBsort_buffer、join_buffer 等

计算公式:

1
2
3
可用于 MySQL 的内存 = 总内存 - OS 预留 - 其他应用
Buffer Pool = 可用内存 × 70-80%

示例:

对于 32GB 内存的服务器:

  • OS 预留:4GB
  • 可用于 MySQL:28GB
  • Buffer Pool:20-22GB(innodb_buffer_pool_size = 20G
1
2
3
4
5
6
7
8
9
10
11
12
13
-- 查看 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;

查看 Buffer Pool 大小

查看 Buffer Pool 使用情况

查看内存信息

内存类型选择:

  • 优先选择 DDR4DDR5
  • 选择支持 ECC(Error Correcting Code) 的内存
  • 多通道配置可提升内存带宽
存储选择

存储是 MySQL 性能的最大瓶颈 。选择合适的存储设备至关重要。

存储类型对比:

存储类型随机读 IOPS随机写 IOPS顺序读带宽延迟价格
HDD(机械硬盘)100-200100-200100-200 MB/s5-10ms
SATA SSD50,000-100,00030,000-80,000500-550 MB/s0.1ms
NVMe SSD500,000-1,000,000200,000-500,0003-7 GB/s0.02ms
Intel Optane500,000+500,000+2-3 GB/s0.01ms很高

选择建议:

  1. OLTP 场景必须使用 SSD

    • 随机 I/O 性能是 HDD 的 100-1000 倍
    • 推荐 NVMe SSD
  2. 数据文件和日志文件分离

    • Redo Log 放在高性能 SSD(写密集)
    • 数据文件可放在普通 SSD
  3. 考虑写入寿命(TBW)

    • 数据库写入量大,选择企业级 SSD
    • 关注 DWPD(Drive Writes Per Day)指标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 查看磁盘信息
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 02最高最高100%临时数据、缓存
RAID 12镜像50%系统盘、日志
RAID 531块校验(n-1)/n读多写少
RAID 642块校验(n-2)/n高可靠性
RAID 104镜像+条带最高50%数据库推荐
MySQL RAID 配置建议
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────────┐
│                    MySQL RAID 架构                       │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   系统盘 (OS + MySQL 二进制)                             │
│   └─ RAID 1 (2块 SSD)                                   │
│      - 高可靠性                                          │
│      - 系统启动快                                        │
│                                                         │
│   数据盘 (数据文件 + 索引)                               │
│   └─ RAID 10 (4块或更多 SSD)                            │
│      - 高性能 + 高可靠性                                 │
│      - 随机 I/O 性能最佳                                 │
│                                                         │
│   日志盘 (Redo Log + Binlog)                            │
│   └─ RAID 1 (2块高性能 SSD)                             │
│      - 顺序写为主                                        │
│      - 写入性能关键                                      │
│                                                         │
└─────────────────────────────────────────────────────────┘

配置建议:

  1. 数据文件使用 RAID 10

    • 兼顾性能和可靠性
    • 随机读写性能最佳
    • 可承受单块磁盘故障
  2. Redo Log 使用 RAID 1 或单独的高性能 SSD

    • 顺序写为主,RAID 1 足够
    • 写入延迟要求高
  3. Binlog 可与 Redo Log 共用或单独存放

    • 顺序写为主
    • 对延迟要求不如 Redo Log 高
  4. 开启 RAID 卡的写缓存(BBU/电池保护)

    • 显著提升写入性能
    • 必须有电池保护,防止断电数据丢失
1
2
3
4
5
6
7
8
9
# 查看 RAID 信息(以 MegaRAID 为例)
megacli -LDInfo -Lall -aALL

# 查看 RAID 卡缓存策略
megacli -LDGetProp -Cache -Lall -aALL

# 查看 BBU 状态
megacli -AdpBbuCmd -GetBbuStatus -aALL

查看 RAID 信息

RAID 写惩罚

不同 RAID 级别的写操作开销不同:

RAID 级别写惩罚说明
RAID 01无冗余,直接写
RAID 12写入两份镜像
RAID 54读旧数据+读校验+写数据+写校验
RAID 66比 RAID 5 多一次校验计算
RAID 102每条带写两份镜像

计算实际 IOPS:

1
2
实际写 IOPS = 磁盘总 IOPS / 写惩罚

例如:4 块 SSD(每块 50000 IOPS)组成 RAID 10

  • 总 IOPS:200000
  • 写惩罚:2
  • 实际写 IOPS:100000

操作系统的优化

文件系统的选择

文件系统的选择直接影响 MySQL 的 I/O 性能。

常见文件系统对比
文件系统特点优点缺点推荐场景
XFS高性能、可扩展大文件性能好、并发写入优秀删除大量小文件慢MySQL 推荐
ext4稳定、成熟兼容性好、小文件性能好大文件性能不如 XFS通用场景
Btrfs写时复制、快照支持快照、压缩性能不稳定不推荐生产
ZFS企业级特性数据完整性、压缩、快照内存占用大特殊场景
MySQL 文件系统推荐

推荐使用 XFS ,原因如下:

  1. 大文件性能优秀

    • InnoDB 数据文件通常很大
    • XFS 对大文件的顺序读写优化好
  2. 并发写入性能好

    • 支持延迟分配(delayed allocation)
    • 多线程写入不会相互阻塞
  3. 在线扩容

    • 支持在线扩展文件系统大小
  4. Linux 内核原生支持

    • RHEL/CentOS 7+ 默认文件系统

XFS 挂载选项优化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 推荐的 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 的倾向。

1
2
3
4
5
6
7
8
9
# 查看当前值
sysctl vm.swappiness

# 推荐设置为 1-10(MySQL 场景)
sysctl -w vm.swappiness=1

# 永久生效
echo "vm.swappiness = 1" >> /etc/sysctl.conf

查看 sysctl 参数

说明
0仅在内存不足时使用 swap
1-10MySQL 推荐 ,尽量避免 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)的刷新策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 查看当前值
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[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

1
2
3
4
5
6
7
8
9
10
# 查看当前调度器
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"

查看 I/O 调度器

对于 NVMe SSD:

  • 推荐使用 nonemq-deadline
  • NVMe 本身有硬件队列,内核调度意义不大
文件描述符限制

MySQL 需要大量文件描述符(每个连接、每个表文件都需要)。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看当前限制
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

查看文件描述符限制

推荐配置:

1
2
3
4
5
6
# /etc/security/limits.conf
mysql soft nofile 65535
mysql hard nofile 65535
mysql soft nproc 65535
mysql hard nproc 65535

网络参数优化

对于高并发 MySQL 服务器,网络参数也需要优化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# /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 配置示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# /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 v1cgroups v2
层级结构多层级,每个控制器独立单一层级
配置方式各控制器目录分散统一目录结构
资源控制各控制器独立配置统一接口
推荐版本旧系统新系统推荐

检查 cgroups 版本:

1
2
3
4
5
6
# 检查是否支持 cgroups v2
cat /sys/fs/cgroup/cgroup.controllers 2>/dev/null && echo "cgroups v2" || echo "cgroups v1"

# 查看挂载的 cgroups
mount | grep cgroup

查看 cgroups 挂载

cgroups v1 配置(传统方式)

CPU 限制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建 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

内存限制:

1
2
3
4
5
6
7
8
9
10
11
12
# 创建 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 限制:

1
2
3
4
5
6
7
8
9
10
11
12
# 创建 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:

1
2
3
4
5
6
7
8
9
10
# 在 GRUB 中添加参数
# /etc/default/grub
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"

# 更新 GRUB
grub2-mkconfig -o /boot/grub2/grub.cfg

# 重启系统
reboot

创建和配置 cgroup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建 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.maxCPU 限制(quota period)200000 100000 = 200% CPU
memory.max内存硬限制4294967296 = 4GB
memory.high内存软限制(触发回收)3221225472 = 3GB
io.maxI/O 带宽和 IOPS 限制253:16 rbps=100M wbps=50M
NUMA 绑定优化

NUMA(Non-Uniform Memory Access) 是多处理器系统的内存架构。在 NUMA 系统中,每个 CPU 有自己的本地内存,访问本地内存比访问远程内存更快。

查看 NUMA 拓扑:

1
2
3
4
5
6
7
8
9
# 查看 NUMA 节点信息
numactl --hardware

# 查看 NUMA 统计
numastat

# 查看进程的 NUMA 分布
numastat -p <pid>

查看 NUMA 拓扑

NUMA 绑定策略:

策略说明适用场景
--cpunodebind绑定到指定 NUMA 节点的 CPU限制 CPU 使用
--membind绑定到指定 NUMA 节点的内存限制内存分配
--interleave内存交错分配到所有节点大内存应用
--preferred优先使用指定节点,不够时使用其他一般场景

MySQL NUMA 绑定示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 将 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 优化建议:

  1. 单实例场景

    • 如果 MySQL 内存需求小于单个 NUMA 节点的内存,绑定到一个节点
    • 如果内存需求大,使用 --interleave=all
  2. 多实例场景

    • 每个实例绑定到不同的 NUMA 节点
    • 避免跨节点内存访问
  3. InnoDB 配置

    • 设置 innodb_numa_interleave=1(MySQL 5.7.9+)
    • Buffer Pool 会交错分配到所有 NUMA 节点
1
2
3
-- 查看 NUMA 相关配置
SHOW VARIABLES LIKE '%numa%';

查看 NUMA 相关配置

Docker 资源限制

在 Docker 中运行 MySQL 时,可以通过 Docker 的资源限制功能实现隔离。

CPU 限制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 限制 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

内存限制:

1
2
3
4
5
6
7
8
9
10
11
12
# 限制内存为 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 限制:

1
2
3
4
5
6
7
8
9
10
11
12
# 限制块设备读写带宽
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 资源限制示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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"

资源隔离最佳实践
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌─────────────────────────────────────────────────────────┐
│              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 节点01
CPU 核心0-716-23
内存限制32GB32GB
Buffer Pool24GB24GB
I/O 带宽100MB/s100MB/s
端口33063307

性能测试与验证

优化效果需要通过性能测试来验证。以下介绍常用的测试工具和方法。

sysbench 基准测试

sysbench 是最常用的 MySQL 基准测试工具。

安装 sysbench:

1
2
3
4
5
6
7
8
9
# CentOS/RHEL
yum install -y sysbench

# Ubuntu/Debian
apt-get install -y sysbench

# 验证安装
sysbench --version

OLTP 测试流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 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插入测试测试写入性能

关键指标解读:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

Docker MySQL 容器状态

默认配置 sysbench 测试结果:

默认配置测试结果

优化配置 sysbench 测试结果:

优化配置测试结果

性能对比:

指标默认配置优化配置提升幅度
TPS620.61900.81+45.1%
QPS12412.1218016.17+45.1%
平均延迟12.89ms8.88ms-31.1%
P95 延迟17.63ms11.87ms-32.7%

通过 CPU 绑定(--cpuset-cpus)、内存限制(--memory)和 InnoDB 参数优化,性能提升显著。

fio 磁盘性能测试

fio 用于测试磁盘 I/O 性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 随机读测试(模拟数据库随机查询)
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

监控指标采集

系统级监控:

1
2
3
4
5
6
7
8
9
10
11
12
# CPU 使用率
vmstat 1

# 内存使用
free -h

# 磁盘 I/O
iostat -x 1

# 网络流量
sar -n DEV 1

vmstat 监控

iostat 监控

MySQL 级监控:

1
2
3
4
5
6
7
8
9
10
11
12
-- 查看 InnoDB 状态
SHOW ENGINE INNODB STATUS\G

-- 查看 Buffer Pool 命中率
SHOW STATUS LIKE 'Innodb_buffer_pool%';

-- 查看连接数
SHOW STATUS LIKE 'Threads%';

-- 查看慢查询
SHOW STATUS LIKE 'Slow_queries';

Buffer Pool 状态

线程状态

慢查询统计

总结

MySQL 的硬件和操作系统优化是一个系统工程,需要从多个维度进行考虑:

硬件选择:

  1. CPU :OLTP 优先高主频,高并发选择多核心
  2. 内存 :越大越好,Buffer Pool 配置为物理内存的 50-80%
  3. 存储 :必须使用 SSD,推荐 NVMe,数据和日志分离

RAID 配置:

  1. 数据文件使用 RAID 10
  2. 日志文件使用 RAID 1 或高性能单盘
  3. 开启 RAID 卡写缓存(需要 BBU 保护)

文件系统:

  1. 推荐 XFS 文件系统
  2. 使用 noatime、nodiratime 挂载选项
  3. 有 BBU 的 RAID 卡可使用 nobarrier

内核参数:

  1. vm.swappiness = 1,避免 swap
  2. 禁用透明大页(THP)
  3. I/O 调度器使用 mq-deadline 或 none
  4. 增加文件描述符限制

多实例资源隔离:

  1. 使用 cgroups 限制 CPU、内存、I/O
  2. NUMA 绑定优化内存访问
  3. Docker 资源限制简化管理

在实际工作中,需要根据具体的业务场景和硬件配置,选择合适的优化策略。优化是一个持续的过程,需要不断监控和调整。

本文由作者按照 CC BY 4.0 进行授权