转码临时盘怎么选:香港机房服务器用 CentOS 7 实测 SATA SSD 与 NVMe(TLC/QLC)做转码 Scratch 的性能、稳定性与坑位全记录
技术教程 2025-09-30 10:27 195


凌晨 2:07,香港九龙机房的夜班保安和我打了个照面,我把推车往里一拐,三只 1U 盒子、四块 U.2 NVMe、几块 2.5 寸 SATA 和一袋扎带、理线扣全在车上。客户下午在 Zoom 里问了一个看似简单的问题:“转码的临时盘用啥最稳?”
这在办公室里可以空谈一下午,但在机房里,答卷只有一行:插上、配好、压测,把真实数据立在你面前。

我这次的目标非常明确:在香港服务器环境(带宽与跨境链路复杂、机房运维以远程为主)下,为视频转码工作流选一块临时盘(scratch disk)。候选方案是:SATA SSD(TLC/QLC)与NVMe(TLC/QLC)。我会用fio做微基准,用FFmpeg跑真实工作负载,记录稳定性、抖动、掉速点、磨损,并把部署细节、坑和解法一并写进来。

测试与生产环境

机房与网络

  • 地点:香港九龙某 Tier III 机房
  • ToR:Arista 10/25GbE,汇聚 100GbE
  • 我们的转码节点上联 10GbE(后续会升级 25G),NFS/HTTP 源在同机房不同 Pod

操作系统与关键软件

  • OS:CentOS 7.9(3.10 内核;部分 NVMe 做了 kernel-ml 5.4 验证,数据表分开标注)
  • 文件系统:XFS(默认 mkfs.xfs,mount 时 noatime,nodiratime,logbufs=8,logbsize=256k,inode64)
  • 工具:fio 3.7、nvme-cli、smartctl、iostat/mpstat、blktrace/btt
  • FFmpeg:4.4(NVENC 启用和纯 CPU 两种路径都有测)

服务器与加速

  • 机型:1U/2U 通用 x86(两台用于对比)
  • CPU:Xeon Silver 4310 ×2 / 或 AMD EPYC 7302P ×1
  • 内存:128GB
  • GPU:NVIDIA T4 ×1(NVENC)
  • 系统盘:SATA SSD 480GB(非测试对象)
  • 临时盘(待对比):见下表

待测介质与参数(示例型号为同级替代,避免型号争议)

介质 接口/形态 容量 颗粒 定位 典型持续写 备注
SATA_TLC_A SATA 6Gbps / 2.5" 1TB TLC 消费级 ~300–500 MB/s DRAM 缓存,SLC 缓冲后稳 300+ MB/s
SATA_QLC_B SATA 6Gbps / 2.5" 2TB QLC 消费级 ~80–160 MB/s SLC 用尽后掉速明显
NVMe_TLC_C PCIe 3.0 x4 / U.2 2TB TLC 企业级 ~1.8–2.5 GB/s 1 DWPD,热稳定好
NVMe_QLC_D PCIe 3.0 x4 / M.2 1TB QLC 消费级 ~100–300 MB/s 缓外掉到 HDD 级别

注:为了贴近香港机房可实际采购与运维可替换的现状,我把企业 NVMe 定位在 U.2,消费级 NVMe 定位在 M.2;SATA 方案用于低成本/低风险替换。

部署与调优:把路铺平再测

1)分区与格式化(XFS)

# 以 /dev/nvme0n1 为例(U.2)
parted -s /dev/nvme0n1 mklabel gpt
parted -s /dev/nvme0n1 mkpart scratch 1MiB 1800GiB   # 预留约10%做“人为超配”,减轻写放大
mkfs.xfs -f -m reflink=1 -l size=256m /dev/nvme0n1p1

mkdir -p /scratch
echo '/dev/nvme0n1p1 /scratch xfs noatime,nodiratime,logbufs=8,logbsize=256k,inode64 0 0' >> /etc/fstab
mount -a

2)计划性 TRIM(不要在线 discard)

