DB2 pureScale 是 cluster 环境下的 DB2,它采用了 DB2 for z/OS 系统中经典的 Sysplex 架构,为分布式平台带来以前仅 DB2 for z/OS 拥有的集中锁定和缓存功能。
I/O 性能调优是系统性能调优的一个重要方面,尤其对于数据库系统而言,更是如此。I/O 上的性能瓶颈往往会成为整个系统的性能瓶颈,表现出来的特征就是 I/O 系统数据读写的速度无法满足系统计算的需求,宝贵的计算资源被浪费在等待 I/O 操作上。DB2 pureScale 是一个复杂的系统,它的 I/O 性能调优至上而下涉及从数据库、操作系统、文件系统,到存储的各个层面,只有综合考虑了各个层面的约束条件,才能达到最优的性能。本文将按照至上而下的顺序分别介绍各个层面有关 I/O 配置的重要参数,并给出这些参数在特定应用场景下的最佳调优实践。
通过提供无限的容量、持续的可用性和应用程序程序透明性,DB2 pureScale 降低了业务增长的风险和成本。DB2 pureScale on IBM Power Systems 融合了 PowerHA pureScale 技术,交付了无与伦比的数据库可伸缩性和可用性水平。该产品是在可用性、可伸缩性、安全性和可靠性领先的产品 DB2 for z/OS and System z 的有力补充,是 DB2 for LUW 在分布式平台上的一个重大突破。显示了 DB2 pureScale 系统的基本结构。
DB2 pureScale 为所有事务性工作负载提供了几乎无限的容量。要扩展您的系统,只需连接新节点并发出两条简单命令。DB2 pureScale 基于集群的共享磁盘架构通过有效使用系统资源降低了成本。您可以轻松添加机器到集群中,进而向外扩展您的系统。DB2 pureScale Feature 可扩展到包含 128 个成员,且具有一个集中管理工具,支持高效的向外扩展功能。它使用一种称为 Remote Direct Memory Access (RDMA) 的技术,提供一种效率很高的节点间通信机制来辅助其扩展功能。
DB2 pureScale 通过使用基于 IBM Power Systems 且高度可靠的 PowerHA pureScale 技术,以及一个冗余平台,提供了持续的可用性。该系统避免了普通系统中存在的单点故障,几乎可在出现节点故障的同时进行恢复,立刻将工作负载重新分配到健康的节点上。在故障期间,只有在发生故障的成员上修改的数据暂时不可用,直至为该组数据完成数据库恢复。
使用 DB2 pureScale,您无需更改应用程序代码即可在多个节点上有效运行。借助成熟、可扩展的架构,您可以扩展应用程序来满足最严苛的业务需求。而且,只需少量改动或者甚至无需改动,就可以运行为其他数据库软件编写的应用程序。在一个 DB2 pureScale 环境中的运行的应用程序不需要了解集群中的不同成员,也不需要关注数据分区。DB2 pureScale Feature 会自动将应用程序路由到最合适的成员。
不同类型的应用对于 I/O 的需求是不一样的,由于运行在 DB2 pureScale 之上的应用主要是 OLTP(Online Transaction Processing)类型的应用,下面我们将以 OLTP 应用为例,介绍如何调整数据库、操作系统、文件系统和存储各个层面的相关参数,来达到最优的 I/O 性能。
数据库系统涉及的 I/O 操作无非两种:读(Read)操作和写(Write)操作。对于 DB2 而言,读操作既可以由 prefetcher 来异步完成,也可以由 db2 agent 来同步完成;写操作既可以由 page cleaner 来异步完成,也可以由 db2 agent 来同步完成。一般来说,相对于同步 I/O,异步 I/O 会有性能上的提高,因为计算操作无需等待 I/O 操作,可以和 I/O 操作同时进行。但是在 OLTP 类型的应用场景中,由于大部分的 I/O 读取操作都是随机读取,并且每次读取的数据量都很小,开启数据预取功能并不会带来性能上的好处,反而会增加 I/O 带宽,所以我们一般会使用同步 I/O 来进行读操作,使用异步 I/O 来进行写操作。
正如 所示,在 OLTP 应用场景中,来自数据库的 I/O 操作主要分为两类,一类是由 page cleaners 提交的异步写操作,一类是由 db2 agents 提交的同步读操作。对于 page cleaners 提交的异步写操作,我们可以使用 num_iocleaners 来控制数据库中 page cleaner 的数目;对于 db2 agents 提交的同步读操作,我们可以使用 max_coordagents 来控制数据库实例中协调代理的数目。
DB2 中控制读写操作的参数主要有:
- num_ioservers:这个参数用来指定一个数据库中 I/O prefetcher 的数目。在任何时候,数据库中 I/O prefetcher 的数目都不能超过这个值。I/O prefetcher 可以被 db2 agent 用来执行数据预取操作,也可以被备份恢复工具用来执行异步 I/O 读取操作。
调优:在 OLTP 类型的应用场景中,我们一般会把这个参数的运行时值设为 1,因此关闭数据预取操作,而由 db2 agent 来进行同步数据读取。这样一方面可以提高 buffer pool 的利用率(仅仅将需要用到的数据读到 buffer pool 中);另一方面也可以提高 I/O 带宽的利用率(有限的 I/O 带宽仅用来传输实际要被用到的数据)。
我们可以使用 中的命令来查看这个参数的当前值,运行结果如 所示。
db2 get db cfg for
我们可以使用 中的命令来修改这个参数的值,运行结果如 所示。
db2 update db cfg for
using num_ioservers 1 - num_iocleaners:这个参数用来指定一个数据库中 page cleaner 的数目。Page cleaner 可以把 buffer pool 中被更改过的页面异步的写回到磁盘,这样当 db2 agent 需要空闲的 buffer pool 空间时,就不需要等待,从而可以提高系统的性能。
调优:DB2 Info Center 中提供了一个用来计算 num_iocleaners 的公式:
number of page cleaners = max( ceil( # CPUs / # local logical DPs ) – 1, 1 )
。其中,# CPUs 是整个系统中 CPU 的数目,这里的 CPU 可以是通过软件技术虚拟出来的逻辑 CPU;# local logical DPs 是位于该系统上的数据库逻辑分区的数目,对于单分区的数据库系统,它的值为 1。在过去很长的时间里,这样的计算规则都是适用的。但是随着硬件技术的发展,多核已经成为一个趋势。同时伴随着 SMT(Simultaneous Multi Threading)技术的飞速发展,一个物理的核又可以被划分成多个硬件线程(逻辑 CPU)。这些导致一个系统中逻辑 CPU 的数目急剧增加。以 Power780 为例,一个 P780 拥有 64 个核,如果这些核运行在 SMT4(一个物理的核可以虚拟出 4 个逻辑的 CPU)模式下,那么整个系统就会有 256 个逻辑 CPU。在这种情况下,由上诉公式算出来的 page cleaner 的数目往往会偏大。这时我们就需要根据应用的具体情况做一些相应的调整。
我们可以使用 中的命令来查看这个参数的值,运行结果如 所示。
db2 get db cfg for
我们可以使用 中的命令来修改这个参数的值,运行结果如 所示。
db2 update db cfg for
using num_ iocleaners - max_coordagents:这个参数用来指定一个数据库实例可以拥有的协调代理的最大数目。它是数据库实例级别的配置参数,影响实例中的所有数据库。任何时候,整个数据库实例中协调代理的数目都不能超过这个值。对于每个连接到数据库的应用程序,我们都需要为它分配一个协调代理来服务。因此,这个参数控制了系统中可以同时存在的协调代理的最大数目,从另一个角度来讲,也控制了系统中提交并发同步读操作的代理的最大数目。
调优:对于这个参数的设置我们一方面需要考虑整个应用系统的并发性,既要保证通常情况下,连接到数据库的应用程序都可以获得为之服务的协调代理;另一方面需要考虑下层 I/O 系统的能力,要保证由这些协调代理提交的同步读操作能够被底层的组件所处理。通常可以将其设置为 Automatic,让数据库根据应用的实际需求来动态的调整它。但由于数据库仅仅根据连接到系统的应用的数量来动态的调整协调代理的值,没有考虑底层 I/O 系统的承受能力,因此有时候会发生连接到系统的应用程序过多,导致提交给下层 I/O 系统的压力过大。这时我们就需要手工的根据以上原则来设置这个值。
我们可以使用 中的命令来修改这个参数的值,运行结果如 所示。
db2 get dbm cfg
我们可以使用 中的命令来修改这个参数的值,运行结果如 所示。
db2 update dbm cfg using max_coordagents
由 所示,上层数据库系统提交的异步写请求,会由 AIX 中的异步 I/O 子系统负责处理。AIX 的异步 I/O 子系统会把相应的请求放到 AIO(Asynchronous I/O)的队列里,然后由叫做 aioserver 的内核进程来负责进行处理。可见,系统中 aioserver 的数目限制了整个系统可以同时进行的异步 I/O 操作的数目。也就是说,我们必须满足:page cleaners 提交的异步写操作的数目 < 系统中 aioserver 的数目
AIX(以 6.1 为例)中控制 aioserver 相关的参数包括:
- aio_maxservers:这个参数用来指定最大的 AIO 服务进程(专门用来处理异步 I/O 的内核进程)数。在 AIX6.1 中,这个值是针对每个 CPU 而言的,也就是说:
整个系统最大的 AIO 服务进程数 = aio_maxservers * 系统中逻辑 CPU 的数目
。任何时候系统中的 AIO 服务进程数都不能超过这个值,所以它在操作系统级别限制了整个系统同一时间并发 AIO 的数目。同时,aio_maxservers 的值必须大于 aio_minservers 的值。调优:一方面,由于上层 DB2 page cleaner 提交的异步写操作需要由 AIO 子系统来处理,我们得保证系统中 aioserver 的数目大于 page cleaner 提交的最大并行异步写的操作数;另一方面,由于 AIO 子系统的所有操作都会提交给下层的 GPFS 来处理,我们得保证提交给 GPFS 的请求在它的处理能力范围之内。aio_maxservers 的默认值是 30。在多核技术以及 SMT 技术飞速发展的时代,使用这个默认值往往会使系统中最大 AIO 服务进程数过大,从而超过下层 GPFS 的承受范围。比如,对于一个拥有 256 个逻辑 CPU 的 P780 系统而言,如果使用 aio_maxservers 的默认值 30,那么整个系统可以容纳的最大并发 AIO 数会为 256 * 30,这对于 GPFS 来说已经远远超过了它的承受范围。所以,我们需要根据具体的需求来设置这个参数的值。
我们可以使用 中的命令来查看这个参数的值,输出结果如 所示。
ioo – o aio_maxservers
我们可以使用 中的命令来修改这个参数的值,输出结果如 所示。
ioo – o aio_maxservers=
- aio_minservers:这个参数是与 aio_maxservers 相对应的一个参数,它指定了最小的 AIO 服务进程数。在 AIX6.1 中,这个值也是针对每个 CPU 而言的。当内核扩展加载时,不管当前 aio_minservers 的设置是什么,系统不会启动任何 AIO 服务进程。这对于那些压根就不使用 AIO 的系统来说有很大的好处,因为减少了创建这些进程和维护这些进程的开销。只有当 AIO 请求真正到达时,AIX 才会按需创建 AIO 服务进程,同时创建的 AIO 服务进程总数会受限于上述 aio_maxservers 的设置。而且一旦 AIO 服务进程的数目超过了这个最小值,它就不会再回落到低于该值的范围。
对于这个参数的调优我们只需要注意 , 在我们对 aio_maxservers 进行调整的过程中,保证 aio_minservers 始终要小于 aio_maxservers。
我们可以使用 中的命令来查看这个参数的值,输出结果如 所示。
ioo – o aio_minservers
我们可以使用 中的命令来修改这个参数的值,运行结果如 所示。
ioo – o aio_minservers=
IBM General Parallel File System (GPFS) 是 DB2 pureScale 的一个关键部分。由 所示,数据库系统中由 db2 agents 提交的同步读操作和 AIX 异步 I/O 子系统提交的异步 I/O 操作,最终都会由 GPFS 来负责处理。这就要求来自上层的并发 I/O 请求的总数必须处在 GPFS 所能处理的范围之内,否则会导致 GPFS 中严重的锁冲突,造成整个 I/O 系统性能的下降。所以,我们必须满足:db2 agent 提交的同步读操作 + AIO 子系统提交的异步 I/O 操作 < GPFS 同一时间所能处理的最大 I/O 并发数
GPFS 中控制并发 I/O 操作的参数有:
- worker1threads:这个参数用来控制整个 GPFS 系统可以同时处理的应用请求的最大数目。这些操作既包含源数据操作(如:open, close), 也包含对普通数据的操作(如:read, write)。减少 worker1threads 的值不需要重启 GPFS 后台进程,但是增加它的值却需要。使用 中的命令可以查看系统中的 worker1threads 是否足够,输出结果如 所示。
# mmfsadm dump mb | grep Worker1
其中,max 代表当 GPFS 后台进程启动时设置的 worker1threads 的值;current limit 代表在运行过程中动态改变的 worker1threads 的值(只能减小,不能增加);in use 代表有多少个 worker1thread 正在被使用;waiting 代表有多少个请求正在等待 worker1threads。根据这些信息我们就可以判断系统中设置的 worker1Threads 是否足够。
调优:在并发请求的情况下,为了使底层的磁盘始终处于忙碌的状态,提高磁盘的利用率,我们一般会把 worker1threads 的值设为文件系统中 LUN 数目的 2 倍。在 64 位的架构中,worker1threads 的最大值依赖于
worker1Threads + prefetchThreads + nsdMaxWorkerThreads < 1500
。在 DB2 pureScale 环境中,该参数的默认值是 150。在实际的大型 OLTP 应用场景中,这个值有点小,会成为整个系统的一个瓶颈。所以我们需要根据实际的应用需求来对它进行调整。我们可以使用 中的命令来修改这个参数的值(记住:如果增加它的值,需要重启 GPFS 后台进程才能生效),输出结果如 所示。mmchconfig worker1threads=
由 所示,上层所有的 I/O 请求最终都会流向底层具体的物理存储。物理存储的 I/O 能力是有一定限制的,这依赖于存储的物理特性以及组织方式,所以我们必须保证上层应用的 I/O 请求不能超过底层存储的限制。如今,一个大型的存储系统一般会包含很多个 LUN(Logical Unit Number)。根据我们在 OLTP 环境中测试所得的经验,为了取得最好的 I/O 性能,我们一般会保证同一时间有 5IOs/LUN。这样对于用 HDD 作为后台存储介质的情况,我们可以让磁盘始终保持忙碌的状态,从而提高磁盘的利用率以及系统的 I/O 性能。
因此,整个系统同一时间可以处理的 I/O 操作 = 5 * 系统中 LUN 的数目
。有时候为了满足上层应用对于 I/O 的内在需求,我们需要在存储层次做很多的设计和优化工作,来容纳这些 I/O 请求。
综上所诉,DB2 pureScale 系统的 I/O 性能调优是一个复杂的过程,我们需要考虑数据库、操作系统、文件系统、底层存储所有层面的设置,才能让系统达到一个最优的性能。在实际场景中,我们可以从最上层的应用入手,分析应用的特点和 I/O 特征,得到应用的 I/O 需求,然后根据这个需求,一步一步至上而下调整各个层面的 I/O 设置。尽管本文是基于 Power+GPFS+AIX 来阐述的,但其思想同样适用于其他平台及环境中的 I/O 性能调优。同时,需要注意,性能调优工作是一个不断重复的工作,我们需要不断的监控系统的性能,根据当前的情况作出相应的调整,才能使系统始终保持最优的运行状态。
学习
- 查看文章 了解更多关于 DB2 pureScale 的内容。
- 查看 获取关于 DB2 pureScale 特性的更多信息。
- 查看 获取关于 AIX 的更多信息。
- 查看 获取关于 GPFS 的更多信息。
- 随时关注 developerWorks 和 。
获得产品和技术
- 下载 ,体验强大的 DB2®,Lotus®,Rational®,Tivoli®和 WebSphere®软件。
- 可以直接使用从 developerWorks 下载的 构建您的下一个开发项目。