最近我们买了几台 Hetzner 的 AX102 独立服务器,并加入了 15.36 TB NVMe SSD Datacenter Edition 用于我们内部的服务,在网上看到少有关于这台机器的评测,我们想来分享一些这个机器的信息,希望可以帮助到在观望这个机器配置的小伙伴们。
基本信息
机器使用的是 AMD Ryzen™ 9 7950X3D CPU,自带 128 GB DDR5 ECC 和 2x 1.92 TB NVMe SSD Datacenter Edition (Gen4),每个月基本价格 104EUR(芬兰区域)。
此外添加了一块 Hetzner 称为 15.36 TB NVMe SSD Datacenter Edition 的 SSD,每月 130EUR。

AX102 对于 Hetzner AX 线来说这个是第一个「企业级」配置了。

在前面的几个配置中,不是内存没有 ECC(例如 AX52,和早期的 AX41-NVMe),就是自带的硬盘不是 Datacenter Edition,对于没有 ECC 和 Datacenter 的机器跑跑无状态应用还行,但是一旦到了生产环境,容易付出一些本不必付出的代价,例如:

所以这一次特地选用了全部 ECC + “Datacenter Edition” 的配置,在做足了安全措施(指冷/热备份)的情况下将一些重要服务迁移到 AX102 上,来评估整体稳定性和 ROI 表现。
基本 Benckmark
话不多说,我们首先参考本博客第一篇也是唯一登录过 Hackernews 首页的博文「Hetzner CAX 系列 ARM64 服务器性能简评以及 WebP Cloud Services 在其上的实践」文章中的基本测试开始!