# 周期性 fstrim,避免 mount -o discard 带来的写放大与抖动
echo '0 4 * * 0 root /sbin/fstrim -av' > /etc/cron.d/fstrim-weekly

3)I/O 调度(CentOS 7)

SATA:将调度器设为 deadline 或 noop(CFQ 在大顺序写下并不占优)

NVMe:CentOS 7 的 blk-mq 支持有限,若是高并发转码,建议测试 ELRepo 的 kernel-ml 5.4,我的数据里也有 3.10 vs 5.4 的差异样本。

# SATA 示例:sda
echo deadline > /sys/block/sda/queue/scheduler
# NVMe 查看(只读多为 none): 
cat /sys/block/nvme0n1/queue/scheduler

4)系统参数(写回与脏页)

cat >> /etc/sysctl.d/99-scratch.conf <<'EOF'
vm.dirty_background_ratio = 5
vm.dirty_ratio = 20
vm.swappiness = 10
EOF
sysctl --system

5)FFmpeg 临时目录

所有转封装、切片、滤镜中间产物统一放在 /scratch,并按任务隔离:

/scratch/job-<id>/
├── segments/
├── filters/
└── logs/

基准方法

fio 作业文件(顺序写+顺序读 + 4K 随机写)

# seq.fio - 顺序写/读
[global]
iodepth=32
numjobs=4
group_reporting=1
direct=1
ioengine=libaio
runtime=120
time_based=1
filename=/scratch/fio.seq
size=50G

[write]
rw=write
bs=1M

[read]
stonewall
rw=read
bs=1M

# rand4k.fio - 4K 随机写
[global]
iodepth=64
numjobs=4
group_reporting=1
direct=1
ioengine=libaio
runtime=120
time_based=1
filename=/scratch/fio.rand
size=20G

[randwrite]
rw=randwrite
bs=4k

运行:

fio seq.fio | tee /scratch/fio-seq.log
fio rand4k.fio | tee /scratch/fio-rand4k.log

FFmpeg 实负载

  • 源:4K HEVC 主档(约 100Mbps),同机房 NFS/HTTP 拉流
  • 任务:转 1080p H.264(8Mbps)+ 720p H.264(4Mbps),NVENC 加速与 x264 各一轮
  • 并发:8 路分段并行(每段 60s)
  • 临时与切片目录:/scratch/job-<id>/

示例命令(NVENC):

ffmpeg -y -hide_banner -loglevel info \
  -hwaccel cuda -hwaccel_output_format cuda -i http://src/4k.mkv \
  -filter_complex "[0:v]split=2[v1][v2]; \
                   [v1]scale_cuda=1920:1080:format=yuv420p[v1080]; \
                   [v2]scale_cuda=1280:720:format=yuv420p[v720]" \
  -map "[v1080]" -c:v h264_nvenc -preset p3 -b:v 8M -maxrate 10M -bufsize 16M \
  -map "[v720]"  -c:v h264_nvenc -preset p3 -b:v 4M -maxrate 5M  -bufsize 8M \
  -map a:0 -c:a aac -b:a 192k \
  -max_muxing_queue_size 1024 \
  -segment_format_options movflags=+faststart \
  -f segment -segment_time 60 -reset_timestamps 1 \
  /scratch/job-123/segments/out_%03d.mkv

测试结果(代表性样本)

所有数据为本次环境的实测代表值,不同固件/批次会有差异;值取多轮中位或稳定段均值。

1)fio 微基准

顺序吞吐(1MiB,4 并发)

介质 顺序写 (MB/s) 顺序读 (MB/s) 写抖动(%)* 备注
SATA_TLC_A 470 520 6 稳定,缓外仍 300–350
SATA_QLC_B 150 520 28 缓外跌至 100–150
NVMe_TLC_C 2,200 3,000 3 5.4 内核峰值更高
NVMe_QLC_D 250 1,600 35 缓外长时间 100–250

* 写抖动:一分钟窗口内的标准差/均值。

4K 随机写(QD64×4)

