网上dd命令的文章有很多,这里只是自己做下简单的记录。
dd命令介绍
作用是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。可以用于测试磁盘命令、数据备份或恢复等。
dd命令用于复制文件并对原文件的内容进行转换和格式化处理。用的比较多的还是用dd来备份裸设备。但是不推荐,如果需要备份oracle裸设备,可以使用rman备份,或使用第三方软件备份,使用dd的话,管理起来不太方便。建议在有需要的时候使用dd 对物理磁盘操作,如果是文件系统的话还是使用tar backup cpio等其他命令更加方便。另外,使用dd对磁盘操作时,最好使用块设备文件。
dd --help 打印帮助
dd 命令通用语法格式如下:
dd [bs=<字节数>][cbs=<字节数>][conv=<关键字>][count=<区块数>][ibs=<字节数>][if=<文件>][obs=<字节数>][of=<文件>][seek=<区块数>][skip=<区块数>][--help][--version]
dd if=path/to/input_file of=/path/to/output_file bs=block_size count=number_of_blocks
命令简介
主要选项(指定数字的地方若以下列字符结尾乘以相应的数字: b=512, c=1, k=1024, w=2, xm=number m):
if=file 输入文件名,缺省为标准输入。 从file读取,如if=/dev/zero,该设备无穷尽地提供0,(不产生读磁盘IO)
of=file 输出文件名,缺省为标准输出。 向file写出,可以写文件,可以写裸设备。如of=/dev/null,"黑洞",它等价于一个只写文件. 所有写入它的内容都会永远丢失. (不产生写磁盘IO)
ibs=bytes 一次读入 bytes 个字节(即一个块大小为 bytes 个字节)。
obs=bytes 一次写 bytes 个字节(即一个块大小为 bytes 个字节)。
bs=bytes 同时设置读写块的大小为 bytes ,可代替 ibs 和 obs。如bs=8k 每次读或写的大小,即一个块的大小为8K。
cbs=bytes 一次转换 bytes 个字节,即转换缓冲区大小。
skip=blocks 从输入文件开头跳过 blocks 个块后再开始复制。
seek=blocks 从输出文件开头跳过 blocks 个块后再开始复制。(通常只有当输出文件是磁盘或磁带时才有效)。
count=blocks 仅拷贝 blocks 个块,块大小等于 ibs 指定的字节数。
iflag=FLAGS 指定读的方式FLAGS,参见“FLAGS参数说明”
oflag=FLAGS 指定写的方式FLAGS,参见“FLAGS参数说明”
conv=conversion:用指定的参数转换文件。
ascii:转换ebcdic为ascii
ebcdic:转换ascii为ebcdic
ibm:转换ascii为alternate ebcdic
block:把每一行转换为长度为cbs,不足部分用空格填充
unblock:使每一行的长度都为cbs,不足部分用空格填充
lcase:把大写字符转换为小写字符
ucase:把小写字符转换为大写字符
swab:交换输入的每对字节
noerror:出错时不停止
notrunc:不截短输出文件
sync:将每个输入块填充到ibs个字节,不足部分用空(NUL)字符补齐。
flags参数
conv转换参数、flags参数。
使用方式如:
测试方式:使用dd指令,对磁盘进行连续写入,不使用内存缓冲区,每次写入8k的数据,总共写入20万次,产生1.6G大小的文件。
测试指令:dd if=/dev/zero of=/data01/test.dbf bs=8k count=200k conv=fdatasync
1) dd用于复制,从if读出,写到of;
2) if=/dev/zero(产生字符)不产生IO,因此可以用来测试纯写速度;
3) bs是每次读或写的大小,即一个块的大小,count是读写块的数量;
4)conv=fdatasync表示只把文件的“数据”写入磁盘
5)会在/data01下生成一个文件test.dbf,count * bs 等于最终大小,注意删除。
从if读出写到of,不同的设备表示的不同
从源 /dev/zero 读取写入到驱动盘的时候(测试写),当从驱动盘读取时写入到/dev/null(测试读)。在整个操作过程中, DD 命令会跟踪数据传输的速度并且报告出结果。
/dev/null和/dev/zero的区别
/dev/null,它是空设备,也称为位桶(bit bucket)、回收站、无底洞,可以向它输出任何数据。任何写入它的输出都会被抛弃。如果不想让消息以标准输出显示或写入文件,那么可以将消息重定向到位桶。
/dev/zero,是一个输入设备,可用它来初始化文件。该设备无穷尽地提供0,可以使用任何需要的数目——设备提供的要多的多。他可以用于向设备或文件写入字符串0。
使用sync、fsync、fdatasync
dd bs=8k count=4k if=/dev/zero of=test.log conv=fsync
dd bs=8k count=4k if=/dev/zero of=test.log conv=fdatasync
dd bs=8k count=4k if=/dev/zero of=test.log oflag=dsync
dd bs=8k count=4k if=/dev/zero of=test.log 默认“写缓存”启作用
dd bs=8k count=4k if=/dev/zero of=test.log conv=sync “写缓存”启作用
dd bs=8k count=4k if=/dev/zero of=test.log; sync “写缓存”启作用
1、
dd bs=8k count=4k if=/dev/zero of=test.log conv=fsync
加入这个参数后,dd命令执行到最后会真正执行一次“同步(sync)”操作,,这样算出来的时间才是比较符合实际使用结果的。conv=fsync表示把文件的“数据”和“metadata”都写入磁盘(metadata包括size、访问时间st_atime & st_mtime等等),因为文件的数据和metadata通常存在硬盘的不同地方,因此fsync至少需要两次IO写操作,fsync 与fdatasync相差不大。(重要,最有参考价值)
2、
dd bs=8k count=4k if=/dev/zero of=test.log conv=fdatasync
加入这个参数后,dd命令执行到最后会真正执行一次“同步(sync)”操作,,这样算出来的时间才是比较符合实际使用结果的。conv=fdatasync表示只把文件的“数据”写入磁盘,fsync 与fdatasync相差不大。(重要,最有参考价值)
3、
dd bs=8k count=4k if=/dev/zero of=test.log oflag=dsync
加入这个参数后,dd在执行时每次都会进行同步写入操作。每次读取8k后就要先把这8k写入磁盘,然后再读取下面一个8k,一共重复4K次,生成一个32M文件。这是最慢的一种方式了,基本上没有用到写缓存(write cache)。也是比较准确的。
conv=fdatasync与oflag=dsync的区别在于:sync函数只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。fsync函数只对由文件描述符filedes指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。所以看到的fdatasync速度比dsync好。
4、
dd bs=8k count=4k if=/dev/zero of=test
没有加任何参数,dd默认的方式不包括“同步(sync)”命令(没加关于操作系统“写缓存”的参数,默认“写缓存”启作用),也就是说,dd命令完成前并没有让系统真正把文件写到磁盘上。dd先把数据写到操作系统“写缓存”,就完成了写操作。所以以上命令只是单纯地把数据读到内存缓冲当中(写缓存[write cache])。通常称为update的系统守护进程会周期性地(一般每隔30秒)调用sync函数,把“写缓存”中的数据刷入磁盘。
因为“写缓存”起作用,会测试出一个超快的性能。因为dd给的只是读取速度,直到dd完成后系统才开始真正往磁盘上写数据,但这个速度是看不到了。
如:163840000 bytes (164 MB) copied, 0.742906 seconds, 221 MB/s
5、
dd bs=8k count=4k if=/dev/zero of=test conv=sync
conv=sync参数明确“写缓存”启作用,默认值就是conv=sync
6、
dd bs=8k count=4k if=/dev/zero of=test; sync
和默认的不加参数一样,分号隔开的只是先后两个独立的命令。当sync命令准备开始往磁盘上真正写入数据的时候,前面dd命令已经把错误的“写入速度”值显示在屏幕上了。所以还是得不到真正的写入速度。
裸设备测试
----------------------
1、裸设备到文件系统
dd if=/dev/rsd1b of=/backup/df1.dbf bs=8k skip=8 count=3841
2、文件系统到裸设备
dd if=/backup/df1.dbf of=/dev/rsd2b bs=8k seek=8
关于IO方式
正常系统调用read/write流程
硬盘->内核缓冲区->用户缓冲区
用户缓冲区->内核缓冲区->硬盘
Direct IO
跨过内核缓冲区,从用户缓冲区直接写盘,在Oracle里应该是跨过SGA,从PGA——>datafile
SYNC IO
会话发起IO请求时,整个会话阻塞,直到IO完成,在Oracle里比较典型的是lgwr,用户commit后必须等待lgwr写完才能返回
ASYNC IO
发出IO请求后,丢给内核去做,在Oracle表现为设置了dbwr_io_slaves,dbwr收集脏块后丢给slave进程去写盘
测试磁盘读写速度
测试时常会加上time计时
1、只测试磁盘写能力
time dd if=/dev/zero of=test.log bs=64k,count=4k
因为/dev//zero是一个伪设备,它只产生空字符流,对它不会产生IO,所以,IO都会集中在of文件中,of文件只用于写,所以这个命令相当于测试磁盘的写能力。命令结尾添加oflag=direct将跳过内存缓存,添加oflag=sync将跳过hdd缓存。
2、只测试磁盘读能力
time dd if=/dev/sdb of=/dev/null bs=64k
因为/dev/sdb是一个物理分区,对它的读取会产生IO,/dev/null是伪设备,相当于黑洞,of到该设备不会产生IO,所以,这个命令的IO只发生在/dev/sdb上,也相当于测试磁盘的读能力。(Ctrl+c终止测试)
读取某个文件测试磁盘读能力时,要首先清除内存的缓存,以确保这个文件确实是从驱动盘读取的。否则是从page cache里取的值。
运行下面的命令来清除内存缓存
$ sudo sh -c "sync && echo 3 > /proc/sys/vm/drop_caches"
执行完后再执行dd命令,如dd if=./test.log of=/dev/null bs=4k
实际测试,写入一个文件128M,查看free -m里cached增加128M,执行读取命令结果2.7GB,再执行清缓存命令后,同样命令读取速度变为135MB。
3、测试同时读写能力
time dd if=/dev/sdb of=/testrw.dbf bs=64k
一个是物理分区,一个是实际的文件,对它们的读写都会产生IO(对/dev/sdb是读,对/testrw.dbf是写),假设它们都在一个磁盘中,这个命令就相当于测试磁盘的同时读写能力。
4、测试纯写入性能
dd if=/dev/zero of=test bs=8k count=10000 oflag=direct
5、测试纯读取性能
dd if=test of=/dev/null bs=8k count=10000 iflag=direct
注意:dd 只能提供一个大概的测试结果,而且是连续 I/O(顺序IO) 而不是随机 I/O,理论上文件规模越大,测试结果越准确。 同时,iflag/oflag 提供 direct 模式,direct 模式是把写入请求直接封装成 I/O 指令发到磁盘,非 direct 模式只是把数据写入到系统缓存就认为 I/O 成功,并由操作系统决定缓存中的数据什么时候被写入磁盘。
还可以监控下dd执行的进度:linux下显示dd命令的进度
疑问1:fdatasync 、fsync 、dsync 几种方式,建议用哪种呢?
建议dd bs=8k count=4k if=/dev/zero of=test.log conv=fdatasync
因为这种方式最接近计算机实际操作,所以测出来的数据最有参考价值。??
1. dd if=/dev/zero of=test bs=64k count=16k
这个很不准确的,因为命令结束的时候数据还没有真正写到磁盘上去
2. dd if=/dev/zero of=test bs=64k count=16k conv=fsync
这个还算准确,数据已经写入磁盘
3. dd if=/dev/zero of=test bs=64k count=4k oflag=dsync
这个可以当成是模拟数据库插入操作,所以很慢
-dsync 可以当成是模拟数据库插入操作,在/dev/zone中读出一条数据就立即写入硬盘
-fsync 同样也是将数据已经写入磁盘,但是是在经过缓存后最后再写入硬盘
疑问2:同一块磁盘,不同bs与count的组合,测试结果不同?
测试结果磁盘写速度肯定不同。
同一块磁盘,同一命令每次结果都可能会不同,需要多采样几次,取平均值。
疑问3:bs表示一个块大小,count为次数。应该如何设置bs、count的值,测试更准确?
常用的有bs=64k,count=4k
bs的大小:1M的大小实际上是相当大的。小尺寸如 64K 甚至是 4K 的。
常用命令
dd if=/dev/zero of=test bs=64k count=4k oflag=dsync
dd if=/dev/zero of=test bs=8k count=256k conv=fdatasync
参考文档:
正确的使用dd进行磁盘读写速度测试、Linux 中用 dd 命令来测试硬盘读写速度