使用测试脚本指令:
curl -sL yabs.sh | bash -s -- -i
基本信息
Processor : AMD Ryzen 9 7950X3D 16-Core Processor
CPU cores : 32 @ 4865.977 MHz
AES-NI : ✔ Enabled
VM-x/AMD-V : ✔ Enabled
RAM : 124.9 GiB
Swap : 0.0 KiB
Disk : 15.6 TiB
Distro : Ubuntu 24.04.3 LTS
Kernel : 6.8.0-85-generic
VM Type : NONE
IPv4/IPv6 : ✔ Online / ✔ Online
IPv6 Network Information:
---------------------------------
ISP : Hetzner Online GmbH
ASN : AS24940 Hetzner Online GmbH
Location : Helsinki, Uusimaa (18)
Country : Finland
Geekbench 6 Benchmark Test:
---------------------------------
Test | Value
|
Single Core | 2365
Multi Core | 14981
基本磁盘信息
由于这台机器带有三块磁盘,型号分别如下:
- 2x 1.92 TB NVMe SSD Datacenter Edition
- Micron_7450_MTFDKCC1T9TFR
- 15.36 TB NVMe SSD Datacenter Edition
- MTFDKCC15T3TGP-1BK1DABYY
通过搜索我们可以知道:
1.92 TB 的是 Micron 7450 NVMe SSD ,官网链接:https://www.micron.com/products/storage/ssd/data-center-ssd/7450-ssd ,标称性能如下:
- Sequential 128KB READ: Up to 6800 MB/s
- Sequential 128KB WRITE: Up to 5600 MB/s
- Random 4KB READ: Up to 1,000,000 IOPS
- Random 4KB WRITE: Up to 400,000 IOPS
15.36 TB 的还是 Micron,不过是 7500 PRO,标称性能如下:
Read speed (max.) 7000 MB/s
Write speed (max.) 5900 MB/s
Read access (max.) 1,100,000 IOPS
Write access (max.) 250,000 IOPS
由于 1.92TB 的 NVMe 做了 RAID,测试结果可能不太具有代表性,这次我们着重对于 15T 的 NVMe 进行测试,在上面的测试脚本中,我们得到了这样的数据:
fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/nvme2n1):
---------------------------------
Block Size | 4k (IOPS) | 64k (IOPS)
------ | --- ---- | ---- ----
Read | 775.69 MB/s (193.9k) | 2.69 GB/s (42.0k)
Write | 777.74 MB/s (194.4k) | 2.70 GB/s (42.2k)
Total | 1.55 GB/s (388.3k) | 5.39 GB/s (84.3k)
| |
Block Size | 512k (IOPS) | 1m (IOPS)
------ | --- ---- | ---- ----
Read | 3.10 GB/s (6.0k) | 3.10 GB/s (3.0k)
Write | 3.26 GB/s (6.3k) | 3.30 GB/s (3.2k)
Total | 6.37 GB/s (12.4k) | 6.41 GB/s (6.2k)
说实话,看上去比较惊艳了,为了帮助读者对比 Hetzner 其他机器的性能,我们又挑选并购买了一台不是 Datacenter NVMe 的 AX41-NVMe 机器和两台 Cloud 的机器的测试结果粘贴如下。
参与对比的机器为如下:
- AX41-NVMe(另一个独立服务器,AMD Ryzen™ 5 3600 CPU,搭配 512G 普通 NVMe)
- 磁盘是 SAMSUNG MZVL2512HCJQ-00B00(Samsung PM9A1)
- CCX63(Dedicated Resources 下最大的配置,拥有 48Core,192GB RAM 和 960GB LocalSSD)
- CAX41(ARM64 下的最大配置,拥有 16Core,32GB RAM 和 320GB LocalSSD)
对于 Cloud 测试均在机器的 / 目录测试,用来测试机器自带的 LocalSSD 性能,AX41-NVMe 机器在挂载了硬盘的分区上测试。
AX41-NVMe
---------------------------------
Block Size | 4k (IOPS) | 64k (IOPS)
------ | --- ---- | ---- ----
Read | 509.95 MB/s (127.4k) | 1.43 GB/s (22.4k)
Write | 511.30 MB/s (127.8k) | 1.44 GB/s (22.5k)
Total | 1.02 GB/s (255.3k) | 2.87 GB/s (44.9k)
| |
Block Size | 512k (IOPS) | 1m (IOPS)
------ | --- ---- | ---- ----
Read | 1.87 GB/s (3.6k) | 2.05 GB/s (2.0k)
Write | 1.97 GB/s (3.8k) | 2.19 GB/s (2.1k)
Total | 3.84 GB/s (7.5k) | 4.24 GB/s (4.1k)
可以看出在 NVMe 裸盘上跑出的性能都挺不错,到了 Cloud 的测试中会略微逊色一些,如下:
CCX63
fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/sda1):
---------------------------------
Block Size | 4k (IOPS) | 64k (IOPS)
------ | --- ---- | ---- ----
Read | 109.71 MB/s (27.4k) | 1.00 GB/s (15.7k)
Write | 110.00 MB/s (27.5k) | 1.01 GB/s (15.8k)
Total | 219.71 MB/s (54.9k) | 2.02 GB/s (31.5k)
| |
Block Size | 512k (IOPS) | 1m (IOPS)
------ | --- ---- | ---- ----
Read | 1.33 GB/s (2.5k) | 1.18 GB/s (1.1k)
Write | 1.40 GB/s (2.7k) | 1.26 GB/s (1.2k)
Total | 2.73 GB/s (5.3k) | 2.44 GB/s (2.3k)
CAX41
fio Disk Speed Tests (Mixed R/W 50/50) (Partition /dev/sda1):
---------------------------------
Block Size | 4k (IOPS) | 64k (IOPS)
------ | --- ---- | ---- ----
Read | 96.69 MB/s (24.1k) | 579.80 MB/s (9.0k)
Write | 96.62 MB/s (24.1k) | 597.04 MB/s (9.3k)
Total | 193.32 MB/s (48.3k) | 1.17 GB/s (18.3k)
| |
Block Size | 512k (IOPS) | 1m (IOPS)
------ | --- ---- | ---- ----
Read | 816.20 MB/s (1.5k) | 1.09 GB/s (1.0k)
Write | 886.02 MB/s (1.7k) | 1.22 GB/s (1.1k)
Total | 1.70 GB/s (3.3k) | 2.31 GB/s (2.2k)
哦,不得不提一下,如果你是挂载了 Hetzner 的 Volume 的话,得到的结果是这样的:
fio Disk Speed Tests (Mixed R/W 50/50):
---------------------------------
Block Size | 4k (IOPS) | 64k (IOPS)
------ | --- ---- | ---- ----
Read | 29.70 MB/s (7.4k) | 314.04 MB/s (4.9k)
Write | 29.68 MB/s (7.4k) | 323.38 MB/s (5.0k)
Total | 59.38 MB/s (14.8k) | 637.43 MB/s (9.9k)
| |
Block Size | 512k (IOPS) | 1m (IOPS)
------ | --- ---- | ---- ----
Read | 298.03 MB/s (582) | 288.82 MB/s (282)
Write | 323.52 MB/s (631) | 322.23 MB/s (314)
Total | 621.56 MB/s (1.2k) | 611.05 MB/s (596)
所以不要用 Volume 上面跑什么奇怪的高负载应用,不然 IOWait 会让你怀疑人生。
Datacenter SSD?
这次我们特别提到了 Datacenter NVMe,那么它和普通的 NVMe 主要的差异是什么?
首先在宏观设计哲学上,两者的目标截然不同:
- 普通 NVMe (Consumer): 设计目标是 “爆发力” 。它假设用户的负载是突发的(Bursty)、读多写少的(如系统启动、游戏加载)。它极度依赖 SLC Cache(模拟 SLC),一旦缓存写满,性能会呈断崖式下跌。
- 企业级 NVMe (Enterprise): 设计目标是 “确定性” (Determinism) 和 稳态性能 (Steady State)。它假设设备将 24/7 满负荷运行,不仅看重平均延迟,更看重 99.99th 百分位(P99.99)的尾延迟稳定性。
所以我们往往可以看到一些消费级的 NVMe 都有着很高的(顺序)读写速度,而且会发现同样的价格下企业级的 NVMe 比消费级的要贵不少。
好,那这个时候就有读者问了:那我不 care 这些所谓的高负载平均延迟和尾延迟稳定性,我有充足的灾备措施,是不是就没有必要去买企业级 NVMe ,直接用消费级 NVMe 就行了?
还记得上面那张 Twitter 截图嘛?我当时也是这么想的…
这个时候就会引入企业级 NVMe 的另一个优势——PLP(Power Loss Protection)。在理解 PLP 之前,我们需要看看 fsync 是什么:
在 Linux 系统中,当你调用 write 写入数据时,操作系统出于性能考虑,并不会立刻把数据写到 SSD 上,而是先扔进内存里的 Page Cache(页缓存),然后立刻告诉你“写完了”。
这在一般场景下没有什么问题,操作系统上许多标准的文件操作并不要求数据即刻落盘,而是依赖内核的 pdflush 或工作队列在后台从容地进行脏页回写(Dirty Page Writeback),以此换取极致的内存读写性能。”
比如你在 Windows 的设备管理器 -> 磁盘管理中可以看到这么个设置(默认都是开启状态的):

