上一篇 下一篇 分享链接 返回 返回顶部

香港服务器 ZFS 到底要不要上 SLOG / L2ARC?——数据库与文件服务的选型、部署与完整对比评测

发布人:Minchunlin 发布时间:2025-09-29 10:24 阅读量:172


凌晨 1:40,香港将军澳机房的客户抱怨“数据库提交卡顿、SMB 拷贝忽快忽慢”,我们准备把一台数据库节点和一台文件服务节点从 ext4/LVM 迁到 ZFS,顺带验证两个老生常谈的问题:

  • ZFS 到底要不要配 SLOG(分离 ZIL 日志设备)?
  • L2ARC(读缓存)值不值得上?

我不想拍脑袋,所以直接拉了两台候选服务器做对比测试,把能想到的典型场景都跑了一遍:本地数据库 OLTP、NFS 强制同步小文件写、SMB 海量小文件热读。数据不说谎。

测试环境与硬件配置(香港节点,机柜同列)

OS 我仍然选 CentOS 7.9(客户生产环境一致),ZFS 采用 OpenZFS 2.1.x(kmod) 分支,内核稳定、驱动成熟。

节点 A(数据库型候选)

  • 机型:Dell PowerEdge R650xs
  • CPU:2 × Intel Xeon Silver 4314(16C/32T ×2)
  • 内存:256 GB DDR4-2933
  • 系统盘:2 × SATA SSD(RAID1,系统/日志)
  • 数据盘池(Pool-DB):6 × 3.84 TB 企业级 SATA SSD(三星 PM883),3 组镜像 vdev(RAID10 类)
  • SLOG(候选):2 × Intel Optane P4801X 100 GB(镜像)
  • L2ARC(候选):1 × Samsung PM9A3 1.92 TB NVMe
  • 网卡:Mellanox ConnectX-4 Lx 25GbE × 2
  • 用途:PostgreSQL、MySQL OLTP 压测;NFS 同步写验证

节点 B(文件服务型候选)

  • 机型:Supermicro 2U(H12 系列)
  • CPU:AMD EPYC 7302P(16C/32T)
  • 内存:128 GB DDR4-3200
  • 系统盘:2 × SATA SSD(RAID1)
  • 数据盘池(Pool-FS):12 × 16 TB 7200 RPM SAS HDD,2 个 raidz2 vdev(6D+2P)
  • Special vdev(元数据/小文件):2 × Samsung PM983 960 GB NVMe(镜像)
  • SLOG(候选):2 × Intel Optane P1600X 118 GB(镜像)
  • L2ARC(候选):1 × Samsung PM9A3 3.84 TB NVMe
  • 网卡:Mellanox ConnectX-4 Lx 25GbE × 2
  • 用途:SMB/NFS 文件服务;小文件/大文件混合读写

注 1:所有 HBA 设置为 IT 模式直通;ashift=12(4K 扇区对齐)。

注 2:测试 VLAN 与生产隔离,交换机端口统一 25GbE,MTU 9000(Jumbo Frame)。

ZFS 关键配置与创建命令

软件安装(CentOS 7)

# 1) 安装仓库与内核模块(生产请固定版本)
yum install -y epel-release
yum install -y zfs

# 2) 加载模块并开机自启动
modprobe zfs
echo zfs >> /etc/modules-load.d/zfs.conf

创建数据库池(Pool-DB)

# 3 组镜像 vdev(相当于 RAID10),适合 OLTP 的低延迟与并发
zpool create -f Pool-DB \
  mirror /dev/disk/by-id/ssd1 /dev/disk/by-id/ssd2 \
  mirror /dev/disk/by-id/ssd3 /dev/disk/by-id/ssd4 \
  mirror /dev/disk/by-id/ssd5 /dev/disk/by-id/ssd6 \
  -o ashift=12 -o autoreplace=on -o autotrim=on

# 数据集参数(数据库)
zfs create -o recordsize=16K -o atime=off -o compression=lz4 \
  -o primarycache=all -o logbias=latency Pool-DB/pgdata

创建文件服务池(Pool-FS)

# 2 个 raidz2 vdev(6+2),容量与容错兼顾;special vdev 存放元数据/小文件
zpool create -f Pool-FS \
  raidz2 /dev/disk/by-id/hdd1 ... /dev/disk/by-id/hdd6 \
  raidz2 /dev/disk/by-id/hdd7 ... /dev/disk/by-id/hdd12 \
  special mirror /dev/disk/by-id/nvme_meta1 /dev/disk/by-id/nvme_meta2 \
  -o ashift=12 -o autoreplace=on

