Bcachefs 完全指南 / 第 9 章:性能调优
第 9 章:性能调优
让每一块存储设备都发挥极致性能
9.1 性能调优概述
9.1.1 性能影响因素
Bcachefs 性能影响因素:
┌─────────────────────────────────────────────────┐
│ 应用层 │
│ I/O 模式 (顺序/随机)、块大小、并发度 │
├─────────────────────────────────────────────────┤
│ 文件系统层 │
│ CoW 开销、B-Tree 缓存、Journal、压缩 │
├─────────────────────────────────────────────────┤
│ 内核层 │
│ I/O 调度器、页缓存、预读策略 │
├─────────────────────────────────────────────────┤
│ 硬件层 │
│ 存储设备类型、CPU、内存、总线带宽 │
└─────────────────────────────────────────────────┘
9.1.2 性能基准指标
| 指标 | 说明 | 单位 |
|---|
| IOPS | 每秒 I/O 操作数 | ops/s |
| 吞吐量 | 每秒传输数据量 | MB/s |
| 延迟 | I/O 操作耗时 | μs / ms |
| CPU 使用 | 文件系统操作 CPU 开销 | % |
9.2 挂载选项调优
9.2.1 常用性能挂载选项
# 完整的性能优化挂载
sudo mount -t bcachefs -o \
noatime,\
nodiratime,\
discard,\
compress=lz4,\
journal_flush_delay=5000 \
/dev/sdb /mnt/data
9.2.2 挂载选项详解
| 选项 | 默认值 | 推荐值 | 说明 |
|---|
noatime | off | on | 不更新访问时间,减少元数据写入 |
nodiratime | off | on | 不更新目录访问时间 |
discard | off | SSD: on | 启用 TRIM,帮助 SSD 垃圾回收 |
journal_flush_delay | 1000ms | 5000ms | 延迟日志刷新,合并小写入 |
gc_reserve_percent | 8% | 5-15% | GC 保留空间比例 |
btree_node_size | 256KB | 可调 | B-Tree 节点大小 |
readahead | 128KB | 可调 | 预读窗口大小 |
9.2.3 noatime 详解
# 默认行为 (atime):
# 每次读取文件都更新 inode 的访问时间
# 导致大量元数据写入
# 推荐: noatime
# 不更新访问时间,性能提升 10-30%
# 验证当前挂载选项
mount | grep bcachefs
# 应该包含 noatime
9.2.4 discard (TRIM) 选项
# SSD 必须启用 discard
# 帮助 SSD 控制器回收已删除数据块
# 检查 SSD TRIM 支持
sudo hdparm -I /dev/sda | grep TRIM
# 如果不支持在线 TRIM,可以定期执行
sudo fstrim /mnt/data
# 或配置 cron 每周执行
9.2.5 Journal 调优
# journal_flush_delay 控制日志刷新频率
# 较大值: 更好的合并,但崩溃时可能丢更多数据
# 较小值: 更安全,但 IOPS 更低
# 默认 1000ms,推荐生产环境 1000-5000ms
sudo mount -t bcachefs -o journal_flush_delay=3000 /dev/sdb /mnt/data
# 使用专用日志设备(NVMe)效果更好
9.3 I/O 调度器调优
9.3.1 I/O 调度器概述
Linux I/O 调度器:
┌──────────────┬─────────────────────────────────┐
│ 调度器 │ 特点 │
├──────────────┼─────────────────────────────────┤
│ none │ 直接派发,无调度 (NVMe 推荐) │
│ mq-deadline │ 延迟优先 (SSD 推荐) │
│ bfq │ 公平队列 (HDD/桌面推荐) │
│ kyber │ 双队列 (快速设备推荐) │
└──────────────┴─────────────────────────────────┘
9.3.2 配置 I/O 调度器
# 查看当前调度器
cat /sys/block/sdb/queue/scheduler
# 输出: [mq-deadline] kyber bfq none
# 设置调度器
# NVMe: none(直接派发,延迟最低)
echo "none" | sudo tee /sys/block/nvme0n1/queue/scheduler
# SATA SSD: mq-deadline
echo "mq-deadline" | sudo tee /sys/block/sda/queue/scheduler
# HDD: bfq(适合旋转磁盘)
echo "bfq" | sudo tee /sys/block/sdb/queue/scheduler
# 永久配置 (udev 规则)
cat << 'EOF' | sudo tee /etc/udev/rules.d/60-io-scheduler.rules
# NVMe
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"
# SSD
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# HDD
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"
EOF
sudo udevadm control --reload-rules
9.3.3 调度器参数调优
# mq-deadline 参数
echo 150 | sudo tee /sys/block/sda/queue/iosched/read_expire # 读超时 150ms
echo 1500 | sudo tee /sys/block/sda/queue/iosched/write_expire # 写超时 1500ms
# bfq 参数
echo 100 | sudo tee /sys/block/sdb/queue/iosched/read_expire # 读超时 100ms
# 队列深度
echo 32 | sudo tee /sys/block/sda/queue/nr_requests # SSD
echo 128 | sudo tee /sys/block/nvme0n1/queue/nr_requests # NVMe
9.4 内核参数调优
9.4.1 虚拟内存参数
# 查看当前参数
sysctl vm.dirty_ratio
sysctl vm.dirty_background_ratio
# 推荐配置
# dirty_ratio: 脏页占内存的最大百分比(触发同步写入)
sudo sysctl -w vm.dirty_ratio=10
# dirty_background_ratio: 脏页后台刷新阈值
sudo sysctl -w vm.dirty_background_ratio=5
# 脏页过期时间(厘秒)
sudo sysctl -w vm.dirty_expire_centisecs=3000
# 脏页写回间隔
sudo sysctl -w vm.dirty_writeback_centisecs=500
# 永久配置
cat << 'EOF' | sudo tee -a /etc/sysctl.d/99-bcachefs.conf
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500
EOF
sudo sysctl --system
9.4.2 文件系统缓存
# 查看当前缓存设置
cat /proc/sys/fs/inotify/max_user_watches
# 增加 inotify 监视数(大量文件时需要)
sudo sysctl -w fs.inotify.max_user_watches=524288
# VFS 缓存压力
# 默认 100,降低可以保留更多缓存
sudo sysctl -w vm.vfs_cache_pressure=50
# 永久配置
cat << 'EOF' | sudo tee -a /etc/sysctl.d/99-bcachefs.conf
fs.inotify.max_user_watches = 524288
vm.vfs_cache_pressure = 50
EOF
9.4.3 NUMA 优化
# 多 NUMA 节点系统
numactl --hardware
# 绑定 I/O 到特定 NUMA 节点
numactl --cpunodebind=0 --membind=0 mount -t bcachefs /dev/sdb /mnt/data
9.5 块设备调优
9.5.1 队列参数
# 查看设备队列参数
ls /sys/block/sdb/queue/
# 最大队列深度
cat /sys/block/nvme0n1/queue/nr_requests
# 最大扇区数
cat /sys/block/sdb/queue/max_sectors_kb
# 预读大小
cat /sys/block/sdb/queue/read_ahead_kb
9.5.2 SSD 特定优化
# 启用 SSD 优化
echo 0 | sudo tee /sys/block/sda/queue/rotational # 确保标记为非旋转
# NVMe 优化
echo 0 | sudo tee /sys/block/nvme0n1/queue/add_random # 不添加熵
echo 2 | sudo tee /sys/block/nvme0n1/queue/nomerges # 禁用合并(NVMe 本身很快)
# SATA SSD
echo 512 | sudo tee /sys/block/sda/queue/read_ahead_kb # 增加预读
echo 512 | sudo tee /sys/block/sda/queue/max_sectors_kb # 增大最大扇区
9.5.3 HDD 特定优化
# 启用预读(HDD 顺序读很重要)
echo 2048 | sudo tee /sys/block/sdb/queue/read_ahead_kb
# 启用合并
echo 1 | sudo tee /sys/block/sdb/queue/nomerges
# NCQ 队列深度
echo 31 | sudo tee /sys/block/sdb/queue/nr_requests
9.6 Bcachefs 特定调优
9.6.1 B-Tree 节点大小
# 创建时指定 B-Tree 节点大小
# 较大节点: 更少的树遍历,但更多内存
# 较小节点: 更少内存,但更多磁盘 I/O
# 推荐: 256KB (默认)
sudo bcachefs format /dev/sdb --btree_node_size=256K
# 大内存系统可使用更大节点
sudo bcachefs format /dev/sdb --btree_node_size=512K
9.6.2 Bucket 大小优化
# 小文件场景: 使用较小 bucket
sudo bcachefs format /dev/sdb --bucket_size=64K
# 大文件场景: 使用较大 bucket
sudo bcachefs format /dev/sdb --bucket_size=1M
# 查看当前 bucket 大小
sudo bcachefs show-super /dev/sdb | grep bucket
9.6.3 GC 调优
# gc_reserve_percent 控制 GC 触发阈值
# 默认 8%,意味着当空闲空间 < 8% 时触发 GC
# 增加 GC 保留空间(减少 GC 频率)
sudo mount -t bcachefs -o gc_reserve_percent=12 /dev/sdb /mnt/data
# 手动触发 GC
sudo bcachefs fs gc /mnt/data
# 锁定 GC(用于性能测试)
sudo bcachefs fs lock /mnt/data
9.7 基准测试
9.7.1 fio 测试
# 安装 fio
sudo apt install fio # Debian/Ubuntu
sudo pacman -S fio # Arch Linux
# 顺序写入测试
fio --name=seq-write \
--ioengine=libaio \
--rw=write \
--bs=1M \
--size=4G \
--numjobs=1 \
--runtime=60 \
--directory=/mnt/data/fio-test
# 顺序读取测试
fio --name=seq-read \
--ioengine=libaio \
--rw=read \
--bs=1M \
--size=4G \
--numjobs=1 \
--runtime=60 \
--directory=/mnt/data/fio-test
# 随机读写测试
fio --name=rand-rw \
--ioengine=libaio \
--rw=randrw \
--bs=4k \
--size=1G \
--numjobs=4 \
--runtime=60 \
--iodepth=32 \
--directory=/mnt/data/fio-test
# 混合测试脚本
fio --name=bcachefs-bench \
--ioengine=libaio \
--directory=/mnt/data/fio-test \
--group_reporting \
--bs=4k,64k,1M \
--rw=randread:randwrite:read:write \
--size=2G \
--numjobs=4 \
--runtime=30 \
--iodepth=16
9.7.2 dd 测试
# 顺序写入
dd if=/dev/zero of=/mnt/data/testfile bs=1M count=4096 conv=fdatasync
# 顺序读取
dd if=/mnt/data/testfile of=/dev/null bs=1M
# 块大小测试
for bs in 4k 64k 256k 1M; do
echo "=== Block size: $bs ==="
dd if=/dev/zero of=/mnt/data/testfile-$bs bs=$bs count=$((4096*1024/$(echo $bs | sed 's/k/*1024/' | sed 's/M/*1048576/'))) conv=fdatasync 2>&1 | tail -1
rm /mnt/data/testfile-$bs
done
9.7.3 iozone 测试
# 安装 iozone
sudo apt install iozone3
# 运行综合测试
iozone -a -n 512k -g 4G -i 0 -i 1 -i 2 -f /mnt/data/iozone-test -Rb /tmp/iozone-results.xls
# 参数说明:
# -a: 自动模式
# -n: 最小文件大小
# -g: 最大文件大小
# -i 0: 写/重写测试
# -i 1: 读/重读测试
# -i 2: 随机读/写测试
9.7.4 综合基准脚本
#!/bin/bash
# benchmark-bcachefs.sh
set -e
MOUNT="/mnt/data"
TEST_DIR="$MOUNT/benchmark"
RESULT_FILE="/tmp/bcachefs-benchmark-$(date +%Y%m%d).txt"
mkdir -p "$TEST_DIR"
echo "=== Bcachefs 性能基准测试 ===" | tee "$RESULT_FILE"
echo "时间: $(date)" | tee -a "$RESULT_FILE"
echo "设备: $(mount | grep $MOUNT | awk '{print $1}')" | tee -a "$RESULT_FILE"
echo "" | tee -a "$RESULT_FILE"
# 清理缓存
sync
echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
# 测试 1: 顺序写入
echo "--- 测试 1: 顺序写入 (1M block) ---" | tee -a "$RESULT_FILE"
dd if=/dev/zero of="$TEST_DIR/seq-write" bs=1M count=2048 conv=fdatasync 2>&1 | tail -1 | tee -a "$RESULT_FILE"
# 测试 2: 顺序读取
echo "--- 测试 2: 顺序读取 (1M block) ---" | tee -a "$RESULT_FILE"
echo 3 | sudo tee /proc/sys/vm/drop_caches > /dev/null
dd if="$TEST_DIR/seq-write" of=/dev/null bs=1M 2>&1 | tail -1 | tee -a "$RESULT_FILE"
# 测试 3: 随机写入 (4K)
echo "--- 测试 3: 随机写入 (4K block, fio) ---" | tee -a "$RESULT_FILE"
fio --name=rand-write \
--ioengine=libaio \
--rw=randwrite \
--bs=4k \
--size=512M \
--numjobs=1 \
--runtime=30 \
--directory="$TEST_DIR" \
--output-format=terse 2>/dev/null | awk -F';' '{print "IOPS: " $8 ", BW: " $7 " KB/s"}' | tee -a "$RESULT_FILE"
# 测试 4: 随机读取 (4K)
echo "--- 测试 4: 随机读取 (4K block, fio) ---" | tee -a "$RESULT_FILE"
fio --name=rand-read \
--ioengine=libaio \
--rw=randread \
--bs=4k \
--size=512M \
--numjobs=1 \
--runtime=30 \
--directory="$TEST_DIR" \
--output-format=terse 2>/dev/null | awk -F';' '{print "IOPS: " $8 ", BW: " $7 " KB/s"}' | tee -a "$RESULT_FILE"
# 清理
rm -rf "$TEST_DIR"
echo "" | tee -a "$RESULT_FILE"
echo "=== 测试完成 ===" | tee -a "$RESULT_FILE"
echo "结果保存到: $RESULT_FILE"
9.8 监控工具
9.8.1 iostat
# 安装 sysstat
sudo apt install sysstat
# 实时监控
iostat -x 1
# 输出说明:
# Device r/s w/s rkB/s wkB/s await %util
# sdb 1500 800 60000 32000 0.5 45.2
#
# r/s: 读 IOPS
# w/s: 写 IOPS
# await: 平均 I/O 等待时间 (ms)
# %util: 设备利用率
9.8.2 iotop
# 安装
sudo apt install iotop
# 监控进程级 I/O
sudo iotop -oP
# 输出显示每个进程的 I/O 使用情况
9.8.3 blktrace
# 安装
sudo apt install blktrace
# 跟踪块设备 I/O
sudo blktrace -d /dev/sdb -o - | blkparse -i -
# 分析 I/O 模式
sudo btt -i sdb.blktrace.0
9.8.4 perf
# 安装
sudo apt install linux-perf
# 监控文件系统相关的内核函数
sudo perf top -g
# 或记录特定事件
sudo perf record -g -a sleep 10
sudo perf report
9.8.5 Bcachefs 特定监控
# 查看 Bcachefs 内核统计
cat /proc/fs/bcachefs/*/internal/*
# 查看挂载选项
cat /proc/fs/bcachefs/*/options
# 内核日志
dmesg | grep bcachefs
9.9 性能问题排查
9.9.1 高延迟
# 检查设备利用率
iostat -x 1
# 如果 %util > 90%,设备可能是瓶颈
# 检查 I/O 调度器
cat /sys/block/sdb/queue/scheduler
# 检查 B-Tree 缓存命中
# 如果缓存命中率低,可能需要更多内存
free -h
9.9.2 低 IOPS
# 检查队列深度
cat /sys/block/sdb/queue/nr_requests
# 检查 I/O 调度器
# none/mq-deadline 通常 IOPS 更高
# 检查是否有 GC 在运行
dmesg | grep -i "gc\|garbage"
9.9.3 低吞吐量
# 检查块大小
# 大块顺序 I/O 吞吐量更高
# 检查是否启用了压缩
# 压缩可能成为瓶颈
# 检查多设备是否均匀
iostat -x 1
# 观察各设备的 wkB/s 是否均衡
9.9.4 CPU 瓶颈
# 检查 CPU 使用
top
# 观察 iowait 和系统 CPU 使用率
# 如果 CPU 成为瓶颈:
# 1. 降低压缩级别
# 2. 切换到 lz4
# 3. 关闭不必要的校验和
9.10 工作负载特定优化
9.10.1 数据库工作负载
# 数据库特点: 随机小块 I/O,低延迟要求
# 推荐配置:
# - 挂载选项: noatime, journal_flush_delay=1000
# - I/O 调度器: none (NVMe) 或 mq-deadline (SSD)
# - 压缩: lz4 或 none
# - 块大小: 4K (InnoDB 默认页大小)
sudo mount -t bcachefs -o \
noatime,\
compress=lz4,\
journal_flush_delay=1000 \
/dev/nvme0n1 /var/lib/mysql
9.10.2 文件服务器
# 文件服务器特点: 混合 I/O,大块顺序读写
# 推荐配置:
# - 挂载选项: noatime, compress=zstd
# - I/O 调度器: bfq (HDD) 或 mq-deadline (SSD)
# - 预读: 较大值 (1024KB+)
# - 压缩: zstd (节省空间)
sudo mount -t bcachefs -o \
noatime,\
compress=zstd \
/dev/sdb:/dev/sdc /mnt/fileserver
# 增加预读
echo 2048 | sudo tee /sys/block/sdb/queue/read_ahead_kb
9.10.3 开发工作站
# 开发特点: 频繁小文件操作,编译时大量 I/O
# 推荐配置:
# - 挂载选项: noatime, compress=zstd
# - 快照: 启用
# - 预读: 中等 (256KB)
sudo mount -t bcachefs -o \
noatime,\
compress=zstd \
/dev/nvme0n1 /home
9.11 本章小结
| 优化领域 | 关键参数 | 影响 |
|---|
| 挂载选项 | noatime, discard | 减少元数据写入 |
| I/O 调度器 | none/mq-deadline/bfq | 延迟和吞吐量 |
| 内核参数 | dirty_ratio, readahead | 写入合并和预读 |
| 块设备 | nr_requests, max_sectors_kb | 队列深度和块大小 |
| Bcachefs | bucket_size, gc_reserve | 空间分配和 GC |
扩展阅读
上一章: ← 第 8 章:压缩策略 | 下一章: 第 10 章:Docker 与容器化 →