HACK #19 ext4的调整

本节介绍可以从用户空间执行的ext4调整。
ext4在sysfs中有一些关于调整的特殊文件(见表3-6)。使用这些特殊文件,就不用进行内核编译、重启,直接从用户空间确认、更改内核空间的设置参数。
表3-6 sysfs中的ext4文件

/sys/fs/ext4/<设备名>下有与文件系统相关的各种文件。表3-6所示为这些文件的说明和默认值的列表。
这里将具体介绍上述文件中最为有效的部分文件。

  1. lifetime_write_kbytes与session_write_kbytes
    lifetime_write_kbytes虽然不是可调整的入口,但是在SSD上生成ext4的情况下有时非常有用。SSD对写入次数有限制。通过磨损平衡(wear leveling)将写入分散化,从而延长了寿命,但掌握目前为止写入文件系统的数据量对于预测SSD寿命也是非常有用的信息。

lifetime_write_kbytes以千字节为单位记录写入文件系统的数据量,session_write_kbytes以千字节为单位记录文件系统挂载后写入的数据量。
下例中展现的就是lifetime_write_kbytes和session_write_kbytes的值。
即使在刚生成ext4后,lifetime_write_kbytes也会显示已有数据写入。这表示执行mkfs时写入的元数据量。而sesson_write_kbytes中记录的是挂载文件系统的处理中产生的数据被写入的信息。

# cat /sys/fs/ext4/sda5/lifetime_write_kbytes
10637 # cat /sys/fs/ext4/sda5/session_write_kbytes
1

在这个ext4上生成100MB的文件。可以看到值分别增加了约100MB。由于元数据的写出也会计数,因此是约100MB。

# dd if=/dev/urandom of=/mnt/mp1/file bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 18.322 s, 5.7 MB/s # cat /sys/fs/ext4/sda5/lifetime_write_kbytes
113099 # cat /sys/fs/ext4/sda5/session_write_kbytes
102463

再次挂载文件系统后,lifetime_write_kbytes的值会有一些增加。这是因为文件系统的挂载处理中有更新的数据(例如,内存上的超级块信息等)写入磁盘。而session_write_kbyte重置为0。

# umount /mnt/mp1
# mount -t ext4 /dev/sda5 /mnt/mp1 # cat /sys/fs/ext4/sda5/lifetime_write_kbytes
113105
# cat /sys/fs/ext4/sda5/session_write_kbytes
1
2. mb_stream_req

ext4中安装了多块分配处理功能,可以降低块分配处理中的CPU成本。可以将多个块分配到物理上连续的区域,提高I/O的效率。
另外,ext4可以使用fallocate系统调用进行块的持久预分配,而多块分配处理中安装的则是内核内部使用的group预分配(下称group PA)和inode预分配(下称inode PA)。
group PA由各CPU分别管理,用来将对象文件块(满足某条件的块)排列到物理上较近的区域,inode PA用来将某一个文件的块排列到物理上连续的区域。
这些预分配算法的切换是如何进行的呢?ext4.h里的下列定义就是其阈值。

#define MB_DEFAULT_STREAM_THRESHOLD    16    /* 64k */

由于是以块数为单位,因此块的大小4KB时阈值为64KB,块的大小为1KB时阈值为16KB。
默认设置表示对于16块以下的块分配处理使用group PA,对于16块以上则使用inode PA。这个值可以使用mb_stream_req来更改。
默认值设置为16块,是因为设置文件等多数文件都在16块(块的大小4KB时阈值为64KB)以内。因此,这些文件通过group PA实现物理上的局部化。在系统启动时等数据读入处理操作中,通过将文件数据局部化,可以缩短磁盘的寻道时间(seek time)。
实际操作mb_stream_req,来验证一下group PA和inode PA的运行和效果。为了便于测定预分配的效果,这次操作中将延迟分配禁用。

# mount -t ext4 -o nodelalloc /dev/sdb5 /mnt/mp1

# cat /proc/mounts  | grep sdb5
/dev/sdb5 /mnt/mp1 ext4
rw,relatime,user_xattr,barrier=1,nodelalloc,data=ordered 0 0

为了使用group PA,将mb_stream_req设置为64,并向文件分配小于这个值的32块。

# echo 64 > /sys/fs/ext4/sdb5/mb_stream_req