# 文件服务通用数据集
zfs create -o recordsize=1M -o atime=off -o compression=lz4 Pool-FS/share

# 针对小文件的目录可单独定义(覆盖 recordsize 与 primarycache)
zfs create -o recordsize=16K -o primarycache=metadata Pool-FS/smallfiles

动态加挂 SLOG / L2ARC

# SLOG(强烈建议镜像 & 有断电保护的低延迟介质/Optane)
zpool add Pool-DB log mirror /dev/disk/by-id/optane1 /dev/disk/by-id/optane2
zpool add Pool-FS log mirror /dev/disk/by-id/p1600x1 /dev/disk/by-id/p1600x2

# L2ARC(读缓存,容量可大于内存;2.0+ 支持持久)
zpool add Pool-DB cache /dev/disk/by-id/pm9a3_1
zpool add Pool-FS cache /dev/disk/by-id/pm9a3_2

关键点:

  • SLOG 只加速“同步写”(sync write),异步写几乎没收益;没有断电保护(PLP)的消费级 NVMe 做 SLOG 风险极高。
  • L2ARC 只缓存读;是否有用取决于“热数据是否稳定重复命中、且超出内存 ARC”。

压测方法与脚本片段

1)数据库 OLTP(PostgreSQL)

# 初始化(数据量 > 内存,确保需要二级缓存/L2ARC 才可能有效)
sudo -u postgres pgbench -i -s 20000   # 约 ~320GB 数据集

# 标准 5 分钟压测,128 并发,开启 fsync(默认)
pgbench -c 128 -T 300 -P 10 -M prepared -S   # 纯读
pgbench -c 128 -T 300 -P 10                  # 读写混合

# ZFS 数据集建议
zfs set recordsize=16K Pool-DB/pgdata
zfs set logbias=latency Pool-DB/pgdata

2)NFS 同步写(模拟 VM/数据库/严格一致性)

# 服务器侧(ZFS)
zfs set sync=always Pool-FS/share   # 强制同步写,以暴露 SLOG 的价值

# 客户端侧(fio 小文件同步写)
fio --name=sync-small --directory=/mnt/nfs \
    --numjobs=8 --iodepth=1 \
    --rw=randwrite --bs=8k --size=20G \
    --ioengine=libaio --direct=1 --fsync=1 --runtime=180 --time_based

3)SMB 海量小文件热读

# 先用 rsync 准备 2TB、4~128KB 混合小文件(Zipf 分布)
# 再用 fio/自写脚本做多进程随机读 3~5 分钟,观察 ARC/L2ARC 命中率

测试矩阵

方案编号 池/介质 SLOG L2ARC 备注
A1 Pool-DB(SSD 镜像) 基线
A2 Pool-DB(SSD 镜像) Optane ×2 镜像 仅 SLOG
A3 Pool-DB(SSD 镜像) NVMe 1.92TB 仅 L2ARC
A4 Pool-DB(SSD 镜像) Optane ×2 镜像 NVMe 1.92TB SLOG+L2ARC
F1 Pool-FS(HDD raidz2+special) 基线
F2 同 F1 Optane/P1600X ×2 镜像 仅 SLOG
F3 同 F1 NVMe 3.84TB 仅 L2ARC
F4 同 F1 Optane/P1600X ×2 镜像 NVMe 3.84TB SLOG+L2ARC

结果一:PostgreSQL OLTP(读写混合)

  • 参数:128 并发、300 秒、fsync=on、数据集 ~320GB(超出 ARC)。
  • ZFS:recordsize=16K, atime=off, compression=lz4, logbias=latency。

TPS 与延迟(节点 A)

方案 TPS(avg) p95 延迟(ms) p99 延迟(ms) ARC 命中 L2ARC 命中
A1 基线 22,480 8.7 9.8 78% 0%
A2 SLOG 25,920 7.2 7.9 79% 0%
A3 L2ARC 27,780 6.1 6.8 65% 27%
A4 SLOG+L2ARC 29,430 5.4 6.1 66% 29%

解读:

  • SSD 池上 SLOG 仍有收益(~+15% TPS),原因是 OLTP 中存在大量 fsync/同步提交。
  • L2ARC 在“稳定热数据”下带来额外提升(~+24%),关键在工作集复用度;“冷热剧烈波动”时收益会收敛。
  • SLOG+L2ARC 叠加效果最好,但前提是 SLOG 用低时延且带 PLP 的介质(如 Optane)。