但数据库不这么认为,为了保证每次数据是真正被保存了(而不是等待操作系统提交),数据库(如 MySQL 的 redo log 落盘)会强制调用 fsync 或 fdatasync。
fsync的语义是: “我不管你(OS)和硬盘怎么协调,我现在就要阻塞线程,直到硬盘明确回复我‘数据已经物理刻录在介质上了’,我才继续下一步。”
对于没有掉电保护(PLP)的普通消费级 SSD,当它收到主机的 fsync 指令时,它会经历如下步骤:
- 强制刷盘: 主控必须将 DRAM 缓存中所有相关的脏数据,立刻编程写入到 NAND Flash 颗粒中。
- 物理延迟: NAND Flash 的写入并不快。TLC/QLC 的编程周期(Program time)通常在 50us 到几百 us 甚至更久。
- 返回确认: 只有当电荷真正注入到晶圆的单元格里,主控才敢向主机发送“ACK”确认信号。
在这个过程中,CPU 在等,数据库线程在等,所有的业务都在等这几百微秒的物理操作。因此,在频繁 Sync Write 的场景下(如数据库事务提交),消费级 SSD 的 IOPS 被物理介质的写入延迟死死锁住,通常只有几千 IOPS。
对于企业级 SSD 而言,由于配备了 PLP。
- 当收到
fsync指令,主控只需要把数据写入板载的 DRAM 缓存,就可以立刻向 OS 返回“成功”。 - 原理: 即使此刻突然拔电,板载电容提供的电力足够主控在几毫秒内将 DRAM 中的脏数据刷入 NAND。
- 后果:
fsync的延迟等同于写入 DRAM 的延迟(纳秒级)。这使得企业级 SSD 在 Sync Write 场景下的 IOPS 可以比消费级高出 10 倍甚至更多。
上面的差异反应到大家常会在服务器上跑的数据库(如今谁的服务器上还不会跑一个数据库呢?)上就是:
数据库为了保证 ACID 中的 D (Durability),通常要求 Write Ahead Log (WAL) 必须落盘(例如 MySQL 的 innodb_flush_log_at_trx_commit=1)。
- 现象: 这种写入通常是小块(4K~16K)、顺序但极其频繁的
fsync调用。 - 普通 NVMe: 即使标称顺序写速度有 3000MB/s,但在频繁
fsync下,吞吐量可能跌至几十 MB/s,导致数据库 TPS(每秒事务数)上不去。 - 企业级 NVMe: 依靠 PLP,能轻松吃下高频的小块 Sync Write,TPS 几乎随 CPU 线性扩展。
这个时候有同学就要问了,如何直观感受到这种差距呢?
PGBench
为了方便直观感受,我们使用 PGSQL 自带的 pgbench 来搞个测试,测试统一使用如下方式启动 PGSQL(我知道用容器启动并不是一个被推荐的方式,这不是用来测试嘛?),在 Hetzner Cloud 上就是在 / 目录下运行,在 AX102 和 AX41-NVMe 机器上是在使用 ext4 文件系统挂载的 15T NVMe 的磁盘下运行。
version: "3.8"
services:
db:
image: postgres:18-alpine
restart: always
shm_size: 1g
environment:
PGUSER: postgres
POSTGRES_PASSWORD: hellopassword
POSTGRES_DB: tester
volumes:
- ./db_data:/var/lib/postgresql/18/docker
healthcheck:
test: [ "CMD", "pg_isready", "-h", "db", "-U", "${PGUSER:-postgres}", "-d", "${POSTGRES_DB:-tester}" ]
interval: 1s
timeout: 3s
retries: 60
测试指令如下:
createdb pgbench_test
pgbench -i -s 100 pgbench_test
pgbench -c 16 -j 4 -T 60 pgbench_test
AX102
pgbench (18.0)
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 16
number of threads: 4
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 1556888
number of failed transactions: 0 (0.000%)
latency average = 0.617 ms
initial connection time = 9.362 ms
tps = 25951.831902 (without initial connection time)
AX41-NVMe
让我们来同样是独立服务器 + NVMe,且根据上面硬盘跑分来看差异不大,但是不是 Datacenter SSD 的 AX41-NVMe 的表现:
pgbench (18.1)
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 16
number of threads: 4
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 323149
number of failed transactions: 0 (0.000%)
latency average = 2.971 ms
initial connection time = 12.635 ms
tps = 5385.896737 (without initial connection time)
可以看到,一旦遇到了 fsync 场景下,TPS 一下子就掉到了只有 1/5。
请注意,这里的差异不仅仅是硬盘性能带来的,由于 AX102 配备的 7950X3D CPU 性能远强于 AX41 的 Ryzen 3600,也导致了 TPS 比 AX41 高。不过还请注意观察 latency average (延迟) 和稍后的 fio fsync 专项测试,在 latency average 表现中,AX102 的平均延迟为 0.617 ms,而 AX41-NVMe 是 2.971 ms。
在 fio 这种排除 CPU 干扰的纯 IO 测试中,企业级硬盘展示了 50 倍以上的 IOPS 优势,这才是数据库不卡顿的关键。
顺便,同样的方式我们来看看 Cloud 的表现:
CCX63
pgbench (18.0)
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 16
number of threads: 4
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 388748
number of failed transactions: 0 (0.000%)
latency average = 2.469 ms
initial connection time = 19.118 ms
tps = 6480.864372 (without initial connection time)
CAX41
pgbench (18.0)
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 100
query mode: simple
number of clients: 16
number of threads: 4
maximum number of tries: 1
duration: 60 s
number of transactions actually processed: 301215
number of failed transactions: 0 (0.000%)
latency average = 3.185 ms
initial connection time = 39.615 ms
tps = 5023.234052 (without initial connection time)
FIO
最后,我们也使用了同样的 fio 程序对磁盘的带 fsync 性能进行了测试。
测试指令:
TEST_FILE=/mnt/fio_fsync_test.dat
fio --name=fsync-test --filename=$TEST_FILE --size=5G --ioengine=libaio --direct=0 --rw=write --bs=8k --numjobs=1 --iodepth=1 --fsync=1 --group_reporting
简单来说结论如下:
- AX102
- min= 8306, max=10842, avg=10318.05, stdev=512.82, samples=126
- AX41-NVMe
- min= 146, max= 194, avg=187.15, stdev= 4.94, samples=7003
- CCX63
- min= 602, max= 1178, avg=822.16, stdev=115.33, samples=1594
- CAX41
- min= 418, max= 991, avg=727.56, stdev=93.69, samples=1801
详细结果如下(由于结果太长,已经折叠):
点我展开看 fio 结果
CAX41
fio --name=fsync-test --filename=$TEST_FILE --size=5G --ioengine=libaio --direct=0 --rw=write --bs=8k --numjobs=1 --iodepth=1 --fsync=1 --group_reporting
fsync-test: (g=0): rw=write, bs=(R) 8192B-8192B, (W) 8192B-8192B, (T) 8192B-8192B, ioengine=libaio, iodepth=1
fio-3.36
Starting 1 process
fsync-test: Laying out IO file (1 file / 5120MiB)
Jobs: 1 (f=1): [W(1)][100.0%][w=6064KiB/s][w=758 IOPS][eta 00m:00s]
fsync-test: (groupid=0, jobs=1): err= 0: pid=7397: Tue Nov 11 13:22:04 2025
write: IOPS=726, BW=5815KiB/s (5955kB/s)(5120MiB/901547msec); 0 zone resets
slat (usec): min=8, max=7282, avg=34.96, stdev=31.44
clat (nsec): min=1120, max=3602.4k, avg=3768.39, stdev=8391.96
lat (usec): min=9, max=7368, avg=38.73, stdev=33.14
clat percentiles (usec):
| 1.00th=[ 3], 5.00th=[ 3], 10.00th=[ 3], 20.00th=[ 3],
| 30.00th=[ 3], 40.00th=[ 4], 50.00th=[ 4], 60.00th=[ 4],
| 70.00th=[ 4], 80.00th=[ 5], 90.00th=[ 5], 95.00th=[ 6],
| 99.00th=[ 13], 99.50th=[ 21], 99.90th=[ 45], 99.95th=[ 80],
| 99.99th=[ 277]
bw ( KiB/s): min= 3344, max= 7935, per=100.00%, avg=5821.29, stdev=749.69, samples=1801
iops : min= 418, max= 991, avg=727.56, stdev=93.69, samples=1801
lat (usec) : 2=0.65%, 4=74.41%, 10=23.75%, 20=0.67%, 50=0.44%
lat (usec) : 100=0.05%, 250=0.03%, 500=0.01%, 750=0.01%, 1000=0.01%
lat (msec) : 2=0.01%, 4=0.01%
fsync/fdatasync/sync_file_range:
sync (usec): min=468, max=50797, avg=1336.17, stdev=774.61
sync percentiles (usec):
| 1.00th=[ 717], 5.00th=[ 783], 10.00th=[ 832], 20.00th=[ 898],
| 30.00th=[ 963], 40.00th=[ 1037], 50.00th=[ 1123], 60.00th=[ 1237],
| 70.00th=[ 1401], 80.00th=[ 1598], 90.00th=[ 1975], 95.00th=[ 2474],
| 99.00th=[ 4490], 99.50th=[ 5342], 99.90th=[ 8979], 99.95th=[11207],
| 99.99th=[17957]
cpu : usr=1.06%, sys=8.48%, ctx=1312544, majf=0, minf=13
IO depths : 1=200.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=0,655360,0,655359 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
WRITE: bw=5815KiB/s (5955kB/s), 5815KiB/s-5815KiB/s (5955kB/s-5955kB/s), io=5120MiB (5369MB), run=901547-901547msec
Disk stats (read/write):
sda: ios=18/1968375, sectors=528/31683384, merge=0/1321571, ticks=6/714675, in_queue=986506, util=77.33%
AX102
fio --name=fsync-test --filename=$TEST_FILE --size=5G --ioengine=libaio --direct=0 --rw=write --bs=8k --numjobs=1 --iodepth=1 --fsync=1 --group_reporting
fsync-test: (g=0): rw=write, bs=(R) 8192B-8192B, (W) 8192B-8192B, (T) 8192B-8192B, ioengine=libaio, iodepth=1
fio-3.36
Starting 1 process
fsync-test: Laying out IO file (1 file / 5120MiB)
Jobs: 1 (f=1): [W(1)][100.0%][w=80.2MiB/s][w=10.3k IOPS][eta 00m:00s]
fsync-test: (groupid=0, jobs=1): err= 0: pid=2347193: Tue Nov 11 14:08:52 2025
write: IOPS=10.3k, BW=80.6MiB/s (84.5MB/s)(5120MiB/63524msec); 0 zone resets
slat (usec): min=3, max=847, avg= 5.86, stdev= 4.22
clat (nsec): min=480, max=625479, avg=640.36, stdev=955.14
lat (usec): min=4, max=848, avg= 6.50, stdev= 4.47
clat percentiles (nsec):
| 1.00th=[ 490], 5.00th=[ 502], 10.00th=[ 510], 20.00th=[ 510],
| 30.00th=[ 524], 40.00th=[ 532], 50.00th=[ 540], 60.00th=[ 548],
| 70.00th=[ 588], 80.00th=[ 684], 90.00th=[ 876], 95.00th=[ 1032],
| 99.00th=[ 1448], 99.50th=[ 1864], 99.90th=[ 8512], 99.95th=[11968],
| 99.99th=[21632]
bw ( KiB/s): min=66448, max=86736, per=100.00%, avg=82544.38, stdev=4102.53, samples=126
iops : min= 8306, max=10842, avg=10318.05, stdev=512.82, samples=126
lat (nsec) : 500=1.22%, 750=83.20%, 1000=9.37%
lat (usec) : 2=5.78%, 4=0.17%, 10=0.19%, 20=0.06%, 50=0.01%
lat (usec) : 100=0.01%, 750=0.01%
fsync/fdatasync/sync_file_range:
sync (usec): min=52, max=6975, avg=90.81, stdev=41.37
sync percentiles (usec):
| 1.00th=[ 67], 5.00th=[ 73], 10.00th=[ 77], 20.00th=[ 81],
| 30.00th=[ 84], 40.00th=[ 87], 50.00th=[ 89], 60.00th=[ 91],
| 70.00th=[ 93], 80.00th=[ 96], 90.00th=[ 101], 95.00th=[ 111],
| 99.00th=[ 163], 99.50th=[ 200], 99.90th=[ 375], 99.95th=[ 570],
| 99.99th=[ 1713]
cpu : usr=1.54%, sys=20.19%, ctx=1325091, majf=0, minf=16
IO depths : 1=200.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=0,655360,0,655359 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
WRITE: bw=80.6MiB/s (84.5MB/s), 80.6MiB/s-80.6MiB/s (84.5MB/s-84.5MB/s), io=5120MiB (5369MB), run=63524-63524msec
Disk stats (read/write):
nvme2n1: ios=66675/2008316, sectors=4288160/38031992, merge=14/1356438, ticks=9377/40112, in_queue=49490, util=61.98%
CCX63
fio --name=fsync-test --filename=$TEST_FILE --size=5G --ioengine=libaio --direct=0 --rw=write --bs=8k --numjobs=1 --iodepth=1 --fsync=1 --group_reporting
fsync-test: (g=0): rw=write, bs=(R) 8192B-8192B, (W) 8192B-8192B, (T) 8192B-8192B, ioengine=libaio, iodepth=1
fio-3.36
Starting 1 process
fsync-test: Laying out IO file (1 file / 5120MiB)
Jobs: 1 (f=1): [W(1)][100.0%][w=5749KiB/s][w=718 IOPS][eta 00m:00s]
fsync-test: (groupid=0, jobs=1): err= 0: pid=3616829: Tue Nov 11 13:20:52 2025
write: IOPS=821, BW=6572KiB/s (6730kB/s)(5120MiB/797748msec); 0 zone resets
slat (usec): min=8, max=4587, avg=26.51, stdev=27.83
clat (nsec): min=1172, max=594986, avg=2655.72, stdev=2212.45
lat (usec): min=10, max=4589, avg=29.16, stdev=28.18
clat percentiles (nsec):
| 1.00th=[ 1368], 5.00th=[ 1560], 10.00th=[ 1608], 20.00th=[ 1688],
| 30.00th=[ 1832], 40.00th=[ 2256], 50.00th=[ 2736], 60.00th=[ 2864],
| 70.00th=[ 2960], 80.00th=[ 3056], 90.00th=[ 3344], 95.00th=[ 3856],
| 99.00th=[ 5408], 99.50th=[12736], 99.90th=[35072], 99.95th=[39680],
| 99.99th=[53504]
bw ( KiB/s): min= 4816, max= 9424, per=100.00%, avg=6578.23, stdev=922.67, samples=1594
iops : min= 602, max= 1178, avg=822.16, stdev=115.33, samples=1594
lat (usec) : 2=34.57%, 4=61.31%, 10=3.50%, 20=0.32%, 50=0.28%
lat (usec) : 100=0.01%, 250=0.01%, 500=0.01%, 750=0.01%
fsync/fdatasync/sync_file_range:
sync (usec): min=560, max=99343, avg=1188.78, stdev=407.12
sync percentiles (usec):
| 1.00th=[ 742], 5.00th=[ 799], 10.00th=[ 840], 20.00th=[ 898],
| 30.00th=[ 971], 40.00th=[ 1045], 50.00th=[ 1139], 60.00th=[ 1254],
| 70.00th=[ 1369], 80.00th=[ 1434], 90.00th=[ 1516], 95.00th=[ 1614],
| 99.00th=[ 2114], 99.50th=[ 2835], 99.90th=[ 5080], 99.95th=[ 5735],
| 99.99th=[ 8356]
cpu : usr=0.72%, sys=8.52%, ctx=1314198, majf=0, minf=15
IO depths : 1=200.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=0,655360,0,655359 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
WRITE: bw=6572KiB/s (6730kB/s), 6572KiB/s-6572KiB/s (6730kB/s-6730kB/s), io=5120MiB (5369MB), run=797748-797748msec
Disk stats (read/write):
sda: ios=0/1980548, sectors=0/33330920, merge=0/1377610, ticks=0/652120, in_queue=906250, util=78.84%
AX41-NVMe
fio --name=fsync-test --filename=$TEST_FILE --size=5G --ioengine=libaio --direct=0 --rw=write --bs=8k --numjobs=1 --iodepth=1 --fsync=1 --group_reporting
fsync-test: (g=0): rw=write, bs=(R) 8192B-8192B, (W) 8192B-8192B, (T) 8192B-8192B, ioengine=libaio, iodepth=1
fio-3.36
Starting 1 process
fsync-test: Laying out IO file (1 file / 5120MiB)
Jobs: 1 (f=1): [W(1)][100.0%][w=1505KiB/s][w=188 IOPS][eta 00m:00s]
fsync-test: (groupid=0, jobs=1): err= 0: pid=21222: Fri Nov 21 15:39:44 2025
write: IOPS=187, BW=1497KiB/s (1533kB/s)(5120MiB/3502354msec); 0 zone resets
slat (usec): min=8, max=1031, avg=19.54, stdev= 6.14
clat (nsec): min=752, max=1238.4k, avg=1971.06, stdev=1724.91
lat (usec): min=8, max=1258, avg=21.52, stdev= 6.75
clat percentiles (nsec):
| 1.00th=[ 988], 5.00th=[ 1320], 10.00th=[ 1496], 20.00th=[ 1560],
| 30.00th=[ 1608], 40.00th=[ 1720], 50.00th=[ 1832], 60.00th=[ 1976],
| 70.00th=[ 2160], 80.00th=[ 2320], 90.00th=[ 2640], 95.00th=[ 2800],
| 99.00th=[ 3504], 99.50th=[ 4048], 99.90th=[13632], 99.95th=[17024],
| 99.99th=[22912]
bw ( KiB/s): min= 1168, max= 1555, per=100.00%, avg=1497.67, stdev=39.50, samples=7003
iops : min= 146, max= 194, avg=187.15, stdev= 4.94, samples=7003
lat (nsec) : 1000=1.08%
lat (usec) : 2=59.81%, 4=38.59%, 10=0.36%, 20=0.14%, 50=0.02%
lat (usec) : 100=0.01%
lat (msec) : 2=0.01%
fsync/fdatasync/sync_file_range:
sync (usec): min=4950, max=43794, avg=5323.43, stdev=491.68
sync percentiles (usec):
| 1.00th=[ 5145], 5.00th=[ 5145], 10.00th=[ 5145], 20.00th=[ 5211],
| 30.00th=[ 5211], 40.00th=[ 5276], 50.00th=[ 5276], 60.00th=[ 5276],
| 70.00th=[ 5276], 80.00th=[ 5276], 90.00th=[ 5342], 95.00th=[ 5407],
| 99.00th=[ 8356], 99.50th=[ 8717], 99.90th=[12125], 99.95th=[12387],
| 99.99th=[12911]
cpu : usr=0.11%, sys=1.10%, ctx=1312291, majf=0, minf=14
IO depths : 1=200.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued rwts: total=0,655360,0,655359 short=0,0,0,0 dropped=0,0,0,0
latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs):
WRITE: bw=1497KiB/s (1533kB/s), 1497KiB/s-1497KiB/s (1533kB/s-1533kB/s), io=5120MiB (5369MB), run=3502354-3502354msec
Disk stats (read/write):
nvme2n1: ios=0/1966100, sectors=0/31458056, merge=0/1310775, ticks=0/3416205, in_queue=4253444, util=97.54%
说到这里,可能用 Mac 做开发的同学会疑惑:‘我的 Mac 也是消费级 SSD,为什么跑数据库挺快的?’ 这就不得不提 macOS 那个著名的‘语义陷阱’了……”
番外篇:Mac 用户请注意,你的 fsync 可能在“撒谎”
如果你是在 MacBook Pro (M1/M2/M3) 上进行本地开发,你可能会发现本地的数据库跑起来非常轻快,甚至比服务器上还快。但这并不代表苹果的 SSD 也是“企业级”的,而是因为 macOS 在 fsync 的实现上玩了一个文字游戏。
1. API 的语义欺骗:fsync vs F_FULLFSYNC
在 Linux 标准中,fsync(fd) 的定义非常严格:必须把数据写入物理介质才算完。
但在 macOS (以及 iOS) 上,标准的 fsync 系统调用并不保证数据写入物理介质,它往往只是把数据刷入硬盘的DRAM 缓存就返回成功了。这相当于 macOS 默认替所有 SSD 开了“作弊模式”。
如果要在 macOS 上实现和 Linux fsync 等同的“物理落盘安全性”,应用必须调用一个苹果特有的 fcntl 指令:
// macOS 上真正的“物理落盘”
fcntl(fd, F_FULLFSYNC);
PostgreSQL 等数据库在 macOS 上运行时,为了性能往往需要在这两者之间做权衡。如果你强制开启 F_FULLFSYNC,你会发现普通消费级 SSD 的 Mac 性能会瞬间暴跌(虽然 M 系列芯片的控制器优化极强,掩盖了部分延迟)。
总结与建议
通过 fio 基础测试和 pgbench 的实战对比,结论已经非常明显:标称参数只是冰山一角,架构差异才是深海里的巨兽。
在普通的顺序读写测试中,AX41-NVMe 的消费级硬盘甚至能和 AX102 的企业级硬盘打得有来有回。但在涉及到数据库真实负载——即包含大量 fsync 的同步写入场景下,企业级 SSD 凭借 PLP(掉电保护)带来的物理层优势,实现了对消费级硬盘 5 倍以上 的 TPS 碾压(25k vs 5k)。
这恰恰解释了为什么很多开发者在本地开发环境(通常是高性能 NVMe)或者普通 VPS 上跑数据库时,一旦并发量上来,CPU 还没满,IOwait 却先爆表的原因。
对于正在观望 AX102 的小伙伴,我们的建议是:
- 如果你跑的是无状态应用(如 Web Server、CI/CD Runner、计算节点):普通的 AX 系列甚至 Cloud 实例完全足够,你不需要为 Datacenter SSD 和 ECC 内存支付溢价。
- 如果你跑的是有状态应用(尤其是 PostgreSQL、MySQL、Redis 等数据库):为了 Datacenter NVMe 每月多出的几十欧,买到的不仅仅是更大的容量,更是 IO 延迟的确定性(Determinism)和数据落盘的安全性。
毕竟,在生产环境中,“稳定”本身就是最大的性能指标。希望这篇评测能帮你少走弯路,把钱花在刀刃上。
Happy Hacking!
哦对了,如果你看完本文后对 Hetzner 的机器感兴趣,可以尝试使用我们的链接来注册 Hetzner 体验: https://hetzner.cloud/?ref=6moYBzkpMb9s
通过我们的链接注册的话你可以在注册成功后直接获得 20EUR 的可用额度,我们也可以获得 10EUR 的奖励,这样也可以支持我们的产品发展。