# for i in 1 2 3; do dd if=/dev/urandom of=/mnt/mp1/file$i bs=4K count=32 >
/dev/null 2>&1; done # ls -l /mnt/mp1/file*
-rw-r--r-- 1 root root 135168 2011-05-17 01:10 /mnt/mp1/file1
-rw-r--r-- 1 root root 135168 2011-05-17 01:10 /mnt/mp1/file2
-rw-r--r-- 1 root root 135168 2011-05-17 01:10 /mnt/mp1/file3

可以使用e2fsprogsa工具包的fileflag命令来确认分配给磁盘的数据块。根据physical和length显示的值,可以看出通过group PA,把各个文件的数据块排列在物理上相近的位置。

# for i in 1 2 3; do filefrag -v /mnt/mp1/file$i; done

Filesystem type is: ef53
File size of /mnt/mp1/file1 is 131072 (32 blocks, blocksize 4096)
ext logical physical expected length flags
0 0 33280 32 eof
/mnt/mp1/file1: 1 extent found
Filesystem type is: ef53
File size of /mnt/mp1/file2 is 131072 (32 blocks, blocksize 4096)
ext logical physical expected length flags
0 0 33792 32 eof
/mnt/mp1/file2: 1 extent found
Filesystem type is: ef53
File size of /mnt/mp1/file3 is 131072 (32 blocks, blocksize 4096)
ext logical physical expected length flags
0 0 33312 32 eof

然后,为了确认inode PA的运行,再将mb_stream_req设置为16,并向文件分配大于这个值的32块。

# rm -rf /mnt/mp1/file*

# umount /mnt/mp1

# mount -t ext4 -o nodelalloc /dev/sdb5 /mnt/mp1

# echo 16 > /sys/fs/ext4/sdb5/mb_stream_req

# for i in 1 2 3; do dd if=/dev/urandom of=/mnt/mp1/file$i bs=4K count=32 >
/dev/null 2>&1; done # for i in 1 2 3; do filefrag -v /mnt/mp1/file$i; done Filesystem type is: ef53
File size of /mnt/mp1/file1 is 131072 (32 blocks, blocksize 4096)
ext logical physical expected length flags
0 0 33280 16
1 16 33072 33295 16 eof
/mnt/mp1/file1: 2 extents found
Filesystem type is: ef53
File size of /mnt/mp1/file2 is 131072 (32 blocks, blocksize 4096)
ext logical physical expected length flags
0 0 33296 16
1 16 33088 33311 16 eof
/mnt/mp1/file2: 2 extents found
Filesystem type is: ef53
File size of /mnt/mp1/file3 is 131072 (32 blocks, blocksize 4096)
ext logical physical expected length flags
0 0 33792 16
1 16 33104 33807 16 eof
/mnt/mp1/file3: 2 extents found

在多于mb_stream_request的块分配处理中,将使用inode PA。inode PA只在引用对象文件期间保留有效的预分配块。从而在按顺序向对象文件写入时,把块分配到物理上连续的区域,抑制碎片的产生。要注意的是,inode PA在块分配中并不是每次都会生成,而是只在多块分配处理中获取的连续空闲块与要求的块数之间有差异时使用。例如,对于16块的分配要求,当多块分配处理检索到连续空闲块有16个时,就不会生成inode PA。
在上述块分配中不生成inode PA,file1的第一个范围(extent)是从物理偏移量33 280分配16块,而从其后的物理偏移量33 296分配的是file2的第一个范围的块。这样就会产生碎片注5。
为了避免产生碎片,文件系统上就必须有足够的连续空闲块。使用e2fsprogs工具包中包含的e2freefrag命令来确认有多少连续的空闲块。在下例中,Extent Size Range越大,在整体中所占的比例越大,可见这个文件系统上有充足的连续空闲块。

# e2freefrag /dev/sdb5

Device: /dev/sdb5
Blocksize: 4096 bytes
Total blocks: 1220703
Free blocks: 1166377 (95.5%) Min. free extent: 40 KB
Max. free extent: 917504 KB
Avg. free extent: 358884 KB
Num. free extent: 13 HISTOGRAM OF FREE EXTENT SIZES:
Extent Size Range : Free extents Free Blocks Percent
32K... 64K- : 2 20 0.00%
64M... 128M- : 2 49102 4.21%
128M... 256M- : 5 326180 27.97%
512M... 1024M- : 4 791075 67.82%

产生的碎片可以使用e4defrag命令来消除。发布版(例如Fedora 14)的e2fsprogs工具包中还未收入e4defrag命令。在使用时就需要获取由Git管理的e2fsprogs工具包。使用git命令获取e2fsprogs的方法请参考HACK #17注6。
下面是执行e4defrag命令的示例。可以看出原来有17个的文件碎片已消除。

