Linux优化之磁盘预读readahead
简介
在内存中读取数据比从磁盘中读取数据要快很多,增加linux内核预读,对于大量顺序读取的操作,可以有效减少I/O的等待时间。该参数值建议在实际环境中测试再决定设置多大值。
磁盘预读可以改善顺序读的性能,并且测试发现每个读请求的大小也受预读大小的影响,也就是发生了 IO 合并。
Linux的文件预读readahead,指Linux系统内核将指定文件的某区域预读进页缓存起来,便于接下来对该区域进行读取时,不会因缺页(page fault)而阻塞。因为从内存读取比从磁盘读取要快很多。预读可以有效的减少磁盘的寻道次数和应用程序的I/O等待时间,是改进磁盘读I/O性能的重要优化手段之一。
查看和配置
可以使用blockdev来查看或配置磁盘预读的值。
blockdev用法:
1 2 3 | blockdev -V blockdev --report [设备] blockdev [-v|-q] 命令 设备 |
可用命令有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | --getsz 获得 512-字节扇区的大小 --setro 设置只读 --setrw 设置读写 --getro 获得只读 --getdiscardzeroes 获取 忽略零数据 支持状态 --getss 获得逻辑块(扇区)大小 --getpbsz 获得物理块(扇区)大小 --getiomin 获得最小 I/O 大小 --getioopt 获得最优 I/O 大小 --getalignoff 获得对齐偏移字节数 --getmaxsect 获得每次请求的最大扇区数 --getbsz 获得块大小 --setbsz <bytes> set blocksize on file descriptor opening the block device --getsize 获得 32-bit 扇区数量(已废弃,请使用 --getsz) --getsize64 获得字节大小 --setra <sectors> 设置 readahead --getra 获取 readahead --setfra <sectors> 设置文件系统 readahead --getfra 获取文件系统 readahead --flushbufs 刷新缓存 --rereadpt 重新读取分区表 |
通过如下命令查看disk的预读设置:
1 2 3 4 | [root@docker35 ~]# /sbin/blockdev --getra /dev/sda 8192 [root@docker35 ~]# cat /sys/class/block/sda/queue/read_ahead_kb 4096 |
请注意,8192的单位是个,也就是8192个sectors(扇区),而上面4096的单位是KB,其中8192sectors*512bytes/1024=4096KB
查看所有disk:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [root@docker35 ~]# blockdev --report RO RA SSZ BSZ StartSec Size Device rw 8192 512 4096 0 536870912000 /dev/sda rw 8192 512 4096 2048 11059331072 /dev/sda1 rw 8192 512 512 21602304 31889293312 /dev/sda2 rw 8192 512 4096 83886080 21474836480 /dev/sda3 rw 8192 512 1024 125829120 1024 /dev/sda4 rw 8192 512 4096 125831168 21474836480 /dev/sda5 rw 8192 512 4096 167776256 21474836480 /dev/sda6 rw 8192 512 4096 209721344 21474836480 /dev/sda7 rw 8192 512 4096 251666432 21474836480 /dev/sda8 rw 8192 512 4096 293611520 21474836480 /dev/sda9 rw 8192 512 4096 335556608 21474836480 /dev/sda10 rw 8192 512 4096 377501696 21467496448 /dev/sda11 rw 8192 512 4096 0 1099511627776 /dev/sdb rw 8192 512 4096 2048 214748364800 /dev/sdb1 rw 8192 512 4096 419432448 214748364800 /dev/sdb2 rw 8192 512 4096 838862848 214748364800 /dev/sdb3 rw 8192 512 1024 1258293248 1024 /dev/sdb4 rw 8192 512 4096 1258295296 214748364800 /dev/sdb5 rw 8192 512 4096 1677727744 214748364800 /dev/sdb6 rw 8192 512 4096 2097160192 25765609472 /dev/sdb7 rw 256 512 512 0 1073741312 /dev/sr0 rw 8192 512 4096 0 1099511627776 /dev/dm-0 |
上面第二列RA列的单位是个,也就是这么多个sectors.
设置sda的预读为16484,单位是sectors.
1 2 3 | [root@rhel78 ~]# /sbin/blockdev --setra 16384 /dev/sda [root@rhel78 ~]# /sbin/blockdev --getra /dev/sda 16384 |
值得注意,当存储环境中用到多路径聚合软件时,请修改多路径聚合软件聚合之后的磁盘名称,如下是举例:
1 | /sbin/blockdev --setra 16384 /dev/<multipath device> |
通过上面的修改可以看到,修改会立即生效,但是这么设置重启OS后会失效,因此,建议建立udev规则来保证重启OS后不会失效。
1 2 3 4 5 6 7 8 9 | [root@rhel78 ~]# cat /etc/udev/rules.d/99-custom.rules SUBSYSTEM!="block", GOTO="end_rule" ENV{DEVTYPE}=="partition", GOTO="end_rule" ACTION!="add|change", GOTO="end_rule" ENV{ID_SERIAL}=="36000c2939dfa82377c155d4b4a8d0acd", ATTR{queue/read_ahead_kb}="8192" LABEL="end_rule" [root@rhel78 ~]# udevadm trigger --action="add" |
注意,在上面的输出中36000c2939dfa82377c155d4b4a8d0acd是sda的WWID。8192是sda的预读大小,KB为单位。
另外,也可以命令写入配置文件/etc/rc.local,否则重启就会失效。
参考
https://www.cnblogs.com/dkblog/archive/2011/11/10/2244631.html
https://blog.csdn.net/kunyus/article/details/104620057
https://www.cnblogs.com/kerrycode/p/4743015.html