You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu 22服务器小文件写入偶现20ms阻塞延迟问题问询

Ubuntu 22服务器小数据量文件写入偶发20ms延迟问题

问题描述

在Ubuntu 22服务器上观测到,即便是仅写入几字节的极小数据量,文件写入操作也经常出现约20ms的延迟。
从测试结果可总结出两个规律:

  • 两次写入操作间隔时间较长、待写入的目标文件已存在时,延迟出现的概率明显升高
  • 写入文件前先删除目标文件反而能提升写入性能,和常规认知相反
    测试服务器硬件配置为6核Xeon 2386G处理器,双NVMe SSD组建软RAID,测试期间服务器几乎无其他业务运行,无其他登录用户。

复现代码

#include <iostream>
#include <fstream>
#include <chrono>
#include <filesystem>
#include <thread>

using namespace std;

void go_c() {
  FILE *out = fopen("hello.txt", "w");
  fputs("hello", out);
  fclose(out);
}

void go_cpp () {
  ofstream out("hello.txt");
  out<<"hello"<<endl;
}

double test(void (*f)()) {
  typedef chrono::time_point <chrono::steady_clock> tp;

  tp t0 = chrono::steady_clock::now();
  f();
  tp t1 = chrono::steady_clock::now();

  return chrono::duration<double>(t1-t0).count() * 1000; // 单位:毫秒
}

void bench(void (*f)(), const char *txt, int delay_ms) {
  filesystem::remove("hello.txt");

  for (int i=0;i<5;i++) {
    double t = test(f);
    cerr<<i<<": "<<txt<<", time = "<<t<<" ms"<<endl;
    this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
  }

  cerr<<endl;
}

int main () {
  bench(go_c, "C Write", 0);
  bench(go_cpp, "C++ Write", 0);
  bench(go_c, "C Write with delay", 2500);
  bench(go_cpp, "C++ Write with delay", 2500);

  return 0;
}

编译运行命令:

g++ -o write3 write3.cpp -O2 -Wall
./write3

测试输出

0: C Write, time = 0.09978 ms
1: C Write, time = 21.9316 ms
2: C Write, time = 0.185957 ms
3: C Write, time = 0.140212 ms
4: C Write, time = 0.139051 ms

0: C++ Write, time = 0.145766 ms
1: C++ Write, time = 0.091845 ms
2: C++ Write, time = 0.139618 ms
3: C++ Write, time = 0.130834 ms
4: C++ Write, time = 0.132217 ms

0: C Write with delay, time = 0.048674 ms
1: C Write with delay, time = 0.23875 ms
2: C Write with delay, time = 20.8626 ms
3: C Write with delay, time = 8.4307 ms
4: C Write with delay, time = 19.4026 ms

0: C++ Write with delay, time = 17.1555 ms
1: C++ Write with delay, time = 17.5887 ms
2: C++ Write with delay, time = 18.9792 ms
3: C++ Write with delay, time = 25.8653 ms
4: C++ Write with delay, time = 20.7998 ms

环境信息

执行uname -a与dpkg --list | grep -E "libc6?-(dev|bin)"命令的系统环境截图:
系统内核与libc版本截图

根因说明

这个稳定在20ms左右的延迟不是硬件故障,是Ubuntu 22.04默认内核配置、文件系统逻辑和软RAID机制共同作用的结果:

  • 测试代码中使用"w"模式打开文件属于截断写入,当目标文件已存在时,fclose阶段会触发文件元数据(修改时间、文件大小、块映射)的日志提交操作,该操作默认同步阻塞,需要等待存储端确认落盘才会返回。
  • 内核默认脏页过期时间为3000厘秒(即3秒),当两次写入间隔超过这个时间,之前写入的文件页缓存会被标记为待回收,覆盖写入时需要先做旧页无效化,同时触发文件系统日志即时提交,不会等待默认的5秒批量提交窗口。软RAID1场景下这个等待时间会被放大,需要等两块NVMe都完成落盘确认才会返回,调度开销加双盘确认等待的总时长刚好落在15~25ms区间,和测试得到的延迟值完全匹配。
  • 写入前先删除文件的场景属于新建文件而非截断旧文件,走元数据快速追加路径,不需要等待旧文件元数据的刷盘确认,因此速度更快,这就是“删文件反而提升性能”这一反直觉现象的成因。
  • 无间隔连续写入时,多次写入的元数据更新会合并到同一次日志批量提交中,因此大部分时候延迟都在0.1ms级别,只有刚好撞上日志提交窗口的那次操作会出现高延迟,和第一轮C写入的测试结果吻合。

内容的提问来源于stack exchange,提问作者CaptainCodeman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:18:14