数据库读写IOPS突破30万是真的吗?香港NVMe RAID服务器如何核验性能数据?
“数据库读写 IOPS 突破 30 万”并非一定是假的,但它只有在明确测试条件时才有意义。4KB 随机读、较高队列深度、多个并发任务下,香港 NVMe RAID 服务器的存储层可能达到 30 万级 IOPS;这并不等于实际数据库在开启事务持久化、日志同步和混合读写后,也能稳定完成 30 万次有效数据库操作。
核验时不要只看宣传截图或一个峰值数字,应至少同时确认四件事:测试的块大小与读写比例、队列深度与并发方式、延迟分布尤其是 p99、以及数据库真实负载下的 TPS 和提交延迟。只有存储层结果、数据库层结果和持续运行表现能够相互对应,30 万 IOPS 才能作为有参考价值的性能结论。
先把“30万 IOPS”换算成可理解的指标
IOPS 是每秒完成的 I/O 操作次数,不是固定的带宽单位。相同的 IOPS,在不同块大小下代表完全不同的数据量。
计算方式是:
每秒数据量 = IOPS × 单次 I/O 数据量
例如:

- 300,000 IOPS × 4KB,约等于 1.2GB/s,换算为约 9.6Gbps;
- 300,000 IOPS × 16KB,约等于 4.8GB/s,换算为约 38.4Gbps;
- 300,000 IOPS × 1MB,则相当于 300GB/s,这已经不是通常意义上的 4KB 随机数据库测试场景。
这里按十进制换算:1GB=1000MB,1MB=1000KB,1Byte=8bit。由此可见,只写“30 万 IOPS”而不写块大小,几乎无法判断结果是否与数据库场景相关。
还要区分以下三类结果:
| 结果类型 | 能说明什么 | 不能说明什么 |
|---|---|---|
| 存储层随机读 IOPS | RAID 卷在指定块大小、队列和并发下的处理能力 | 不能代表写入能力和事务提交速度 |
| 存储层混合读写 IOPS | 指定读写比例下的物理 I/O 能力 | 不能直接等同于数据库 TPS |
| 数据库压测 TPS、提交延迟 | 数据库引擎在具体参数下的实际业务处理能力 | 不能脱离数据库版本、数据量和事务模型比较 |
因此,“读写 IOPS 突破 30 万”至少要继续追问:是随机读,还是混合读写?读写比例是多少?块大小是 4KB 还是 16KB?队列深度是多少?结果是峰值还是持续值?测试时是否启用了写回缓存?数据库是否开启了真正的日志落盘确认?
香港 NVMe RAID 服务器需要先核对什么
香港只是服务器所在地区,不能替代具体硬件和阵列配置。相同机房、相同带宽条件下,不同批次的 NVMe 盘数量、型号、RAID 级别、控制器缓存策略和文件系统,都可能使结果出现明显差异。
确认测试对象确实是 RAID 卷
测试前应在服务器本机执行信息采集,而不是仅在远程客户端通过网络发起一个应用请求。Linux 环境可以先查看块设备、NVMe 盘和阵列状态:

lsblk -o NAME,MODEL,SIZE,ROTA,TYPE,FSTYPE,MOUNTPOINTS
sudo nvme list
cat /proc/mdstat
df -hT /data
如果使用 Linux 软件 RAID,还应查看阵列详细信息:
sudo mdadm --detail /dev/md0
/dev/md0 只是示例路径,实际设备名应以 cat /proc/mdstat 和 lsblk 的结果为准。若使用硬件 RAID 或专用阵列控制器,操作系统可能只看到一个逻辑卷,此时还需要从服务商控制面板或控制器管理工具确认:
- RAID 级别是 RAID0、RAID10 还是其他模式;
- 阵列包含几块 NVMe 盘;
- 是否存在写回缓存;
- 写回缓存是否有电容、缓存保护或其他掉电保护;
- 文件系统和数据库数据目录是否确实位于该阵列卷;
- 数据目录、日志目录是否被拆分到不同设备。
不能把“服务器配有多块 NVMe”直接理解为“数据库正在使用 NVMe RAID”。如果 fio 测试文件写到了另一块单盘、临时盘或系统盘,结果就与目标阵列无关。
确认 RAID 级别和缓存策略
RAID0 可能在并行随机读写中取得较高峰值,但不提供盘级冗余;RAID10 通常更适合需要同时读写和恢复能力的数据库场景;带校验计算的阵列在小块随机写入中可能受到额外开销影响。这里不能只比较“盘的数量”,还要看数据写入路径和持久化策略。
尤其要警惕控制器或 SSD 的写回缓存。若设备先把数据放入易失缓存,再向测试程序返回完成,短时间内的写 IOPS 可能非常高,但这不代表掉电后数据已经安全落盘。对于数据库而言,真正有意义的是开启持久化确认后,事务提交仍能保持怎样的延迟和吞吐。
用四组指标核验存储层性能
存储层测试的目标不是制造一个最大的数字,而是把宣传数字还原成完整的测试组合。一个可复核的结果至少应包含以下字段:
| 指标 | 必须记录的内容 | 对结果的影响 |
|---|---|---|
| 块大小 | 4KB、8KB、16KB 等 | 决定单次 I/O 的数据量和访问模式 |
| 读写比例 | 100%读、100%写、70/30 混合等 | 写入通常更容易受到阵列和缓存影响 |
| 队列深度 | QD1、QD4、QD32、QD256 等 | 队列越深,越容易堆出峰值,但不一定接近业务 |
| 并发任务数 | numjobs、线程或进程数量 | 影响 CPU、队列和调度方式 |
| 访问方式 | 随机或顺序、直接 I/O 或缓存 I/O | 决定测试的是设备还是操作系统缓存 |
| 延迟 | 平均值、p95、p99、最大值 | 反映业务请求是否出现长尾 |
| 持续时间 | 预热时间、正式运行时间 | 用于观察缓存耗尽和温度导致的下降 |
| 测试位置 | 实际 RAID 挂载点 | 避免测到错误设备 |
先做低队列深度测试
低队列深度能够观察单个或少量请求的响应能力。对于数据库,QD1 或较低并发下的延迟,往往比极高队列深度下的峰值更有解释力。
以下命令仅作测试格式示例。/data/bench 必须是专门用于测试的目录,不能指向生产数据库目录、生产日志目录或唯一数据盘。fio 会创建并写入测试文件,运行前应确认该路径有备份或其中没有需要保留的数据。
fio --name=randread-4k-q1 \
--filename=/data/bench/fio-testfile \
--size=20G \
--rw=randread \
--bs=4k \
--ioengine=libaio \
--direct=1 \
--iodepth=1 \
--numjobs=1 \
--time_based \
--runtime=300 \
--ramp_time=30 \
--group_reporting \
--output-format=normal
这组测试主要观察:
- QD1 下的 4KB 随机读延迟;
- 单个任务是否能稳定完成 I/O;
- 低并发时阵列是否存在明显响应抖动;
- 结果是否与服务商给出的高队列深度数字差距过大。
如果 QD1 延迟较高,而 QD256 才能出现 30 万 IOPS,说明这个数字更接近阵列的并行处理上限,不宜直接用于推断单事务数据库性能。
再做混合读写和纯写测试
数据库通常不是纯读。即使业务以查询为主,也会产生 redo、binlog、WAL、临时表或后台刷盘。因此至少需要分别观察纯读、纯写和混合读写。
下面是一个 4KB、70%读和30%写的高并发示例:
fio --name=randrw-4k-70r30w \
--filename=/data/bench/fio-testfile \
--size=100G \
--rw=randrw \
--rwmixread=70 \
--bs=4k \
--ioengine=libaio \
--direct=1 \
--iodepth=32 \
--numjobs=8 \
--time_based \
--runtime=600 \
--ramp_time=60 \
--group_reporting \
--output-format=normal
iodepth=32、numjobs=8意味着理论上的总并发队列约为 256,但实际有效队列还会受到设备、内核和应用调度影响。测试文件大小也应根据设备容量和 fio 版本的任务分配方式核算,不能简单把 --size 当作整个阵列只会占用这一部分空间。
纯写测试可以用相同参数将 --rw=randrw 改为 --rw=randwrite,并移除 --rwmixread。纯写测试对 SSD 磨损和阵列缓存压力更大,必须使用隔离卷,不能在生产目录执行。正式测试前应确认备份、影响范围和剩余容量;测试文件后续只应在确认不再需要时单独清理,不要误操作生产目录。
测试过程中,另一个终端应同步记录设备利用率、等待时间和系统资源:

iostat -xmd 1 660
vmstat 1
pidstat -d 1
重点不是某一秒的最高值,而是以下变化:
- IOPS 是否在预热后迅速下降;
await或读写等待时间是否逐步升高;- 设备利用率是否长期接近满载;
- CPU 是否先达到瓶颈;
- 混合写入时是否出现明显长尾;
- 运行十分钟左右后,结果是否仍在同一量级。
如果测试只运行十几秒,且结果明显高于长时间运行结果,应将前者视为缓存峰值,而不是持续性能。
为什么必须进行数据库层测试
fio 只能回答“这个块设备在指定 I/O 模式下能处理多少请求”,不能回答“某个数据库在提交事务时能完成多少有效工作”。
数据库会额外涉及:
- 页面读取和页面淘汰;
- redo、WAL 或 binlog 写入;
- fsync、flush 和提交确认;
- 行锁、事务锁和并发控制;
- SQL 解析、索引访问和 CPU 消耗;
- 数据库缓冲池与操作系统缓存;
- 后台刷脏页和检查点;
- 网络往返或客户端线程调度。
因此,数据库层至少要记录 TPS、平均响应时间、p95 或 p99 延迟、物理读写量以及 CPU 利用率。数据库报告中的“操作次数”也不能直接等于磁盘 IOPS,一个事务可能包含多次页面访问,也可能大部分数据命中内存。
以 MySQL 为例检查持久化条件
先读取关键参数,不要在生产数据库上为了追求数字随意修改它们:
mysql -h 127.0.0.1 -u bench -p -e \
"SHOW VARIABLES WHERE Variable_name IN
('innodb_buffer_pool_size',
'innodb_flush_log_at_trx_commit',
'sync_binlog',
'sync_log',
'innodb_doublewrite');"
对于需要可靠事务提交的测试,至少应记录 innodb_flush_log_at_trx_commit 和 sync_binlog 的值。若测试关闭了日志同步,得到的 TPS 不能与开启持久化确认的结果放在同一张表里比较。
数据库测试应使用单独的测试库和测试账号。若测试库中已有数据,先完成备份;不要在生产库执行 prepare、批量写入或清理操作。下面是一个隔离测试库中的 sysbench 示例:
sysbench oltp_read_write \
--mysql-host=127.0.0.1 \
--mysql-port=3306 \
--mysql-user=bench \
--mysql-password='CHANGE_ME' \
--mysql-db=sbtest \
--tables=8 \
--table-size=1000000 \
--threads=32 \
--time=600 \
--warmup-time=60 \
--report-interval=10 \
--db-ps-mode=auto \
run
如果测试库为空,需要先在该隔离库中准备数据:
sysbench oltp_read_write \
--mysql-host=127.0.0.1 \
--mysql-port=3306 \
--mysql-user=bench \
--mysql-password='CHANGE_ME' \
--mysql-db=sbtest \
--tables=8 \
--table-size=1000000 \
--threads=32 \
--db-ps-mode=auto \
prepare
prepare 会向测试库写入数据,不能指向生产数据库。测试数据量应根据服务器内存和数据库缓冲池调整:如果所有工作集都能完全放入内存,测试更接近缓存命中能力;如果数据量明显超过可用缓存,才更容易观察存储子系统的持续读写压力。两种测试都有价值,但必须明确属于哪一种。
记录数据库结果时不要只看 TPS
数据库测试结果至少应按下面的方式整理:
| 项目 | 示例记录方式 | 判断重点 |
|---|---|---|
| 测试引擎 | MySQL 版本、存储引擎、配置摘要 | 不同版本和引擎不能直接横比 |
| 数据规模 | 表数量、行数、总数据量、索引大小 | 判断是否主要命中内存 |
| 并发数 | 8、32、64 个线程等 | 并发改变会显著影响 TPS |
| 事务模型 | 读写比例、每事务语句数 | 决定物理 I/O 和锁竞争 |
| 持久化设置 | redo、binlog、fsync 相关参数 | 影响提交安全性和延迟 |
| 结果 | TPS、平均延迟、p95、p99 | 判断吞吐和长尾 |
| 资源状态 | CPU、内存、磁盘利用率、读写等待 | 区分存储瓶颈和其他瓶颈 |
如果数据库 TPS 在 CPU 已经接近满载时停止增长,不能简单归因于 NVMe RAID 性能不足;如果 CPU 负载不高、磁盘等待明显升高,同时提交 p99 延迟持续增加,才更可能是存储路径成为瓶颈。
如何阅读一组“30万 IOPS”示例数据
下面是一组用于说明阅读方法的示例数据,不代表任何具体香港服务器的实测结果:

| 测试项目 | 参数 | 示例结果 | 结果含义 |
|---|---|---|---|
| 4KB随机读 | QD1、1任务 | 48,000 IOPS,p99 0.40ms | 低队列响应能力 |
| 4KB混合读写 | 70%读、30%写,QD约256 | 306,000 IOPS,p99 2.1ms | 高并发下的存储层峰值 |
| 4KB随机写 | QD约256 | 175,000 IOPS,p99 4.9ms | 写入和落盘压力下的能力 |
| 数据库事务 | 32线程,开启事务持久化 | 13,800 TPS,提交p99 9.6ms | 具体数据库负载下的有效处理能力 |
这组数据并不矛盾。混合块设备测试达到 30 万 IOPS,而数据库只有 13,800 TPS,可能是因为一个数据库事务包含多次物理 I/O,还受到锁、CPU、日志提交和 SQL 执行开销影响。
反过来,如果某份报告只给出“4KB随机读 30 万 IOPS”,却把它描述为“数据库读写性能 30 万”,就存在明显的口径扩大。以下几种情况也不能直接认可为数据库读写 30 万:
- 只测试了 100%随机读;
- 只测试了几秒钟的突发峰值;
- 队列深度和线程数没有公开;
direct=0,结果可能大量来自操作系统缓存;- 测试的是单块 NVMe,而数据库实际使用的是另一块卷;
- 开启了写回缓存,但没有说明缓存保护;
- 数据库关闭了日志同步或事务持久化;
- 只展示 IOPS,没有延迟、TPS 和持续运行曲线;
- 测试时的数据量远小于内存,无法说明真实存储压力。
复测时要保持哪些条件不变
性能复测最容易出现的问题,是表面上重复了测试,实际上改变了测试条件。要让两次结果可以比较,至少应保持以下内容一致:
- 相同的 RAID 级别、成员盘数量和阵列卷。
- 相同的文件系统、挂载点和测试文件位置。
- 相同的块大小、读写比例、队列深度和并发任务数。
- 相同的测试文件规模、预热时间和正式运行时间。
- 相同的数据库版本、数据规模、线程数和事务模型。
- 相同的持久化参数、日志设置和缓存策略。
- 相同的运行时段记录方式,包括 CPU、内存、磁盘等待和温度状态。
- 至少进行三次独立运行,并保留每次原始输出,而不是只保留最高成绩。
如果首次测试使用了刚启动、尚未升温的设备,复测则应在相近的预热状态下进行。若首次结果来自服务商提供的截图,复测时应要求完整命令、原始输出和环境信息,不能只对照截图上的一个数字。
选择时只认可以复核的结果
对于香港 NVMe RAID 服务器,30 万 IOPS 可以作为一个待验证的性能目标,但不应当被当作脱离条件的固定能力。比较可靠的判断方式是:
- 存储层明确给出 4KB 或数据库相关块大小下的随机读、随机写和混合读写结果;
- 公开队列深度、并发任务、测试文件规模、直接 I/O 设置和持续时间;
- 同时提供平均延迟与 p99 延迟,而不是只给 IOPS 峰值;
- 说明 RAID 级别、NVMe 盘数量、阵列缓存和掉电保护情况;
- 在实际数据库配置下重新测试,并记录 TPS、提交延迟和磁盘等待;
- 经过预热和较长时间运行后,结果没有明显跌落;
- 能够在同一服务器的实际挂载卷上复测出相近结果。
如果只能确认“某次高并发 4KB 随机测试超过 30 万 IOPS”,那么准确表述应是“该阵列在特定存储测试条件下达到 30 万级峰值”。如果数据库在开启持久化、使用实际数据规模和混合读写事务后仍能保持目标 TPS,并且 p99 延迟处于可接受范围,才可以把这项存储能力与数据库业务性能建立联系。