结果二:NFS 强制同步写(小块,8KB,fsync=1)

  • 参数:8 任务、iodepth=1、8KB 随机写、sync=always。
  • 原因:这类场景最能真实暴露 ZIL/SLOG 的价值(VM、数据库、严苛一致性)。

吞吐与延迟(节点 B)

方案 吞吐(ops/s) 平均延迟(ms) p99 延迟(ms)
F1 基线(无 SLOG) 1,820 41.3 82.7
F2 仅 SLOG 12,060 6.2 12.4
F3 仅 L2ARC 1,840 40.9 82.1
F4 SLOG+L2ARC 12,140 6.1 12.1

解读:

  • HDD 池若无 SLOG,强制同步写几乎“废了”;上了 SLOG 直接 提升 6.6×。
  • L2ARC 对写无帮助(它是读缓存)。文件服务若有大量同步写(NFS、某些 SMB/AFP 场景、虚拟化后端),SLOG 是必须品。

结果三:SMB 海量小文件热读(4~128KB)

  • 参数:2TB 数据集,小文件占比高,Zipf 分布,25GbE,读 5 分钟取稳态。
  • ZFS:Pool-FS 启用 special vdev(元数据/小文件),分别对比是否再加 L2ARC。

读性能(节点 B)

方案 吞吐(MB/s) p95 延迟(ms) p99 延迟(ms) ARC 命中 L2ARC 命中
F1 基线(有 special,无 L2ARC) 450 31 45 32% 0%
F3 仅 L2ARC(3.84TB) 920 13 18 38% 43%
F4 SLOG+L2ARC 918 13 18 38% 42%

解读:

  • special vdev 已强烈改善元数据/小文件路径;
  • 若热数据远大于内存,再叠加 L2ARC(容量远超内存),读性能继续翻倍;
  • SMB 热读几乎不涉及同步写,故 SLOG 基本不影响读性能。

什么时候该上 SLOG?

必须上:

  • HDD 为主的池,且 存在同步写(NFS sync=always、VM 存储、数据库日志落盘、Mac SMB 严格一致选项)。
  • SSD 池但对 提交延迟极敏感(数据库 commit latency、消息队列)。

谨慎上:

  • 业务几乎全是异步写(流式落盘、大文件顺序写),SLOG 价值有限。

选型要点:

  • 介质必须有 PLP(断电保护)、低时延、高耐久;Optane 类最佳。

镜像 SLOG 是底线(否则单点风险)。

  • SLOG 容量不必很大(常见 16~64GB 足够,视 TXG/并发而定),重在时延与稳定性。

什么时候该上 L2ARC?

收益大:

  • 稳定且可复用的热数据,规模>内存,且业务是 读为主(构建/编译缓存、素材库、代码仓库、热媒体片段、只读数据库切片)。
  • 已经把内存加到合适规模,仍存在大量重复读取且命中不足。

收益小:

  • 热数据剧烈波动、不可复用;或业务主要是写;或已经受 网络瓶颈 限制。

选型要点:

  • L2ARC 容量可以 远大于内存;OpenZFS 2.0+ 支持 持久化 L2ARC,重启后不需要长时间预热。
  • special vdev + L2ARC 协同:special vdev 解决“寻道/元数据”,L2ARC 解决“大量热读”——二者叠加在文件服务上体验极好。

数据库与文件服务的选型建议(香港机房实战版)

数据库(PostgreSQL/MySQL,OLTP 为主)

磁盘布局:镜像 vdev(RAID10 类)优先于 raidz,追求低时延与并发。

SLOG:上(镜像),尤其对 fsync/同步提交敏感的业务。

L2ARC:可选(看热数据复用度与预算,优先加内存)。

参数建议:

  • recordsize=16K(与数据库页更贴近),atime=off,compression=lz4,logbias=latency。
  • HBA IT 模式直通,ashift=12,autotrim=on(SSD)。
  • PostgreSQL 侧 effective_io_concurrency、shared_buffers 与检查点参数需配合调优。

推荐最小配置(我们这次用的稳定档):

  • 6 × 企业级 SSD 组成 3 组镜像 vdev;
  • 2 × Optane SLOG 镜像;
  • 内存 ≥ 128GB;
  • L2ARC 1~2TB 视预算/命中率加。

文件服务(SMB/NFS,混合大小文件)

磁盘布局:大容量优先可选 raidz2;若小文件/并发元数据压力大,加 special vdev(镜像 NVMe)。

