文档章节

深入理解 Linux磁盘顺序写、随机写

x
 xiangyunyan
发布于 08/31 22:58
字数 3191
阅读 29
收藏 0
Linux磁盘管理好坏直接关系到整个系统的性能问题。Linux磁盘管理常用三个命令为df、du和fdisk。

一、前言

● 随机写会导致磁头不停地换道,造成效率的极大降低;顺序写磁头几乎不用换道,或者换道的时间很短
● 本文来讨论一下两者具体的差别以及相应的内核调用

二、环境准备

组件

版本

OS Ubuntu 16.04.4 LTS
fio 2.2.10

三、fio介绍

通过fio测试,能够反映在读写中的状态,我们需要重点关注fio的输出报告中的几个关键指标:
slat :是指从 I/O 提交到实际执行 I/O 的时长(Submission latency)
clat :是指从 I/O 提交到 I/O 完成的时长(Completion latency)
lat :指的是从 fio 创建 I/O 到 I/O 完成的总时长
bw :吞吐量
iops :每秒 I/O 的次数

四、同步写测试

(1)同步随机写

主要采用fio作为测试工具,为了能够看到系统调用,使用strace工具,命令看起来是这样:

先来测试一个随机写

strace -f -tt -o /tmp/randwrite.log -D fio -name=randwrite -rw=randwrite \
-direct=1 -bs=4k -size=1G -numjobs=1  -group_reporting -filename=/tmp/test.db

提取关键信息

root@wilson-ubuntu:~# strace -f -tt -o /tmp/randwrite.log -D fio -name=randwrite -rw=randwrite \
> -direct=1 -bs=4k -size=1G -numjobs=1  -group_reporting -filename=/tmp/test.db
randwrite: (g=0): rw=randwrite, bs=4K-4K/4K-4K/4K-4K, ioengine=sync, iodepth=1
fio-2.2.10
Starting 1 process
...
randwrite: (groupid=0, jobs=1): err= 0: pid=26882: Wed Aug 14 10:39:02 2019
  write: io=1024.0MB, bw=52526KB/s, iops=13131, runt= 19963msec
    clat (usec): min=42, max=18620, avg=56.15, stdev=164.79
     lat (usec): min=42, max=18620, avg=56.39, stdev=164.79
...
    bw (KB  /s): min=50648, max=55208, per=99.96%, avg=52506.03, stdev=1055.83
...

Run status group 0 (all jobs):
  WRITE: io=1024.0MB, aggrb=52525KB/s, minb=52525KB/s, maxb=52525KB/s, mint=19963msec, maxt=19963msec

Disk stats (read/write):
...
  sda: ios=0/262177, merge=0/25, ticks=0/7500, in_queue=7476, util=36.05%

列出了我们需要重点关注的信息:
(1)clat ,平均时长56ms左右
(2)lat ,平均时长56ms左右
(3)bw ,吞吐量,大概在52M左右

再来看内核调用信息:

root@wilson-ubuntu:~# more /tmp/randwrite.log
...
26882 10:38:41.919904 lseek(3, 665198592, SEEK_SET) = 665198592
26882 10:38:41.919920 write(3, "\220\240@\6\371\341\277>\0\200\36\31\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.919969 lseek(3, 4313088, SEEK_SET) = 4313088
26882 10:38:41.919985 write(3, "\220\240@\6\371\341\277>\0\200\36\31\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920032 lseek(3, 455880704, SEEK_SET) = 455880704
26882 10:38:41.920048 write(3, "\220\240@\6\371\341\277>\0\200\36\31\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920096 lseek(3, 338862080, SEEK_SET) = 338862080
26882 10:38:41.920112 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920161 lseek(3, 739086336, SEEK_SET) = 739086336
26882 10:38:41.920177 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920229 lseek(3, 848175104, SEEK_SET) = 848175104
26882 10:38:41.920245 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920296 lseek(3, 1060147200, SEEK_SET) = 1060147200
26882 10:38:41.920312 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920362 lseek(3, 863690752, SEEK_SET) = 863690752
26882 10:38:41.920377 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920428 lseek(3, 279457792, SEEK_SET) = 279457792
26882 10:38:41.920444 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920492 lseek(3, 271794176, SEEK_SET) = 271794176
26882 10:38:41.920508 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
26882 10:38:41.920558 lseek(3, 1067864064, SEEK_SET) = 1067864064
26882 10:38:41.920573 write(3, "\220\240@\6\371\341\277>\0\2402\24\0\0\0\0\202\2\7\320\343\6H\26P\340\277\370\330\30e\30"..., 4096) = 4096
...

随机读每一次写入之前都要通过lseek去定位当前的文件偏移量

同步顺序写

用刚才的方法来测试顺序写

root@wilson-ubuntu:~# strace -f -tt -o /tmp/write.log -D fio -name=write -rw=write \
-direct=1 -bs=4k -size=1G -numjobs=1  -group_reporting -filename=/tmp/test.db
write: (g=0): rw=write, bs=4K-4K/4K-4K/4K-4K, ioengine=sync, iodepth=1
fio-2.2.10
Starting 1 process
Jobs: 1 (f=1): [W(1)] [100.0% done] [0KB/70432KB/0KB /s] [0/17.7K/0 iops] [eta 00m:00s]
write: (groupid=0, jobs=1): err= 0: pid=27005: Wed Aug 14 10:53:02 2019
  write: io=1024.0MB, bw=70238KB/s, iops=17559, runt= 14929msec
    clat (usec): min=43, max=7464, avg=55.95, stdev=56.24
     lat (usec): min=43, max=7465, avg=56.15, stdev=56.25
...
    bw (KB  /s): min=67304, max=72008, per=99.98%, avg=70225.38, stdev=1266.88
...

Run status group 0 (all jobs):
  WRITE: io=1024.0MB, aggrb=70237KB/s, minb=70237KB/s, maxb=70237KB/s, mint=14929msec, maxt=14929msec

Disk stats (read/write):
...
  sda: ios=0/262162, merge=0/10, ticks=0/6948, in_queue=6932, util=46.49%

可以看到:
吞吐量提升至70M左右

再来看一下内核调用:

root@wilson-ubuntu:~# more /tmp/write.log
...
27046 10:54:28.194508 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\360\t\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194568 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194627 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194687 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194747 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194807 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194868 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194928 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.194988 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195049 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195110 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195197 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195262 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195330 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195426 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195497 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195567 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195637 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195704 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195757 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195807 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195859 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195910 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.195961 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196012 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196062 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0\220\24\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196112 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196162 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196213 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196265 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196314 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196363 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196414 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196472 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196524 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
27046 10:54:28.196573 write(3, "\0\0\23\0\0\0\0\0\0\300\16\0\0\0\0\0\0 \26\0\0\0\0\0\0\320\17\0\0\0\0\0"..., 4096) = 4096
...

由于顺序读,不需要反复定位文件偏移量,所以能够专注于写操作

五、slat指标

从上面的测试,我们在fio的测试报告中,并没有发现slat的身影,那是由于上述都是同步操作,对同步 I/O 来说,由于 I/O 提交和 I/O 完成是一个动作,所以 slat 实际上就是 I/O 完成的时间

异步顺序写,将同步顺序写的命令添加-ioengine=libaio:

root@wilson-ubuntu:~# fio -name=write -rw=write -ioengine=libaio -direct=1 -bs=4k -size=1G -numjobs=1  -group_reporting -filename=/tmp/test.db
write: (g=0): rw=write, bs=4K-4K/4K-4K/4K-4K, ioengine=libaio, iodepth=1
fio-2.2.10
Starting 1 process
Jobs: 1 (f=1): [W(1)] [100.0% done] [0KB/119.3MB/0KB /s] [0/30.6K/0 iops] [eta 00m:00s]
write: (groupid=0, jobs=1): err= 0: pid=27258: Wed Aug 14 11:14:36 2019
  write: io=1024.0MB, bw=120443KB/s, iops=30110, runt=  8706msec
    slat (usec): min=3, max=70, avg= 4.31, stdev= 1.56
    clat (usec): min=0, max=8967, avg=28.13, stdev=55.68
     lat (usec): min=22, max=8976, avg=32.53, stdev=55.72
...
    bw (KB  /s): min=118480, max=122880, per=100.00%, avg=120467.29, stdev=1525.68
...

Run status group 0 (all jobs):
  WRITE: io=1024.0MB, aggrb=120442KB/s, minb=120442KB/s, maxb=120442KB/s, mint=8706msec, maxt=8706msec

Disk stats (read/write):
...
  sda: ios=0/262147, merge=0/1, ticks=0/6576, in_queue=6568, util=74.32%

可以看到,slat指标出现,lat 近似等于 slat + clat 之和(avg平均值);并且换成异步io之后,吞吐量得到了极大的提升,120M左右

六、总结

● fio应该作为磁盘的baseline工具,拿到机器(物理机或者云机器)都应该第一时间对机器的磁盘做一个基线测试,做到心中有数
● 本文所有的测试,都是绕开了缓存,在实际应用中需要将缓存的影响考虑进去

至此,本文结束

本文地址:https://www.linuxprobe.com/deep-linux-random.html

本文转载自:https://www.linuxprobe.com/deep-linux-random.html

x
粉丝 2
博文 179
码字总数 62471
作品 0
长沙
私信 提问
深入理解 Linux磁盘顺序写、随机写

Linux磁盘管理好坏直接关系到整个系统的性能问题。Linux磁盘管理常用三个命令为df、du和fdisk。 一、前言 ● 随机写会导致磁头不停地换道,造成效率的极大降低;顺序写磁头几乎不用换道,或者...

Linux就该这么学
08/31
61
0
顺序IO和随机IO的Linux实现

各位大神,我现在在做一个类似iometer的程序,遇到了一个问题,在实现随机IO和顺序IO时,不知道应该用什么函数。我原先是直接用read()和write()和lseek()这三个函数但是问题是: 文件的...

linkt
2014/09/30
954
0
IO调度策略之我见

IO调度策略对上面的块设备层和下面的磁盘驱动起作用,它实质上切断了数据从应用程序到磁盘的路径,从而也就解除了块设备和底层驱动程序之间的耦合,这样的话就可以匹配上下两层之间的不和谐,...

晨曦之光
2012/04/10
1K
0
RocketMQ高性能之底层存储设计

说在前面 RocketMQ在底层存储上借鉴了Kafka,但是也有它独到的设计,本文主要关注深刻影响着RocketMQ性能的底层文件存储结构,中间会穿插一点点Kafka的东西以作为对比。 例子 Commit Log,一...

薛定谔的旺
02/20
64
0
磁盘性能指标--IOPS、吞吐量及测试

一、概念介绍: 磁盘性能指标--IOPS ---------------------------------------------------------- IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指...

wushank
2018/06/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

R语言基本命令,dataframe增删改查

基本操作: 查询变量类型(假设变量名是a) class(a) 在R语言中: T 代表--> True F 代表--> False 与、或运算符 读取: 读取csv文件到dataframe(字符串不当作factor类型来处理,csv的na不作...

flash胜龙
30分钟前
4
0
重看《功夫熊猫1》却有了另一番感触

最近带着小孩,又看了一遍电影《功夫熊猫1》。但这次中间的很多情节,让我有了另一番新的感触。 电影的开头是熊猫阿宝,在梦里成为了一个武功盖世的大侠。这是他最大的梦想。 当阿宝热情洋溢...

我是菜鸟我骄傲
33分钟前
10
1
3.设计模式之二:原型模式【创建型模式】

在有些系统中,存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,用原型模式生成对象就很高效,就像孙悟空拔下猴毛轻轻一吹就变出很多孙悟空一样...

Eappo_Geng
42分钟前
7
0
Springboot+Junit测试出现No tests found matching

话不多说,出现以下错误,如果各注解都没问题,请检查包路径 测试用例包路径必须跟项目启动类包路径一致,不然也会报下面错误 java.lang.Exception: No tests found matching [{ExactMatche...

fangsw
48分钟前
5
0
封装,继承,多态?

1. 封装? 封装指的是利用抽象数据类型将数据和基于数据操作全部放在一个类里,使其构成一个不可分割的实体。数据被保护在抽象数据类型的内部,尽可能地隐藏内部的实现细节,并对外只提供操作...

happywe
50分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部