作者:锦城牛仔
链接:https://www.zhihu.com/question/381335036/answer/1095187687
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
块设备
Linux中,块(block)设备是相对于字符设备而言的,不像字符设备只能以连续字符流的方式访问,块设备可以提供随机访问,最小的粒度是块。
硬盘HDD——传统的块设备
硬盘中的磁道和扇区(来源《深入理解计算机系统》)
硬盘内部包括多个磁盘,每个磁盘两个盘面都可用于数据存储,每个盘面上的同心圆环称为磁道,每个磁道上均匀间隔着多个扇区,通常情况下每个扇区512字节。多个盘面上半径相同的磁道组成一个柱面。
柱面示意图(来源《深入理解计算机系统》)
之所以有柱面的概念,是因为硬盘中,虽然有多组磁头,但是由于受同一个机械臂控制,这些磁头都是同时移动的,所以同一柱面上的数据不需要移动磁头就可以同时访问。
多磁头受同一传动臂控制(来源《深入理解计算机系统》)
硬盘上的访问时间包括:
- 寻道时间(定位磁道)
- 旋转时间(定位扇区)
- 传输时间(读写扇区数据)
寻道和旋转示意图(来源《深入理解计算机系统》)
固态硬盘SSD——硬盘的代替品
固态硬盘是作为传统硬盘的代替品出现的,相比硬盘主要优势:
- 启动快
- 访问快
- 体积小
- 重量轻
- 并行访问
固态硬盘的存储结构从小到大分别是:
页=>块=>Plane=>LUN=>闪存
固态硬盘存储单元内部结构,来源网络
固态硬盘虽然有那么多优点,但是也有一个缺陷或者说是硬件约束,那就是不能覆盖写问题。SSD可以随机读取页,但是不能像硬盘那样直接覆盖写,SSD只能在空白页上进行写操作。如果没有空白页了,必须擦除整个block的所有页才能写入数据。这就引发了写入放大的问题,比如本来只写1页数据,如果没有空白页了,引发垃圾回收,要先擦除整个block,如果这个block上有5页数据有效,就需要将这5页数据迁移到其他空白页,真实的写入页数就增加了5。
SSD为了克服自身缺陷,进行了一系列的操作:
- 磨损平衡
- 垃圾回收
- Trim
- 预留空间
详情可见,参考文献4、参考文献5。
云存储设备
云存储是基于云主机提供的存储设备,根据应用场景的不同,一般分为:
- 普通云盘
- 高效云盘
- SSD云盘
- 高效SSD云盘
从上到下存储性能越来越强,参考阿里云数据。
Linux块I/O原理
Linux使用虚拟文件系统屏蔽不同I/O设备的差别,Linux内核通过映射层、通用块层、I/O调度层屏蔽不同块设备的差别。
linux块I/O系统结构图,来源(深入理解Linux内核)
Linux内核的I/O操作逻辑结构:
- 扇区(来源于硬盘),硬件上I/O操作的最小单位,通常是512字节。可以通过fdisk -l命令查看每个磁盘sector的大小
- 块,是Linux虚拟文件系统I/O操作的最小单位 ,通常为扇区的2的幂次方倍。通过tune2fs -l /dev/vdb1|grep Block查看块大小
- 段,Linux内存页或页的一部分,是块的整数倍
- 页,Linux内存页,一般是4096字节,用作磁盘缓存。通过getconf PAGE_SIZE查看。
I/O操作的结构体示意图,来源《深入理解Linux内核》
iostat命令——查看I/O统计情况
- 查看tps和读写吞吐量
tps(transfer per second,transfer is an I/O request to device),意思是每秒发起的I/O请求数,包括读和写。测试读或写时,tps约等于fio统计的iops。
#>iostat -dt 1
Linux 4.4.0-93-generic (xjser-dev) 03/21/2020 _x86_64_ (4 CPU)
03/21/2020 04:26:19 PM
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
vda 13.11 513.00 118.35 40830854445 9419986180
vdb 3.24 22.97 90.45 1828620029 7199419100
03/21/2020 04:26:20 PM
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
vda 0.00 0.00 0.00 0 0
vdb 0.00 0.00 0.00 0 0
03/21/2020 04:26:21 PM
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
vda 2.00 0.00 28.00 0 28
vdb 0.00 0.00 0.00 0 0
- 查看I/O详情
#>iostat -xdt 1
Linux 4.4.0-93-generic (xjser-dev) 03/21/2020 _x86_64_ (4 CPU)
03/21/2020 04:31:45 PM
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.02 2.87 6.80 6.31 513.00 118.35 96.32 0.00 0.27 3.94 4.86 1.07 1.41
vdb 0.00 3.47 0.87 2.38 22.97 90.46 69.91 0.04 11.92 1.31 15.79 0.61 0.20
03/21/2020 04:31:46 PM
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
vdb 0.00 0.00 0.00 2616.00 0.00 10464.00 8.00 127.90 48.85 0.00 48.85 0.38 100.00
03/21/2020 04:31:47 PM
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
vdb 0.00 0.00 0.00 2625.00 0.00 10500.00 8.00 127.90 48.69 0.00 48.69 0.38 100.00
重点解释一下几个比较有用的数据项
- r/s, (read per second),每秒读次数,读测试时,约等于fio的iops
- w/s,(write per second),每秒写次数,写测试时,约等于fio的iops
- rKB/s,每秒读数据量,读测试时,约等于fio的bw
- wKB/s,每秒写数据量,写测试时,约等于fio的bw
- avgrq-sz,(average request size)平均每个I/O请求的大小,以sector计量,每个sector通常为512字节,avgrq-sz为8,表示平均每个I/O请求大小为4096字节。测试时,等于fio命令中bs参数的值除以512。
- avgqu-sz,(average queue size)平均队列长度。测试时,约等于fio命令中iodepth参数的值。
- await,I/O请求从发起到完成的平均时间,包括在队列中等待的时间和执行I/O的时间。等于blktrace中的Q2C(整个IO请求所消耗的时间)。注意,由于await包括了在队列中等待的时候,因此await高并不能说明硬盘性能低。分析I/O硬件性能要用blktrace中的D2C(IO请求在driver和硬件上所消耗的时间)
- r_await,与await一样,只统计读I/O
- w_await,与await一样,只统计写I/O
iostat中不要关注的数据项,由于I/O并行化以及SSD的普及,这两个数据项可以不看了。想了解原因请看参考文献1。
- svctm
- %util
fio命令——I/O性能测试利器
一般用于线上业务的服务器,都需要在使用前测试磁盘的性能。推荐fio进行性能测试,fio命令参数说明如下(详细方法请看参考文献2)
blktrace——深入分析I/O性能
如果需要深入分析I/O性能,推荐使用blktrace命令。该命令可以将I/O请求到达块设备处理层后的所有步骤进行统计分析。
参考文献:
1. http://bean-li.github.io/dive-into-iostat/
3. http://linuxperf.com/?p=161
4. http://www.jinbuguo.com/storage/ssd_intro.html
5. http://www.ssdfans.com/?p=131
6. https://help.aliyun.com/documen