Document #: 2411063000000
Body:
[标题]
使用AIX 并行I/O (Concurrent I/O) 来提高数据库的性能
内容提要:
AIX 5L v5.2.0.10( 或称作AIX 5L v5.2 ML01) 在增强的日志文件系统(JFS2) 上引入了并行I/O (Concurrent I/O) 的新的功能。在许多应用环境下,这一新的功能可提高文件系统访问的性能,尤其对于关系型数据库的应用。在JFS2 的文件系统上采用并行I/O (Concurrent I/O) 技术后,可以得到与采用裸设备相似的性能。本文将对并行I/O (Concurrent I/O) 做一个简要的介绍并给出在Oracle 9i 数据库上进行性能比较的结果。
说明:
1. 简介
文件系统长久以来一直是
UNIX 存储管理的核心,
UNIX 的用户通过系统命令和系统接口对存储在文件系统上的数据进行操作和管理。文件系统的使用提供了对数据进行存储的有效手段。
如
同使用其它方式一样,文件系统的使用是对于性能与易用性平衡的结果。在应用和磁盘之间传输数据最快的方式是直接进行访问,如使用裸设备。而使用文件系统
来存数数据会产生很多额外开销,如串行访问,缓存和数据拷贝。这些都将对性能产生影响。使用裸设备进行数据的存储虽然能减少这些额外开销,但对用户的技术
水平要求较高,而且不同应用程序对裸设备的使用方式也不同,需要对用户进行额外的培训。但由于对裸设备进行访问的高性能,传统上来说,数据库的应用程序更
希望使用裸设备而不是文件系统。
在
JFS2 文件系统上采用
并行I/O(Concurrent I/O) 技术后,数据库用应用可以得到与采用裸设备相似的性能。
2. 数据库应用
对于数据库应用来说,之所以采用裸设备比采用文件系统具有更好的
I/O 性能,主要是由于文件系统的一些特性:
l 文件缓存
l 文件写保护锁或
inode 锁
l 系统的
sync 进程
这些文件系统的特性可以帮助保护数据的一致性,提高容错能力,事实上在许多情况下提高系统的性能。然而这些特性却经常对于数据库的应用的性能产生负面的影响。本文将解释文件系统中这些特性的作用,并介绍在
JFS2 上的新功能如何消除它们对性能的影响。
2.1 文件缓存
从
最基本的层面来说,文件就是在介质上所存储一些二进制位的集合,当一个进程需要从某个文件访问数据的时候,操作系统将这些数据读入内存,然后此进程可以
对数据进行操作,最后将处理完的数据写入磁盘。操作系统能够从磁盘上直接读出或写入数据,但是由于磁盘较慢的访问速度,这些操作的响应速度和吞吐率都较
差。因此操作系统试图通过文件缓存的技术,即在内存中缓存数据的方法,来减少对磁盘的访问频率。当进程需要从文件中读取数据的时候,操作系统首先试图从文
件缓存中读取所需要的数据,如果这些数据不在文件缓存中,那么从磁盘上文件系统的文件中读取,同时将这些数据缓存在文件缓存中。如图
1 和图
2 所示:
图
1 读操作
- 数据在文件缓存中(命中)
图
2 读操作
- 数据不在文件缓存中(没有命中)
与
读数据相似,当写数据时数据写入文件缓存,因此将来需要再读取这些数据时,不需要访问磁盘,同时也降低了写磁盘的频率。当缓存的命中率高时,使用文件缓
存将是非常有效的。并且可以采用预先读取和延迟写的技术来减少磁盘访问的频率。文件缓存所带来的另一个好处是,以异步的方式进行写操作,这使得应用可以继
续运行,而不用等待数据写入磁盘操作的完成,如图
3 所示。
虽然文件缓存提高了
I/O 的性能,但是它消耗了大量的系统内存。
AIX JFS2 文件系统允许系统管理员控制可以作为文件缓存的最大内存数。这种控制通过
maxclient% 参数控制。系统管理员可以使用
vmo 命令来调整
maxclient% 参数。
maxclient% 的却省值是
80 ,其含义是
80%的物理内存能够作为文件缓存。
maxclient% 参数的取值可在
1 至
100 之间变动。如可以采用以下命令设置最多
50% 的系统物理内存能够作为文件缓存:
vmo –o maxclient%=50 。
图
3 写操作
于此相对应,裸设备不使用系统内存来缓存应用的数据,所以没有以上图示的操作。
2.1.1 直接存取(
Direct I/O )
一
些应用程序并不能从文件缓存中得到好处,如有些进行大量科学运算的程序,从不访问以前访问过的数据,而且由于他们对数据进行顺序访问,这使得文件缓存的
命中率非常低。数据库的应用通常在应用层上有自己的数据缓存技术,所以不需要操作系统进行文件缓存。在这种情况下,使用文件缓存会产生很多额外开销,因为
数据首先从磁盘被读入系统的文件缓存,然后从文件缓存拷贝到应用的缓存中,这被称为“重复拷贝”(
double-copying ),重复拷贝增加了额外的
CPU 开销,并且相同的数据同时在文件缓存和应用的缓存中,增加了内存的消耗。
JFS2 的直接存取(
Direct I/O )技术可以使应用程序的数据被系统的文件缓存忽略。当使用
Direct I/O 时,数据直接从磁盘读取到应用程序的缓存中,而不是用系统的文件缓存。图
4 和图
5 说明了在
Direct I/O 下的读、写操作。
图
4 Direct I/O 的读操作
图
5 Direct I/O 的写操作
2.1.1.1 Direct I/O 的设置方法
Direct I/O 可以通过两种方式实现,一是通过在
mount 文件系统时加
–o dio 的参数,即
mount –o dio /fs 。二是在调用
open() 函数打开一个文件时加
O_DIRECT 参数。当一个文件系统在
mount 时使用了
–o dio 的参数,此文件系统的所有文件缺省都会使用
Direct I/O ,你也可以通过
namefs 使得
Direct I/O 只对文件系统中某个子目录中的文件起作用。例如:文件系统
somefs 中有一些文件希望使用
Direct I/O 功能,但是其它文件并不希望使用,你可以创建一个子目录
subsomefs ,将所有希望使用
Direct I/O 功能的文件放入这个子目录,在
mount somefs 时不使用
-o dio 参数,然后用
mount –v namefs –o dio /somefs/subsomefs /somefs 命令
mount subsomefs 。
Direct I/O 对应用程序
I/O 的边界(
alignment )和块大小(
length )有限制,表
1 列出了
JFS2 对此的要求,如果应用的
I/O 不满足此要求,所有的
I/O 操作会按传统的方式(文件缓存)的方式进行,但当数据被传输到应用的缓存后,系统缓存中的拷贝会被抛弃。当使用
Direct I/O 时,文件系统的预读功能将不会起作用。
文件系统的类型 | I/O 的边界(alignmnet ) | I/O 块大小(agblksize ) |
JFS2(AIX 5.2 ML01 前) | 4K bytes | 4K bytes |
JFS2(AIX 5.2 ML01 后) | agblksize ( 创建文件系统时的参数) | agblksize ( 创建文件系统时的参数) 表 |
表1 JFS 对Direct I/O 的限制
为了避免一致性的问题,当有多个进程同时打开一个文件,而其中有一个或多个进程没有使用
O_DIRECT 参数,而其它进程使用了此参数时,文件会按传统的方式(文件缓存)的方式打开,当没有使用
O_DIRECT 参数的进程关闭后,文件会转变成
Direct I/O 的方式。从文件缓存的方式转变成
Direct I/O 的方式有时会产生很大的开销,因为所有在内存中被改变的数据将会被立即写入磁盘。
2.1.1.2 Direct I/O 对性能的影响
Direct I/O 对性能的好处,一是降低了
CPU 的负载,二是避免数据被拷贝两次(第一次从磁盘到文件缓存,第二次从文件缓存到应用缓存)。但是其它的一些因素会对
Direct I/O 的性能产生影响。
每一次
Direct I/O 的读请求会产生对磁盘的一次同步的读操作。而传统的方式首先从系统的文件缓存中读取数据。如果数据可能存在于系统的文件缓存中,那么采用
Direct I/O 的方式性能较差。
Direct I/O 也不使用
JFS2 的预读功能。文件系统的预读功能能够提高顺序读取文件时的系统性能。使用预读功能时,当发现应用程序顺序的访问一个文件时,操作系统试图预测此应用将要读取几个文件页,而预先将其读出,这将减少系统
I/O 的次数。预读功能由两个参数控制:
l j2-minPageReadAhead当操作系统发现应用顺序读取文件时,所预读的文件页数,却省值为 2
l j2-maxPageReadAhead 这些参数可通过
ioo 命令调整。
表
2 对
Direct I/O 和传统缓存的方式在三种不同情况下的性能做了比较,这些测试中文件页的大小为
4K bytes ,
j2-minPageReadAhead=2 ,而
j2-maxPageReadAhead=8表2 Direct I/O vs. cached I/O
表
2 中的第一行的情况是应用
一 个字节一个字节的顺序读取
1MB 的文件。当使用
Direct I/O 时,由于没有满足
4K bytes 边界的限制,因此系统采用传统的文件缓存的方式读取
4K 的文件页,其中的一个字节被从系统的文件缓存拷贝到应用的缓存,然后此
4K 的文件页被从系统的文件缓存中删除,这就导致读取这
4K 中每一个字节时,此
4K 的页被反复的读取,而且也没有避免重复拷贝。当使用传统的缓存
I/O 时,当读取
4K 文件页的第一个字节时,
4K 的文件页被读入系统的文件缓存,随后的读取将在文件缓存中进行,而不需要访问磁盘,预读的功能进一步减小了延迟。
表
2 中的第二行的情况是应用
4K 字节
4K 字节的顺序读取
1GB 的文件。虽然在这种情况下满足
Direct I/O 对于
4K bytes 边界的限制,但由于
Direct I/O 没有预读的功能,所以虽然两种情况下所读取的数据量基本相同,传统的缓存
I/O 的性能仍然好于
Direct I/O 。
表
2 中的第三行的情况是应用
10M 字节的顺序读取
1GB 的文件。
Direct I/O 的性能远远好于传统的缓存
I/O 。这主要有两个原因:一是
Direct I/O 不存在重复拷贝,二是传统的缓存
I/O 没有享受到预读的好处。
这个例子说明,应用程序并不一定能从
Direct I/O 中带来性能的改善,然而如果一个应用可以从使用裸设备中得到性能的改善,那么它也能从
Direct I/O 中得到好处。
2.2 Inode 锁
虽然应用程序把文件看作连续的数据流,但这并不是文件实际在硬盘上的存储方式,实际上文件是以连续或不连续的数据块的方式存储的,每一个文件都有一个数据结构与其对应被称为
inode 。
Inode 中包含了访问此文件必须的信息,如文件的宿主,访问权限,文件的大小,上一次文件被访问和改变的时间以及文件数据块在磁盘上的分布。需要注意的是文件内容的改变与文件所对应
inode 的改变是不同的,文件的内容只在对文件进行了写操作以后改变,而
inode 的改变可能是对文件进行了写操作也可能是文件宿主、访问权限以及其它属性的改变。在实际环境中可能有多个进程同时需要改变文件的
inode ,这样会造成
inode 的不一致,为了避免这种情况的发生,
inode 被
inode 锁的锁机制保护。
当文件被读取时,
inode 不会改变,而写文件时
inode 会被改变。
JFS2 采用读共享,写独占(
read-shared, write-exclusive )的
inode 锁的锁机制,允许多个进程同时读一个文件,但当一个进程写文件时,其它进程不允许读写此文件。
2.2.1 并行I/O (concurrent I/O)inode 锁使得对于文件的多个写操作串行处理,这就避免了多个写操作并行时造成的数据的不一致性。而大多数数据库的应用有自己的数据串行处理机制,从而不会造成数据的不一致性。因此它们并不需要操作系统的这种
inode 锁的锁机制,实际上在这种情况下
inode 锁会对性能产生负面的影响。
AIX 5L v5.2 ML01 提供了
并行I/O (concurrent I/O) 的功能,在
并行I/O 的方式下多个进程可同时对一个文件进行读写操作。
并行I/O 是专门对数据库的应用进行设计的,大多数数据库的应用程序不需要修改就可以运行在
并行I/O 的模式下。而对于那些没有自己的数据串行处理机制的应用,如果运行在
并行I/O 的模式下,可能造成数据的损坏。
2.2.1.1 并行I/O 的设置方法
并行I/O 可以通过两种方式实现,一是通过在
mount 文件系统时加
–o cio 的参数,即
mount –o cio /fs 。二是在调用
open() 函数打开一个文件时加
O_CIO 参数。当一个文件系统在
mount 时使用了
–o cio 的参数,此文件系统的所有文件缺省都会使用
并行I/O ,你也可以通过
namefs 使得
并行I/O 只对文件系统中某个子目录中的文件起作用。例如:文件系统
somefs 中有一些文件希望使用
并行I/O 功能,但是其它文件并不希望使用,你可以创建一个子目录
subsomefs ,将所有希望使用
并行I/O 功能的文件放入这个子目录,在
mount somefs 时不使用
-o cio 参数,然后用
mount –v namefs –o cio /somefs/subsomefs /somefs 命令
mount subsomefs 。
并行I/O 缺省会包含
Direct I/O 的功能,因此
O_CIO 参数会覆盖
O_DIRECT 。与
Direct I/O 相似,当有多个进程同时打开一个文件,而其中有一个或多个进程没有使用
O_CIO 参数,而其它进程使用了此参数时,文件的访问将不会按
并行I/O 的方式进行,当没有使用
O_CIO 参数的进程关闭后,文件会转变成
并行I/O 的方式。
在
并行I/O 的方式下,
inode 锁工作在读共享,写共享的方式下,然而当
inode 改变并不是由于对文件内容进行写操作,而是由于
inode 的其它属性改变时,此时需要
inode 锁工作在写独占的模式下。例如文件增大或减小时,增大一个文件需要将磁盘上的空闲数据块分配给这个文件,此时需要改变相应
inode 的内容,在这种情况下读共享的
inode 锁升级为写独占的
inode 锁,当操作完成后
inode 锁恢复成读共享的方式。这是一个非常有用的功能,这就意味着在
并行I/O 的方式下,允许文件动态的增大或减小而不需要关闭这个文件。
2.2.1.2 并行I/O 对性能的影响
既然
并行I/O 中包含了
Direct I/O ,所有
Direct I/O 对性能的影响也适用于
并行I/O 。如果应用程序会从预读功能中得到好处,或在系统的文件缓存中有较高的命中率,那么在
并行I/O 的方式下会对性能产生负面的影响。
并行I/O 也不会对绝大多数
I/O 操作为读的应用产生性能的提高,因为在这种情况下读共享,写独占(read-shared, write-exclusive)的inode 锁的锁机制提供了与
并行I/O 相似的方式。
3.性能测试环境
为了评价
并行I/O 对性能的影响,我们测试了典型的在线交易(
OLTP )的应用在不同存储配置下的性能,我们选用的数据库是
Oracle9i 。此应用工作在
client/server 的体系结构下,其负载中有许多更新的操作。测试结果通过在客户端每秒钟完成的交易量来衡量(
tps )同时衡量响应时间,我们选取了三种不同的数据库的存储配置:
l 裸设备
l JFS2 文件系统
+Direct I/Ol JFS2 文件系统
+并行I/O系统的配置见表3:
表3 系统配置
在作数据库性能测试的时候通常使用裸设备进行数据的存储,这是因为裸设备没有文件系统的开销,通常可以得到最好的性能,在本测试中基于裸设备的测试结果作为基于文件系统的测试所追求的目标。
4.测试结果
表4和图6给出了在每一种存储配置下的平均吞吐率(每秒钟完成的交易量
tps )和平均响应时间,虽然平均吞吐率Direct I/O比裸设备低了70%,但是同步I/O只比裸设备低了8%。由此可见Direct I/O性能差的关键是由于严重的inode锁。
表4 平均吞吐率和平均响应时间
图6 吞吐率
并行I/O
与裸设备性能的不同主要由两个因素决定,一是对文件系统的访问比对裸设备的访问多了一层,对于文件系统,应用需要先访问文件系统,文件系统再访问LV,而
对于裸设备,应用直接访问LV。二是由于异步I/O(AIO),AIO的进程是一个核心进程,当AIO的进程访问文件系统的文件时需要进行context
switch。而对于裸设备的异步I/O时由系统核心完成的,不需要进行context switch。
对于系统锁的研究可以发现三种
存储模式的特点。我们使用了AIX的trace工具来获取系统锁的信息。在这里我们首先解释一下AIX
5.2的锁机制,当系统的一个进程或线程试图得到一个系统锁而没有成功,它会不断尝试去取得这个系统锁,尝试的次数由maxspin参数决定,其缺省值为
16384, maxspin参数可由AIX
schedo命令修改。当此进程或线程尝试了maxspin次后仍然没有取得这个系统锁,此进程或线程会由运行状态转变为等待状态。当取得此系统锁的进程
或线程释放了这个系统锁后,它会激活一个或多个等待此系统锁的进程或线程。
图7说明了在测试当中每种情况下最多的系统锁,通过trace的工具我们观察到了三种主要的系统锁:
l AIOQ锁:防止多个进程同时从AIO队列中插入或删除AIO的请求的锁。
l Inode锁:防止多个进程同时更新Inode的锁。
l SSA 锁:防止多个进程同时访问SSA设备的锁
从
图6中可以看出在Direct I/O的方式下,系统的瓶颈是在Inode锁上,这会造成大量的context switch,
大量的进程处于等待状态,并且CPU也处于等待状态。降低了整个系统的吞吐率。而在裸设备和同步I/Od的方式下,没有大量的inode写保护锁。
图7 不同模式下主要的系统锁类型
5.结论
本文中的性能测试表明,对于数据库的应用,采用JFS2的
并行I/O 的数据存储方式可以获得与采用裸设备的数据存储方式相似的性能,但却可使得数据的管理更加方便灵活。这说明
并行I/O 技术适用于数据库的应用。
转载自 http://ebsblog.blog.163.com/blog/static/127949789200981533033695/