了解Linux写入性能

时间:2017-07-16 01:47:59

标签: linux go filesystems ext4

我一直在做一些基准测试以尝试理解Linux上的写入性能,而且我不理解我得到的结果(我在Ubuntu 17.04上使用ext4,尽管我'如果有的话,我更感兴趣的是了解ext4,而不是比较文件系统。)

具体来说,我了解一些数据库/文件系统的工作方式是保留数据的陈旧副本,然后将更新写入修改日志。定期地,在陈旧数据上重放日志以获得新数据,然后将其保留。这只对我有意义,如果附加到文件比覆盖整个文件更快(否则为什么要写日志更新?为什么不覆盖磁盘上的数据?)。我很好奇附加速度比覆盖更快,所以我在go(https://gist.github.com/msteffen/08267045be42eb40900758c419c3bd38)中写了一个小基准并得到了这些结果:

$ go test ./write_test.go  -bench='.*'
BenchmarkWrite/Write_10_Bytes_10_times-8                30    46189788 ns/op
BenchmarkWrite/Write_100_Bytes_10_times-8               30    46477540 ns/op
BenchmarkWrite/Write_1000_Bytes_10_times-8              30    46214996 ns/op
BenchmarkWrite/Write_10_Bytes_100_times-8                3   458081572 ns/op
BenchmarkWrite/Write_100_Bytes_100_times-8               3   678916489 ns/op
BenchmarkWrite/Write_1000_Bytes_100_times-8              3   448888734 ns/op
BenchmarkWrite/Write_10_Bytes_1000_times-8               1  4579554906 ns/op
BenchmarkWrite/Write_100_Bytes_1000_times-8              1  4436367852 ns/op
BenchmarkWrite/Write_1000_Bytes_1000_times-8             1  4515641735 ns/op
BenchmarkAppend/Append_10_Bytes_10_times-8              30    43790244 ns/op
BenchmarkAppend/Append_100_Bytes_10_times-8             30    44581063 ns/op
BenchmarkAppend/Append_1000_Bytes_10_times-8            30    46399849 ns/op
BenchmarkAppend/Append_10_Bytes_100_times-8              3   452417883 ns/op
BenchmarkAppend/Append_100_Bytes_100_times-8             3   458258083 ns/op
BenchmarkAppend/Append_1000_Bytes_100_times-8            3   452616573 ns/op
BenchmarkAppend/Append_10_Bytes_1000_times-8             1  4504030390 ns/op
BenchmarkAppend/Append_100_Bytes_1000_times-8            1  4591249445 ns/op
BenchmarkAppend/Append_1000_Bytes_1000_times-8           1  4522205630 ns/op
PASS
ok    command-line-arguments  52.681s

这给我留下了两个我无法想到答案的问题:

1)当我从100次写入到1000次时,为什么每次操作的时间会增加很多? (我知道Go会为我重复基准测试,所以自己做多次写操作可能很傻,但是因为我得到了一个奇怪的答案,我想了解原因)这是由于Go测试中的一个错误(现已修复)

2)为什么不写入文件比写入文件更快?我认为更新日志的重点是利用附加的比较速度? (请注意,当前的工作台在每次写入后都会调用Sync(),但即使我不这样做,也不会比写入更快,尽管两者总体上要快得多)

如果这里的任何专家能够启发我,我真的很感激!谢谢!

1 个答案:

答案 0 :(得分:2)

关于(1),我认为这个问题与你的基准没有做Go工具期望他们做的事情有关。

从文档(https://golang.org/pkg/testing/#hdr-Benchmarks):

  

基准函数必须运行目标代码b.N次。在基准执行期间,调整b.N直到基准函数持续足够长的时间以便可靠地计时。

我没有看到您的代码使用b.N,因此当基准工具认为您运行代码b.N次时,您自己管理重复。根据工具实际用于b.N的值,结果会出乎意料地变化。

您实际上可以执行10次,100次和1,000次,但在所有情况下执行b.N次{使b.N * 10b.N * 100等等,以便报告的基准是调整得当。

关于(2),当某些系统使用顺序日志来存储重放它们的操作时,并不是因为附加到文件比覆盖单个文件更快。

在数据库系统中,如果需要更新特定记录,则必须首先找到需要更新的实际文件(以及文件中的位置)。

这可能需要多次索引查找,一旦更新记录,您可能需要更新这些索引以反映新值。

因此,正确的比较是附加到单个日志与进行多次读取再加上几次写入。