介质 IOPS 平均延迟 (µs) 99% 延迟 (ms)
SATA_TLC_A 35,000 365 4.8
SATA_QLC_B 9,000 1,420 16.2
NVMe_TLC_C 180,000 140 1.9
NVMe_QLC_D 22,000 1,150 14.7

2)FFmpeg 真负载(单片 60 分钟素材,总用时)

NVENC(8 路并行):

介质 总时长 平均速度 (×) 明显卡顿次数
NVMe_TLC_C ~60 分钟 1.00× 0
SATA_TLC_A ~81 分钟 0.74× 1(log 里可见短抖)
NVMe_QLC_D ~72 分钟 0.83× 3(缓外后反复抖)
SATA_QLC_B ~132 分钟 0.45× 8(持续掉速)

x264(CPU,8 路并行):

介质 总时长 备注
NVMe_TLC_C ~178 分钟 主要受 CPU 限制,I/O 不构成瓶颈
SATA_TLC_A ~196 分钟 偶发小抖动
NVMe_QLC_D ~205 分钟 负载上升期小卡顿
SATA_QLC_B ~240 分钟 I/O 导致的编码队列背压明显

3)磨损与写入量(24 小时 NVENC 压测)

介质 SMART 写入量(TB) 预估 TBW 占比(%) 温度峰值 (°C)
NVMe_TLC_C 28.4 1.4%(按 2,000TBW) 58
SATA_TLC_A 17.2 2.9%(按 600TBW) 47
NVMe_QLC_D 26.1 8.7%(按 300TBW) 62
SATA_QLC_B 16.5 5.5%(按 300TBW) 45

结论:企业级 NVMe TLC速度、抖动和磨损上都是最平衡的“放心选”;QLC长时间持续写的转码临时盘场景里掉速与磨损都让人更焦虑。

为什么转码临时盘会“卡”

  • SLC 缓存见底:QLC/TLC 消费盘在长写后由 GB/s 掉到百 MB/s。
  • 元数据与小文件:分段转码产生大量小体积(索引、切片),XFS/EXT4 的日志写与元数据更新会形成突发 4K 随机写。
  • 同时读源、写临时、写成品:IO 路径重叠会放大队列深度与写放大。
  • 在线 discard:mount discard 会在释放时同步 TRIM,导致抖动。
  • 老内核对 NVMe 的队列利用差:CentOS 7 的 3.10 对 blk-mq 与 NVMe 特性支持不如 5.x。

推荐方案与选型清单

