今天项目和开发同学反馈过来一个问题,说是程序往服务器内写入文件,每次写1000行,总共写完之后只有9M大小的文件,却要将近几分钟的时间才能写入完成。开发甚至给每批写入的耗时加了日志来排查问题,都没找到问题。

我对这种问题也是百思不得其解。甚至怀疑是程序的问题,于是进行排查,首先用df -hT发现程序挂载的持久化文件目录是nfs远端存储。于是自信满满的怀疑肯定是因为挂载的nfs因为网络质量问题导致的写入慢,然后就用dd命令来写入100M的文件的文件来测试存储速率。但奇怪的是一瞬间就写完了,感觉被打脸了一样又dd了4GB的文件来测试,也是一瞬间就写完了,当时 “感觉” 虽然是写完了,但可能后台还在一点一点上传文件到远端的nfs,看了一下网络监控,瞬间惊呆了,现场的内网网络速率甚至达到了惊人的 1Gb/s。。。。

这就奇怪了,郁闷找大佬群,问群里的大佬,其中有个大佬说了一句:“看怎么写,一次写10M和1000次写10K差距很大” 是我才疏学浅了。那就搞个脚本模拟一下开发同学的功能来复现问题吧😂😂😂

准备工作

样例数据

先来准备一个1万行充满Hello用于测试的文本:

$ yes "Hello" | head -n 10000 > 1w-hello.txt

$ wc -l 1w-hello.txt
10000 1w-hello.txt

脚本准备

准备测试写入的脚本,以每次1000行的速度将文件内容写入到目标位置

$ cat speet_test.sh
#!/bin/bash

# 源文件
input_file=$1
# 目标文件
output_file=$2

line_count=0
SECONDS=0
batch_size=1000
> "$output_file"

# 逐行读取输入文件
while IFS= read -r line; do
  # 将当前行写入输出文件
  echo "$line" >> "$output_file"
  ((line_count++))
  # 检查是否达到批次大小
  if [ "$line_count" -eq "$batch_size" ]; then
    line_count=0
    echo "-------- Batch Separator --------" >> "$output_file"
  echo "现在目标文件的大小: $(du -sh ${output_file}|awk '{print $1}') 行数: $(wc -l ${output_file}|awk '{print $1}') 总已耗时: ${SECONDS}s"
  fi
done < "$input_file"
echo "Processing complete."

开始测试

首先,在将文本内容以每批一千行的速度写入到nfs的存储中:

$ sh speet_test.sh 1w-hello.txt /nas/1w-hello-nfs.txt

# 返回结果
现在目标文件的大小: 8.0K 行数: 1001 总已耗时: 9s
现在目标文件的大小: 12K 行数: 2002 总已耗时: 18s
现在目标文件的大小: 20K 行数: 3003 总已耗时: 26s
现在目标文件的大小: 24K 行数: 4004 总已耗时: 37s
现在目标文件的大小: 32K 行数: 5005 总已耗时: 46s
现在目标文件的大小: 36K 行数: 6006 总已耗时: 55s
现在目标文件的大小: 44K 行数: 7007 总已耗时: 64s
现在目标文件的大小: 48K 行数: 8008 总已耗时: 73s
现在目标文件的大小: 56K 行数: 9009 总已耗时: 83s
现在目标文件的大小: 60K 行数: 10010 总已耗时: 90s
Processing complete.

看到这个结果。。。我。。。写入一个只有一万行的文本,大小只有60KB的文件,9秒才只能写入1000行。。。。。


接着,我们继续测试,将文件写入到本地中看看速度

$ sh speet_test.sh 1w-hello.txt /tmp/1w-hello-local.txt

# 返回结果
现在目标文件的大小: 8.0K 行数: 1001 总已耗时: 0s
现在目标文件的大小: 12K 行数: 2002 总已耗时: 0s
现在目标文件的大小: 20K 行数: 3003 总已耗时: 0s
现在目标文件的大小: 24K 行数: 4004 总已耗时: 0s
现在目标文件的大小: 32K 行数: 5005 总已耗时: 0s
现在目标文件的大小: 36K 行数: 6006 总已耗时: 0s
现在目标文件的大小: 44K 行数: 7007 总已耗时: 0s
现在目标文件的大小: 48K 行数: 8008 总已耗时: 0s
现在目标文件的大小: 56K 行数: 9009 总已耗时: 0s
现在目标文件的大小: 60K 行数: 10010 总已耗时: 0s
Processing complete.

果然,使用nfs存储在这点上面还是有点小坑的,去问了GPT也没得到很好的结果,跟开发同学反馈后,将程序持久化的目录改为了本地存储后,效果果然发生了质的改变。😂

最后修改:2024 年 01 月 26 日
如果觉得我的文章对你有用,请随意赞赏