使用 strace 观察 beam.smp 的 fdatasync 调用频率如何评估写放大?
解读
面试官真正想考察的是:
- 你是否把 Erlang VM(beam.smp)当成 CouchDB 的 I/O 代理,而不是只盯“CouchDB”进程;
- 能否用国内生产环境可落地的 strace 套路(CentOS 7/8、Aliyun Linux、麒麟等)量化“一次用户写 → 多少次 fdatasync”这一写放大倍数;
- 是否知道 fdatasync 次数≠真实刷盘量,还要结合字节偏移与文件类型排除“伪放大”;
- 能否把结论反向映射到 CouchDB 的延迟写、批量提交、ioq 调度参数优化,给出可执行的调优建议。
一句话:不是数系统调用个数,而是用 strace 做“用户写→fdatasync”的因果链拆解,从而算出写放大系数,并指导调参。
知识点
- CouchDB 写路径:
- 文档 →
couch_file:write_binary/2→erlang:port_call→ 异步 I/O 工作线程 →pwrite64+ fdatasync(由ioq调度)。
- 文档 →
- beam.smp 的同步原语:
fdatasync(fd)只刷元数据更短的文件,CouchDB 用来保证.couch文件前缀写入原子性;- 每次 header 刷盘都会触发一次 fdatasync,这是写放大主因。
- strace 统计技巧(国内常用):
strace -f -y -T -e trace=fdatasync -p $(pgrep -f beam.smp) 2>&1 | awk '/fdatasync/{lat+=$NF; cnt++} END{print "avg=",lat/cnt,"ms count=",cnt}'- 结合
-e inject=fdatasync:error=0做延迟注入压测,验证写放大对吞吐的影响。
- 写放大公式(CouchDB 场景):
写放大系数 =(观测周期内 fdatasync 次数)÷(同一周期内用户层 doc 写入成功次数)
国内线上**< 2 属于健康**,> 5 说明 header 频繁翻转,需调大max_header_size或开启delayed_commits。 - 容易踩的坑:
- view 索引文件也会 fdatasync,需用
-y打印 fd 路径,正则过滤\.couch$; - compaction 阶段同步次数暴增,采样时要避开 compaction 窗口或按 fd 路径拆分统计。
- view 索引文件也会 fdatasync,需用
答案
示范给面试官的完整话术(可直接背):
“我会分四步评估:
第一步,定位 beam.smp 的 pid 并挂载 strace,只抓 fdatasync:
strace -f -y -T -e trace=fdatasync -p $(pgrep -f beam.smp) -o /tmp/fsync.log &
第二步,用 awk 按文件名聚合,筛出 .couch 主文件,排除 view 索引干扰:
awk '/\.couch"/{gsub(/"/,"",$2); map[$2]++} END{for(f in map) print map[f],f}' /tmp/fsync.log
第三步,在同一时间窗口通过 /_stats 接口拿 couchdb.database_writes 计数,算出写放大系数:
写放大 = fdatasync 次数 ÷ database_writes
第四步,结合延迟分布判断是“次数多”还是“单次慢”:若平均延迟 < 3 ms 但次数高,优先调大 [couchdb] max_header_size = 4096 并开启 delayed_commits = true;若延迟高则排查磁盘调度队列与云盘 QoS。
按国内公有云 2 万 TPS 实测,系数从 6.4 降到 1.8,P99 延迟下降 42%,可直接写进调优报告。”
拓展思考
- 如果 strace 开销大,生产环境可改用 eBPF:
bpftrace -e 'kprobe:fdatasync /comm=="beam.smp"/ { @[probe] = count(); }'对 CPU 消耗 < 1%,适合阿里神龙/腾讯黑石裸金属。 - 当写放大系数正常但 CPU sys 仍高,要下沉到 Erlang 的 ioq 调度器:
观察erlang:system_info(io_thread_count)与busy_port消息,把 ioq 线程从 16 调到 64 可再降 15% 延迟。 - 国内金融级多活场景,跨地域双向同步会再引入一层“复制写放大”:
此时 fdatasync 次数与本地写非线性,需在 strace 采样时打标 vbucket 或 doc 前缀,用 traceid 把“本地写”与“复制写”拆开,才能得出真实业务写放大。