# e4defrag -v  /mnt/mp1/file1
ext4 defragmentation for /mnt/mp1/file1
[1/1]/mnt/mp3/file1: 100% extents: 17 -> 1 [ OK ]
Success: [1/1]

上文介绍了更改mb_stream_request的值时块的分配的差异。通过切换group PA、inode PA,就可以在文件系统上对文件进行布局。有时还可以提高顺序读入中的I/O性能。

  1. inode_readahead_blks
    使用inode_readahead_blks可以控制进行预读的inode表的数量。inode表是指磁盘上储存inode结构的区域,被分配给各块组。与下列flex_bg标志同时使用,就可以提高运行效率。

下例输出的是启用/禁用功能标志flex_bg时inode表的位置。
启用flex_bg

# mke2fs -t ext4 /dev/sda4; dumpe2fs /dev/sda4 | egrep "Group|Inode table"
dumpe2fs 1.41.14 (22-Dec-2010)
Group 0: (Blocks 0-32767) [ITABLE_ZEROED]
Primary superblock at 0, Group descriptors at 1-1
Inode table at 332-833 (+332)
Group 1: (Blocks 32768-65535) [INODE_UNINIT, ITABLE_ZEROED]
Backup superblock at 32768, Group descriptors at 32769-32769
Inode table at 834-1335 (bg #0 + 834)
Group 2: (Blocks 65536-98303) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
Inode table at 1336-1837 (bg #0 + 1336)
Group 3: (Blocks 98304-131071) [INODE_UNINIT, ITABLE_ZEROED]
Backup superblock at 98304, Group descriptors at 98305-98305
Inode table at 1838-2339 (bg #0 + 1838)
...

禁用flex_bg

# mke2fs -t ext4 -O ^flex_bg /dev/sda4; dumpe2fs /dev/sda4 | egrep "Group|Inode table"
dumpe2fs 1.41.14 (22-Dec-2010)
Group 0: (Blocks 0-32767) [ITABLE_ZEROED]
Primary superblock at 0, Group descriptors at 1-1
Inode table at 302-803 (+302)
Group 1: (Blocks 32768-65535) [INODE_UNINIT, ITABLE_ZEROED]
Backup superblock at 32768, Group descriptors at 32769-32769
Inode table at 33070-33571 (+302)
Group 2: (Blocks 65536-98303) [INODE_UNINIT, BLOCK_UNINIT, ITABLE_ZEROED]
Inode table at 65538-66039 (+2)
Group 3: (Blocks 98304-131071) [INODE_UNINIT, ITABLE_ZEROED]
Backup superblock at 98304, Group descriptors at 98305-98305
Inode table at 98606-99107 (+302)
...

启用flex_bg时,“Inode table at”显示的物理块编号连续,可以看出各块组的inode表排列在物理上连续的区域。
flex_bg在标准设置中是将每16块组的元数据集中在一处。因此,各块组的inode表按照0~15、16~31的单位集中在一处。
因此不启用flex_bg时,有时即使为inode_readahead_blks设置较大的值,inode表的区域也并不连续,因此没有什么意义。
在连续访问多个文件的处理中,可以将inode_readahead_blks设置较大的值,一次读入大量inode表,这样效率更高。
在下面这个极端的例子中,将inode_readahead_blks分别设置为1和4096时的内核源代码读入时间进行了比较。启用ext4的flex_bg。
当inode_readahead_blks为1时

# time find /mnt/mp1/linux-2.6.39-rc1 -type f -exec cat > /dev/null {} \;
real 3m36.599s
user 0m5.092s
sys 0m43.510s

当inode_readahead_blks为4096时

# time find /mnt/mp1/linux-2.6.39-rc1 -type f -exec cat > /dev/null {} \;
real 3m23.613s
user 0m5.080s
sys 0m43.341s

执行时间的差异为约6%。根据运用环境的不同也会有一些差异,在经常需要连续读取多个文件的环境下,就可以通过更改inode_readahead_blks来提高读入性能。
小结
本章介绍了使用sysfs的ext4调整。可以从用户空间对内核参数进行操作,非常方便。
如果在ext4的源代码中发现了其他可以从用户空间进行调整的项目,请尝试向邮件地址列表投稿。对于新的结构或功能会有积极的参考作用,这时如果有补丁的话一定会得到很多反馈。
参考文献
Ext4 (and Ext2/Ext3)Wiki
https://ext4.wiki.kernel.org/index.php/Main_Page
Mailing list ARChives
http://marc.info/?l=linux-ext4&r=1&w=2
—Akira Fujita

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #19 ext4的调整的更多相关文章

  1. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #1 如何获取Linux内核

    HACK #1 如何获取Linux内核 本节介绍获取Linux内核源代码的各种方法.“获取内核”这个说法看似简单,其实Linux内核有很多种衍生版本.要找出自己想要的源代码到底是哪一个,必须首先理解各 ...

  2. 《Linux内核精髓:精通Linux内核必会的75个绝技》目录

    1章 内核入门HACK #1 如何获取Linux内核HACK #2 如何编译Linux内核HACK #3 如何编写内核模块HACK #4 如何使用GitHACK #5 使用checkpatch.pl检 ...

  3. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #15 ramzswap

    HACK #15 ramzswap 本节介绍将一部分内存作为交换设备使用的ramzswap.ramzswap是将一部分内存空间作为交换设备使用的基于RAM的块设备.对要换出(swapout)的页面进行 ...

  4. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #11cpuset

    HACK #11cpuset 本节介绍控制物理CPU分配的cpuset.cpuset是Linux控制组(Cgroup)之一,其功能是指定特定进程或线程所使用的CPU组.另外,除CPU以外,同样还能指定 ...

  5. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #3 如何编写内核模块

    HACK #3 如何编写内核模块 本节将介绍向Linux内核中动态添加功能的结构—内核模块的编写方法.内核模块Linux内核是单内核(monolithic kernel),也就是所有的内核功能都集成在 ...

  6. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #21FUSE

    HACK #21FUSE 本节将介绍使用用户进程的文件系统框架—FUSE.FUSE概要FUSE(Filesystem in Userspace,用户空间文件系统),是用来生成用户空间的一般进程的框架. ...

  7. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #20 使用fio进行I/O的基准测试

    HACK #20 使用fio进行I/O的基准测试 本节介绍使用fio进行模拟各种情况的I/O基准测试的操作方法.I/O的基准测试中有无数需要考虑的因素.是I/O依次访问还是随机访问?是通过read/w ...

  8. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #17 如何使用ext4

    HACK #17 如何使用ext4 本节介绍ext4的编写和挂载方法.开发版ext4的使用方法.ext4是ext3的后续文件系统,从Linux 2.6.19开始使用.现在主要的发布版中多数都是采用ex ...

  9. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #16 OOM Killer的运行与结构

    HACK #16 OOM Killer的运行与结构(1) 本节介绍OOM Killer的运行与结构. Linux中的Out Of Memory(OOM) Killer功能作为确保内存的最终手段,可以在 ...

随机推荐

  1. PHP中redis的使用

    redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合).这些数据类 ...

  2. 3.2 shell输入输出

    shell输入与输出: read : read语句可以从键盘或者文件的某一行文本中读入信息,并将其赋值给一个变量. read  var1  var2  ...    若只指定了一个变量,那么read将 ...

  3. dos命令批处理发送文字到剪贴板

     方法一(推荐): echo 要发送到剪贴板的字 | clip   方法二: @echo off::显示要发送的文字重定向到windows临时文件夹下echo 要发送到剪贴板的字>%system ...

  4. LG2023 [AHOI2009]维护序列

    题意 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数 ...

  5. leetcode:Reverse Integer【Python版】

    1.在进入while之前,保证x是非负的: 2.符号还是专门用flag保存 =================== 3.另一思路:将integer转换成string,然后首位swap,直至中间: cl ...

  6. nodejs express 学习

    nodejs的大名好多人应该是听过的,而作为nodejs web 开发的框架express 大家也应该比较熟悉. 记录一下关于express API 的文档: express() 创建express ...

  7. echarts 知识点

    echarts map 禁止放大缩小,设置 calculable 为 false 即可. calculable: false echarts 报错: There is a chart instance ...

  8. ElementUI 知识点

    类型是number的el-input 去掉滚轮事件: @mousewheel.native.prevent <el-input type="number" @mousewhe ...

  9. bzoj 4556 [Tjoi2016&Heoi2016]字符串——后缀数组+主席树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4556 本来只要查 ht[ ] 数组上的前驱和后继就行,但有长度的限制.可以二分答案解决!然后 ...

  10. Angular 4 路由介绍

    Angular 4 路由 1. 创建工程 ng new router --routing 2. 创建home和product组件 ng g component home ng g component ...