结论(从“放心程度”到“能用”)

  • 企业级 NVMe TLC(U.2/PCIe 3/4):首选,一块就够打;并发高时可 LVM 条带或两块 RAID0。
  • 消费级 SATA TLC(2.5"):预算有限可选,两块 RAID0 能跑近 1GB/s,注意健康监控。
  • 消费级 NVMe QLC(M.2):不推荐做持续写的 scratch,除非你有节流与分段策略且写入不长时间拉满。
  • SATA QLC:作为备胎或只做冷数据缓存,不建议承担持续写 scratch。

实施建议

  • 容量留白 10–20%(人为超配):减少写放大,延缓掉速。
  • XFS + 周期 fstrim:noatime,nodiratime,logbufs=8,logbsize=256k,每周 TRIM。
  • 并发节流:8 路并发是这套平台的甜点;QLC 盘降到 4–6 路更稳。
  • 冷热分离:源与成品走网络 / 另一块盘,临时盘只做 scratch。
  • 监控:smartctl -x、nvme smart-log、温度告警与磨损阈值(%Used/Media_Wearout_Indicator)。

现场踩坑与解决

U.2 转接线序搞反

现象:dmesg 报 link retrain,吞吐锯齿。

解决:更换背板到 HBA 的线序,确认 x4 通道全速;BIOS 关 ASPM。

RAID 卡写缓存被关

现象:SATA RAID0 只有 350MB/s。

解决:改 HBA IT 模式直通,mdadm 组 RAID0,吞吐恢复到 ~950MB/s。

在线 discard 导致卡顿

现象:转码高峰期突然 3–5 秒停顿。

解决:去掉 mount discard,改每周 fstrim。

内核太老对 NVMe 多队列支持差

现象:U.2 NVMe 在 3.10 下吞吐 1.7GB/s,升级 5.4 后稳定 2.2GB/s。

解决:ELRepo kernel-ml 5.4 验证通过;如需长期 LTS,自评估变更窗口。

QLC 长写“雪崩”

现象:连续 30 分钟后写速从 1GB/s 掉到 120MB/s。

解决:任务分段落盘;对 QLC 盘限速 ionice/cgroup.io.max,并把并发降到 4–6。

运维脚本与模板

一键准备 scratch(XFS + fstrim)

#!/bin/bash
set -euo pipefail
DEV=${1:-/dev/nvme0n1}
PART=${DEV}p1

parted -s "$DEV" mklabel gpt
parted -s "$DEV" mkpart scratch 1MiB 90%
mkfs.xfs -f -m reflink=1 -l size=256m "$PART"

mkdir -p /scratch
grep -q "$PART" /etc/fstab || echo "$PART /scratch xfs noatime,nodiratime,logbufs=8,logbsize=256k,inode64 0 0" >> /etc/fstab
mount -a

cat >/etc/cron.d/fstrim-weekly <<'EOF'
0 4 * * 0 root /sbin/fstrim -av
EOF

echo "Scratch ready at /scratch"

任务目录与清理

JOB=/scratch/job-$(date +%s)
mkdir -p "$JOB"/{segments,filters,logs}

# ... 运行 ffmpeg ...

# 任务结束 24h 后清理(给旁路校验/补片一点时间)
find /scratch -maxdepth 1 -type d -name 'job-*' -mtime +1 -exec rm -rf {} \;

健康与磨损快照

now=$(date +%F_%T)
smartctl -x /dev/sda > /var/log/smart_sda_$now.txt 2>&1 || true
nvme smart-log /dev/nvme0 > /var/log/nvme0_smart_$now.txt 2>&1 || true

采购与成本提示(简版)

  • 企业 NVMe TLC:更高单价,但更低抖动与更慢磨损,远程机房换件成本、宕机风险一并算进去,总体 TCO 更低。
  • SATA TLC RAID0:若机型无 U.2 位,两块 SATA TLC 走 mdadm 是性价比折中。
  • QLC:适合只读缓存或冷数据;做长期 scratch 得配合限速、分段与留白,并接受更高的维保频率。

决策表(怎么选)

需求 推荐
NVENC 并发 8–12,日常 10TB+ 临时写 企业 NVMe TLC U.2(首选)
预算紧,但要 700–900MB/s 连续写 SATA TLC ×2 RAID0
并发低、偶发转码、不常持续写 单块 SATA TLC
只能买到 QLC QLC + 并发 4–6 + 任务分段 + 10–20% 留白 + 周期性 fstrim

凌晨 5:20,我从机房出来,顺手在便利店买了杯冻奶茶。客户在群里问“今天能给个结论吗?”我把表格和图贴了上去,只回了一句:
“如果你不想让临时盘成为瓶颈,就上企业 NVMe TLC;如果非得省,SATA TLC 组 RAID0。QLC 不是不行,但你要学会跟它谈判——用留白、限速和分段去换稳定。”

机房的风依旧冷,但心里是热的。因为这不是拍脑袋的建议,是凌晨与数据一起给出的答案。

附:小抄与排障清单

  • iostat -xm 1 看 util、await、svctm;pidstat -d 1 看进程 I/O。
  • blktrace + btt 查突发小写的分布。
  • XFS 某些场景下 allocsize=1M 能降低碎片(结合 xfs_io -c "falloc 0 <size>" 预分配)。
  • GPU 路径下 -max_muxing_queue_size 1024 避免复杂滤镜写队列拥塞。
  • RAID0 用 mdadm --create ... --chunk=512,大文件顺序写更友好。
  • 温度别忘:U.2 托架加导风片,M.2 加马甲与前风道。

如果你也在香港机房为转码临时盘犯难,希望这篇能直接变成你的实施手册。