SLOG:

  • NFS(sync=always)/虚拟化后端 → 必须上;
  • 纯 SMB 非严格同步写 → 可不必。

L2ARC:

  • 热数据远大于内存、且复用度高 → 强烈建议(容量 2~4TB 起步)。

参数建议:

  • 大文件共享:recordsize=1M;小文件目录:recordsize=16K、primarycache=metadata。
  • atime=off,compression=lz4;special vdev 镜像、启用 autotrim(NVMe)。

关键调优片段(仅列要点,生产需结合实况评估)

# 减少 ARC 抖动(示例值,按内存调)
echo 107374182400 > /sys/module/zfs/parameters/zfs_arc_max   # ~100GB
echo  85899345920 > /sys/module/zfs/parameters/zfs_arc_min   # ~80GB

# L2ARC 预取与写速率(按介质与业务微调)
echo 1   > /sys/module/zfs/parameters/l2arc_noprefetch
echo 64  > /sys/module/zfs/parameters/l2arc_write_max_mb

# ZIL 提交节奏(谨慎调整)
echo 5   > /sys/module/zfs/parameters/zfs_txg_timeout

踩坑与现场解决

SLOG 用了“看上去很快”的消费 NVMe:

  • 无 PLP,断电后 数据风险;而且写放大严重,寿命掉得飞快。
  • 解决:换 Optane / 企业盘,并做镜像。

忘了设置 ashift=12:

  • HDD/SSD 4K 物理扇区在 ashift=9 下会引发对齐问题,随机写性能雪崩。重建后性能恢复。

L2ARC 太小且热数据剧烈波动:

  • 频繁替换导致命中率不升反降,还占用内存做元数据。
  • 解决:加大 L2ARC 容量(≥ 2TB),并限制 l2arc_write_max_mb。

special vdev 没做镜像:

  • 元数据丢失=池子瘫痪的概率陡增。
  • 解决:special vdev 必须镜像。

以为 SLOG 能提速异步写:

  • 事实并非如此;异步写依然受到底层盘与 TXG 刷新的约束。

NFS/SMB 没开 Jumbo Frame:

  • CPU 抬升、延迟恶化。
  • 解决:交换机/主机两端统一 MTU=9000,并验证路径无碎片。

成本 vs. 性能的现实平衡(香港场景)

香港机房带宽/机柜成本高,但网络路径好、时延稳;选对少量关键部件(Optane SLOG、合适容量 L2ARC、special vdev),往往比“堆很多通用盘”更划算。

我的经验是:数据库优先“低时延 + 稳定提交”(镜像 vdev + SLOG);文件服务优先“元数据与热读”(special vdev + L2ARC)。两类业务分池,互不拖累,是 TCO 最优解。

  • 数据库 OLTP:Mirror vdev + SLOG(镜像/Optane) 必上;L2ARC 视热数据而定(先把内存加够)。
  • 文件服务:raidz2 + special vdev(镜像 NVMe) 起步;NFS 有同步写就上 SLOG;稳定热读就上 L2ARC。
  • 千万别用消费级无 PLP 的 NVMe 做 SLOG;special vdev 和 SLOG 都要镜像。

把最后一轮 pgbench 停下来的时候,数据库的 p99 延迟稳定到 6ms 左右;NFS 同步写吞吐恢复到了 10GbE 的线速,SMB 热读也能稳稳压在 900MB/s 附近。客户那边的工单也终于安静了。我把两台机器的风扇档位调回自动,灯一灭,机房的风好像也温柔了些。
那一刻我知道——不是 ZFS 多神,而是我们在对的场景里,给了它对的刀。

附录:常用命令清单(可直接套用)

# 查看池状态与写日志/缓存
zpool status
zpool iostat -v 1
arcstat.py 1
arc_summary.py

# 数据集属性回顾
zfs get recordsize,compression,atime,logbias,primarycache Pool-DB/pgdata
zfs get recordsize,primarycache Pool-FS/smallfiles

# 安全移除/更换设备
zpool offline Pool-DB /dev/disk/by-id/ssd3
zpool replace Pool-DB /dev/disk/by-id/ssd3 /dev/disk/by-id/ssd3_new
zpool remove Pool-DB /dev/disk/by-id/pm9a3_1   # 移除 L2ARC(不影响数据)

如果你的场景和我上述两个不完全一致,按这篇文章的思路,把业务 I/O 模型先分类,再决定 SLOG / L2ARC / special vdev 的取舍和大小,就能少走很多弯路。

目录结构
全文