《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #19 ext4的调整

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

时间: 2024-09-20 06:05:43

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

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

HACK #1 如何获取Linux内核 本节介绍获取Linux内核源代码的各种方法. "获取内核"这个说法看似简单,其实Linux内核有很多种衍生版本.要找出自己想要的源代码到底是哪一个,必须首先理解各种衍生版本的意义. 接下来将简单介绍Linux内核的开发模式,并分析各种衍生版本在其中所处的地位,然后介绍获取这些衍生版本的源代码的方法. 内核的种类 想要获取正确的Linux内核源代码,首先必须了解Linux内核的开发模式. Linux内核是由多个开发者以分散型的模式进行开发的.这里出

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

HACK #15 ramzswap 本节介绍将一部分内存作为交换设备使用的ramzswap. ramzswap是将一部分内存空间作为交换设备使用的基于RAM的块设备.对要换出(swapout)的页面进行压缩后,不是写入磁盘,而是写入内存.可以使用的内存仅为完成压缩的部分.压缩处理使用的是LZO注1. ramzswap是从Linux 2.6.33合并到Staging驱动程序的.Staging驱动程序是指尚未达到某种程度的质量的试验性驱动程序. 通过使用ramzswap,运转速度可以比换出到一般磁盘

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

HACK #3 如何编写内核模块 本节将介绍向Linux内核中动态添加功能的结构-内核模块的编写方法. 内核模块 Linux内核是单内核(monolithic kernel),也就是所有的内核功能都集成在一个内核空间内.但是内核具有模块功能,可以将磁盘驱动程序.文件系统等独立的内核功能制作成模块,并动态添加到内核空间或者删除. 内核模块是可以动态添加到Linux内核空间的二进制文件,文件扩展名为ko. 内核模块的编写方法大致有两种.一种是将内核源码树带有的功能编写为模块的方法(参考Hack #2

《Linux内核精髓:精通Linux内核必会的75个绝技》一导读

前 言 内核是操作系统的核心,操作系统的基本功能都是由内核提供的.文件生成和数据包传输等也是通过内核的功能实现的.但这些都不是简单的任务.平时可能意识不到,但这其中确实包含了很多先进技术.例如,在文件系统方面,配置文件时尽量减少磁盘扫描,在网络方面,由于路由表的入口数量庞大,因此设计时尽量保证对系统整体影响较小的设计.在内存管理.进程管理方面也作出了很多努力.解读这种先进技术也是内核构建的魅力之一. 然而,最近的Linux所提供的并不只有基本功能.随着功能的不断发展,现在已经出现了很多特定领域的

《Linux内核精髓:精通Linux内核必会的75个绝技》一第1章 内核入门

第1章 内核入门 一提起内核包,总会让人感觉似乎困难至极.如临深渊一般.但其基本的操作与其他开放源代码软件包并没有什么不一样,都是首先获取源代码,进行解读,然后修改或者添加新功能对应的代码,并编译.测试.本章将介绍这些内核包操作中最基础的知识,以及Linux内核特有的方法.

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

HACK #11cpuset 本节介绍控制物理CPU分配的cpuset.cpuset是Linux控制组(Cgroup)之一,其功能是指定特定进程或线程所使用的CPU组.另外,除CPU以外,同样还能指定内存节点的分配.以前的内核具有CPU affinity功能,该功能将线程分配给特定CPU.现在的内核中虽然也有affinity(taskset命令),但推荐使用cpuset.用法使用cpuset前,必须通过内核config启用cpuset功能.CONFIG_CPUSETS=y最近的发布版在标准中就已

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #8 调度策略

HACK #8 调度策略 本节介绍Linux的调度策略(scheduling policy). Linux调度策略的类别大致可以分为TSS(Time Sharing System,分时系统)和实时系统这两种. 一方面,一般的进程是通过分时运行的.也就是说,使用CPU的时间达到分配给进程的时间(时间片)时,就会切换到其他进程.这种分时运行的调度策略称为TSS. 另一方面,在实时制约较严格且要求保证实时的处理中,就需要指定静态的执行优先级,并严格按照执行优先级进行调度.对这种对应答性有要求的进程,可

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #4 如何使用Git

HACK #4 如何使用Git 本节介绍Git的使用方法. Git是Linux内核等众多OSS(Open Source Software,开源软件)开发中所使用的SCM(Source Code Management,源码管理)系统.在2005年以前,在Linux内核开发中一直使用一个叫做BitKeeper的SCM.但是由于后来BitKeeper的许可证被更改,可能会对开发造成障碍,因此Linux不得不改用新的SCM进行开发.在这种情况下,Linux内核的创始人Linus Torvalds就开发了

《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #2 如何编译Linux内核

HACK #2 如何编译Linux内核 本节介绍编译Linux内核的方法. 当发现bug而修改源代码或者添加新功能时,就需要对内核进行重新编译,生成二进制映像文件.另外,如果想要使用发布版内核中无效的功能或者驱动程序时,或者相反地,想要删除不需要的功能从而使内核更精简.更快时,或者想使用最新版的上游内核时,也需要对内核进行编译. 下面主要介绍对上游内核进行设置.编译以及安装的方法.当使用发布版内核的源码包管理系统来管理内核映像文件时,需要将内核映像文件打包.接下来以两个具有代表性的发布版Fedo