顺序读性能调优
VMM 的顺序预读功能能够改进需要顺序访问大文件的程序的性能。
下面的插图展示了典型的预读的情况。
顺序预读的例子. 插图显示了用一行块模拟一分段磁道的文件页号。这些块段按 0,1 到 3,4 到 7,8 到 15 以及 16 到 23 编号。顺序预读的步骤可以在紧接着插图后的文本中找到。
在这个例子中,minpgahead 的值为 2,maxpgahead 的值为 8 (缺省值)。程序顺序处理文件。图中只显示了对预读机制有重要作用的数据引用(按从 A 到 F 的顺序标出)。这些步骤是:
A
第一次文件访问读取文件的第一页(第 0 页)。在这个时候,VMM 并不知道这次访问是随机还是顺序访问。
B
当程序访问下一页(第 1 页)的首字节而不存在对文件其它页的插入访问时,VMM 推断出该程序正在进行顺序访问。于是将页提前量设为 minpgahead (2) 并且调度读取额外的页(第二、三页)。这样步骤 B 总共读取了 3 页。
C
当程序访问预读的第一页(第 2 页)的首字节时,VMM 将页提前量加倍到 4 并且调度读取第 4 到 7 页。
D
当程序访问前次预读的第一页(第 4 页)的首字节时,VMM 将页提前量加倍到 8 并且调度读取第 8 到 15 页。
E
当程序访问前次预读的第一页(第 8 页)的首字节时,VMM 决定将页提前量设为 maxpgahead 并且调度读取第 16 到 23 页。
F
VMM 在程序访问前一组预读页的首字节的情况下继续预读 maxpgahead 页直到文件结尾。
一旦程序偏离了顺序访问模式并且不按次序访问了文件中的一页,顺序预读就会终止。当 VMM 检测到程序恢复顺序访问后,页提前量便会恢复到 minpgahead 页。
可在 ioo 命令中使用 -r 和 -R 选项来更改 minpgahead 和 maxpgahead 的值。如果您打算改变这些值,请记住:
该值必须是集合:0、1、2、4、8、16 等中的一个。使用其它值可能会对性能或功能造成不利影响。
o 由于 VMM 的加倍算法,该值应该是 2 的幂。
o 大于 16 的 maxpgahead 值(预读量大于 64 KB)会超出某些磁盘设备驱动程序的能力。在这种情况下,预读的大小会保持在 64 KB。
o 更大的 maxpgahead 值可用于条带状逻辑卷的顺序性能显得至关重要的系统中。
minpgahead 和 maxpgahead 的值都为 0 能有效消除此机制。这会给性能带来负面影响。但是,在 I/O 随机的一些情况下,这可能也有用处,这时 I/O 的大小会使预读算法生效。
对于非条带状文件系统,当 maxpgahead 值为 8 或 16 时,其顺序 I/O 性能会达到可能的最大值。
预读值从 minpgahead 增加到 maxpgahead 的过程很快,对于大多数文件大小来说增大 minpgahead 值都不会带来任何性能的提高。
可以针对 JFS 和增强型 JFS 分别调优顺序预读功能。JFS 的预读页可以通过改变 minpgahead 和 maxpgahead 的值调优,而增强型 JFS 使用 j2_minPageReadAhead 和 j2_maxPageReadAhead。
顺序和随机后写性能调优
后写涉及在达到某个阈值后将内存中修改过的页面异步写到磁盘上,而不是等待 syncd 守护程序将页面清空到磁盘上。这被用于限制内存中的脏页数,减少系统开销和最小化磁盘碎片。后写有两种类型:顺序后写和随机后写。
顺序后写
缺省情况下,一个 JFS 文件划分成 16 KB 大小的分区或 4 页。每一个这样的分区被称为一簇。如果该簇中的 4 页都是脏页,那么一旦修改完下一个分区,系统就会调度该簇中的 4 页并将其写入磁盘。如果不具备这一功能,则直到 syncd 守护程序运行前,该页都会留存于内存,导致可能的 I/O 瓶颈和文件碎片。
VMM 用于充当阈值的簇数是可调优的。缺省值是一簇。使用 ioo -o numclust 命令来增加 numclust 参数可以延迟后写。
对于增强型 JFS,ioo -o j2_nPagesPerWriteBehindCluster 命令用来指定每次调度的页数,而不是簇数。增强型 JFS 簇的缺省页数为 32,意味着增强型 JFS 的缺省大小为 128 KB。
随机后写
可能存在一些应用程序执行大量的随机 I/O,即 I/O 模式不满足后写算法的要求,因而导致所有页面驻留在内存中,直到 syncd 守护程序运行为止。如果应用程序在内存中修改了许多页,就有可能在 syncd 守护程序调用 sync() 时向磁盘写入大量页。
后写功能提供了这样一种机制,即当给定文件在内存中的脏页数超过规定阈值后,则会调度所写的后续页面以写到磁盘上。
通过使用 ioo 命令并带有 JFS maxrandwrt 参数可调整此阈值。缺省值为 0,表示随机后写是禁用的。将该值增加到 128 表示一旦文件驻留于内存的页达到 128 页,随后的任何脏页都将被调度写入磁盘。而这些页将在调用 sync() 后刷新。
对于增强型 JFS,ioo 命令选项 j2_nRandomCluster(-z 标志)和 j2_maxRandomWrite(-J 标志)用来调优随机后写。增强型 JFS 的 j2_maxRandomWrite 选项和 JFS 的 maxrandwrt 选项功能相同。即它限定了每个文件可以留在内存中的脏页数。j2_nRandomCluster 选项指定了可以被视为随机的两次连续写入之间的簇数。
异步磁盘 I/O 性能调优
如果应用程序进行同步 I/O 操作,它必须等待 I/O 完成后才能继续执行。相反,异步 I/O 操作在后台运行,不会阻塞用户应用程序。这就改进了性能,因为 I/O 操作和处理中的应用程序可以同时运行。许多应用程序,诸如数据库和文件服务器,利用了重叠处理和重叠 I/O 的能力。
应用程序可以使用 aio_read() 命令、aio_write() 或 lio_listio() 子例程(或它们的副本)来执行异步磁盘 I/O。一旦请求被排队,控制权就从子例程返回应用程序。当磁盘操作被执行时,应用程序可以继续处理。
为了管理异步 I/O,每一个异步 I/O 请求在应用程序地址空间有一个相应的控制块。该控制块包含了请求的控制和状态信息。在 I/O 操作完成后可以被再次使用。
在发出了一个异步 I/O 请求,用户应用程序可以决定何时并以何种方式结束 I/O 操作。这些信息在以下三种方式的任何一种中提供:
应用程序可以轮询 I/O 操作的状态。
当 I/O 操作完成后系统可以异步通知应用程序。
应用程序可以阻塞,直到 I/O 操作完成。
每个 I/O 是由单个 kproc 处理,并且一般来说 kproc 不能处理任何更多的队列中的请求,直到 I/O 已经完成。当异步 I/O 启用时,缺省的配置好的服务器最小数目为 1。这是 minservers 属性。还存在一个可以创建的最大异步 I/O 服务器数,它由 maxservers 属性控制,缺省值为 10(每个 CPU)。服务器的数量限制了可以在系统中同时处理的异步磁盘 I/O 操作的数目。服务器数可用 SMIT 命令(smitty -> 设备 -> 异步 I/O -> 更改/显示异步 I/O 的特征 -> {MINIMUM | MAXIMUM} 服务器数目或 smitty aio)或者使用 chdev 命令来设置。
很少运行应用程序的系统可以使用异步 I/O,缺省值通常可以勉强够用。
如果异步 I/O 请求数目是高的,那么推荐您增加 maxservers 大约至同时 I/O 可能的数目。在大多数情况下,您最好保留 minservers 参数为缺省值,因为如果需要的话,AIO 内核扩展将生成附加的服务器数。
注:
执行在裸逻辑卷上的 AIO 操作并不使用 kproc 服务器进程。有关 maxservers 和 minservers 的设置在这种情况下没有效果。
通过查看 AIO 服务器的 CPU 利用率,如果利用率在它们中间均匀的分配,那就意味着它们都在使用中;在这种情况下,您可能要增加它们的数量。以名称查看 AIO 服务器,运行 pstat -a 命令。运行 ps -k 命令来查看名称为 kproc 的 AIO 服务器。
在异步磁盘 I/O 的性能很重要并且卷请求很高,而你又没有一个适当的同步 I/O 数量的环境下,建议把 maxservers 至少设置为 10(异步存储磁盘的数)。
对系统来说可以通过三个异步存取磁盘获得,如下所示:
# chdev -l aio0 -a maxservers='30'
此外,您可以设置未完成异步 I/O 请求的最大值以及服务器的优先级。如果您的系统拥有大量的异步 I/O 应用程序,那就可以适当地增加请求数以及降低优先级数目。
文件同步性能调优
JFS 的非顺序文件 I/O 会一直存储在内存中直到满足一定条件:
空闲列表缩小到 minfree,以致需要进行页替换。
syncd 守护程序按固定调度间隔刷新页。
执行了 sync 命令。
随机后写在达到随机后写阈值后清空脏页面。
如果在以上的任一条件满足前已存储了过多页,则在 syncd 守护程序进行刷新时,会获得一个 i-node 锁并保持到所有的脏页都被写入磁盘。在这段时间里,任何试图访问此文件的线程会由于无法获得 i-node 锁而被阻塞。请记住:syncd 守护程序会顺利的刷新一个文件中的所有脏页,但限于一次一个文件。在一个拥有大量内存并同时有大量页需要修改的系统中,syncd 守护程序刷新页时 I/O 可能达到高峰值。
AIX 有一个称为 sync_release_ilock 的可调选项。ioo 命令加上 -o sync_release_ilock=1 选项允许在清空该文件的脏页面后释放 i-node 锁。这一选项使得在调用 sync() 的过程中访问该文件有更好的响应。
阻塞效果也可通过在 syncd 守护程序中提高同步频率使之最小化。更换用于启用 syncd 守护程序的 /sbin/rc.boot。然后重新引导系统使之生效。对现行系统,杀死 syncd 守护程序进程并按新的值重新启动守护程序。
第三种调优这种行为的方法是使用 ioo 命令开启随机后写功能
文件系统缓冲区调优
以下 ioo 参数可用于调优磁盘 I/O:
numfsbufs 参数
当有大量针对文件系统的同步或大型 I/O 或是存在针对文件系统的大型顺序 I/O 时,这些 I/O 可能会在等待 bufstruct 时成为文件系统级的瓶颈。每个文件系统的 bufstructs 数目(称为 numfsbufs)可使用 ioo 命令增加。该值仅在文件系统加载后才会生效;因此如果更改了这个值,则必须卸载然后再次加载文件系统。numfsbufs 的缺省值目前为每个文件系统 93 个 bufstruct。
j2_nBufferPerPagerDevice 参数
在增强型 JFS 中,bufstruct 数量由参数 j2_nBufferPerPagerDevice 指定。当前增强型 JFS 文件系统的缺省 bufstruct 数是 512。每个增强型 JFS 文件系统的 bufstructs 数(j2_nBufferPerPagerDevice)可以使用 ioo 命令来增加。该值在文件系统被加载后才起作用。
lvm_bufcnt 参数
如果应用程序正在处理很大量的裸 I/O 而不通过文件系统,同文件系统相同类型的瓶颈也可能出现在 LVM 层上。极大量的 I/O 加上极快的 I/O 设备可能会导致 LVM 层上的瓶颈。但是如果真的出现瓶颈,则可以通过 ioo 命令增加 lvm_bufcnt 参数,以提供大量的“uphysio”缓冲区。该值会立刻生效。当前的缺省值是 9 个 “uphysio” 缓冲区。由于当前 LVM 将 I/O 分为每个 128 K,而 lvm_bufcnt 的缺省值为 9,故一次可写入 9*128 K。如果正在进行的 I/O 大于 9*128 K,增加 lvm_bufcnt 的值才会有利。
hd_pbuf_cnt 参数
hd_pbuf_cnt 参数控制可用于 LVM 设备驱动程序的 pbufs 数。pbuf 是用于存放暂挂于 LVM 层的 I/O 请求的固定内存缓冲区。
在 AIX 中,顺序 I/O 的结合使得无论 I/O 包括多少页,每个顺序 I/O 请求只使用单个 pbuf。这种类型的瓶颈一般很难遇到。而对于随机 I/O,除非运行 syncd 守护程序,I/O 一般会被零星地刷新。
确定是否发生 pbuf 瓶颈的最好方法是检查称为 hd_pendqblked 的 LVM 变量。以下的脚本会给出该变量的值:
#!/bin/ksh
# requires root authority to run
# determines number of times LVM had to wait on pbufs since system boot
addr=`echo "knlist hd_pendqblked" | /usr/sbin/crash 2>/dev/null |tail -1| cut -f2 -d:`
value=`echo "od $addr 1 D" | /usr/sbin/crash 2>/dev/null | tail -1| cut -f2 -d:`
echo "Number of waits on LVM pbufs are: $value"
exit 0
ioo -a 命令也会显示 hd_pendqblked 值。
注:
请不要把 hd_pbuf_cnt 值设得太大,因为除了重新引导系统无法减小该值。
pd_npages 参数
pd_npages 参数指定当删除文件时 RAM 的某一块中应该删除的页数。改变此值只对那些需要删除文件的实时应用程序才有用。由于在分派某个进程/线程之前将删除少量的页面,因此通过减小 pd_npages 参数的值,实时应用程序可获得更快的响应时间。缺省值是最大可能文件大小除以页面大小(目前为 4096);如果最大可能文件大小为 2 GB,则 pd_npages 参数的值缺省为 524288。
v_pinshm 参数
当 v_pinshm 参数设置为 1 时,如果执行 shmget() 的应用程序指定 SHM_PIN 作为标志的一部分,就会使共享内存段中的页面由 VMM 固定。缺省值为 0。
应用程序可以选择提供某种可调优性:指定应用程序是否应该使用 SHM_PIN 标志(例如: Oracle 8.1.5 及以上版本中提供的 lock_sga 参数)。请避免固定过多的内存,因为在这种情况下无法进行页替换。由于节约了这些共享内存段的异步 I/O 开销(不需要异步 I/O 内核扩展来固定缓冲区),因此这种固定是很有用的。
fsbufwaitcnt 和 psbufwaitcnt 计数器
只要 bufstruct 变得不可用以及 VMM 将一个线程放入 VMM 等待列表中,fsbufwaitcnt 和 psbufwaitcnt 计数器就会递增。使用 crash 命令或 ioo -a 命令的 fsbufwaitcnt 和 psbufwaitcnt 选项来检查这些计数器的值。下面是输出的示例:
# ioo -a
hd_pendqblked = 305
psbufwaitcnt = 0
fsbufwaitcnt = 337
xpagerbufwaitcnt 计数器
只要增强型 JFS 文件系统上的 bufstruct 不可用,xpagerbufwaitcnt 就会递增。可使用 ioo -a 命令检查 xpagerbufwaitcnt 计数器的值。下面是输出的示例:
# ioo -a
xpagerbufwaitcnt = 815
直接 I/O 调优
当您在对文件进行正常的 I/O 处理时,I/O 在应用程序缓冲区和 VMM 之间来回进行。在缓冲区中的内容通过 VMM 把实存作为文件缓冲区的高速缓存的使用而高速缓存于 RAM 中。如果文件高速缓存命中率很高,那么这个高速缓存的类型在提高 I/O 的总体性能上将十分有效。但是高速缓存命中率很低的应用程序或者执行大量 I/O 的应用程序也许不会从正常的高速缓存 I/O 使用中得到很多好处。
直接 I/O 的主要益处在于通过消除从 VMM 文件高速缓存到用户缓存的副本来减少 CPU 对文件读操作和写操作的使用率。如果高速缓存命中率低,那么大多数读取请求不得不转向磁盘。写操作在大多数情况下使用正常高速缓存 I/O 要更快。但是如果文件是以 O_SYNC 或 O_DSYNC打开的,那么写操作将不得不转向磁盘。在这种情况下,直接 I/O 可能使应用程序获益,因为数据的副本被消除了。
另一个益处是直接 I/O 可以允许应用程序避免稀释高速缓存对其他文件的效能。当一个文件被读取或写入时,该文件竞争内存空间,有可能引起其他文件数据被推出内存。如果一个应用程序开发者知道某些文件有较低的高速缓存利用率特征,那么只有那些文件可以用 O_DIRECT 打开。
为了让直接 I/O 有效地工作,I/O 请求适用于正被使用的文件系统的类型。finfo() 和 ffinfo() 子例程可以用来查询偏移量、长度以及固定块大小文件系统、碎片文件系统和大文件文件系统有关对地址校正的需求(直接 I/O 没有支持压缩文件系统)。查询到的信息包含于 diocapbuf 结构中,该结构在 /usr/include/sys/finfo.h 文件中描述。
为了避免一致问题,如果有多个调用用来打开文件并且一个或多个调用没有制定 O_DIRECT 而另一个打开操作指定了 O_DIRECT,那么文件将保留于正常高速缓存 I/O 模式。同样的,如果文件是通过 shmat() 或 mmap() 系统调用来映射到内存中,它们保留在正常高速缓存模式。如果最后一个冲突,非直接存取被消除,那么文件系统将把文件移入直接 I/O 模式(或者使用 close()、munmap() 或者使用 shmdt() 子例程)。从正常模式到直接 I/O 模式可能代价不小,因为所有在内存中修改过的页面将不得不在那点上刷新磁盘。
直接 I/O 读操作的性能
即使使用直接 I/O 可能减少 CPU 的使用,但很有可能产生更长的消逝时间,特别对小型 I/O 请求而言,因为请求不会在内存中高速缓存。
直接 I/O 读取操作会从磁盘引起同步读操作,然而通过正常的高速缓存策略,读取操作可能会从高速缓存那里得到满意的结果。如果数据在内存中遵循正常高速缓存策略,那么这样可能导致性能低下。直接 I/O 也忽略 VMM 预读算法,因为 I/O 并不通过 VMM。预读算法对顺序存取文件非常有用,因为 VMM 可以启动磁盘请求并且能在应用程序请求页面之前使页面早就驻留在内存中。应用程序可以通过一下方法中的一种补偿预读的损失:
执行读取请求(最小 128 K)
使用多个线程执行异步直接 I/O 预读取。
使用异步 I/O 设施诸如 aio_read() 或者 lio_listio()
直接 I/O 写操作的性能
直接 I/O 写操作绕过 VMM 直接写入磁盘,以致于可能产生严重的性能损失;在正常高速缓存的 I/O 中,写操作可以写入内存,稍后通过 sync 或 write behind 操作清空到磁盘上。由于直接 I/O 写操作并不复制到内存,当一个 sync 操作执行后,它不会必须刷新这些页面,这样一来就减少了 syncd 守护程序必须执行的工作量。
直接 I/O 调优摘要
直接 I/O 本质上比常规 I/O 需要更少的 CPU 周期。 I/O 增强性应用程序不会在常规 I/O 所提供的高速缓存中得到益处,但是可以使用直接 I/O 来增强性能。
作为直接 I/O 的适当候选者的程序通常受 CPU 限制并且执行大量的磁盘 I/O。拥有大量顺序 I/O 的技术应用程序是适当的候选者。执行许多小型 I/O 的应用程序一般来说受到较少的性能益处,因为直接 I/O 不能预读或后写。受益于条带区的应用程序同样是不错的候选者。