赞
踩
最佳实践的相关文章可见:http://www.ibm.com/developerworks/cn/data/bestpractices/
大多数 DB2 系统都经过了性能的演变。首先,不论出于硬件还是软件的观点,该系统首先要能被配置。在多数情况下,这将成为系统在实施后如何运行的基础。其次,系统一经发布,勤勉的数据库管理员(DBA)将监控系统的性能,来监测任何可能的开发问题。如果发现任何问题,我们就进入下一个阶段 - 故障诊断阶段。每个阶段都是基于上一阶段,如果没有适当的准备,我们极有可能需要处理比较困难的问题。
本文介绍了 DB2 系统性能的最优方法。我首先涉及到一些有助于我们确保良好软硬件性能的重要原则。然后我们讨论多种在操作和故障诊断的情况下,有助于我们了解系统性能的监控方法。最后,尽管我们做了最好的准备,性能问题仍然可以降临到我们身上,我们讨论如何逐步地处理它们,并有条不紊的进行。
任何形式的性能问题都将严重影响并降低一个系统对你组织的价值、削弱业务能力、服务中断、以及增加管理开销。所有这些都会提升总的拥有成本。缺乏对系统配置的基本原则,监视和性能故障诊断可能导致不同程度的性能低下,并且降低对于组织的价值。
因此,在前期花些时间去考虑基本的配置指导方针和建立健全的系统监控这样的做法,将使你对处理许多可能出现的典型性能问题,有充分的准备。并使数据服务器得以高性能运行,以提高投资回报率。
像 InfoSphere 平衡的仓库(BW)这类的 DB2 部署类型,或者那些在 SAP 系统之内的系统,配置都是高度确定的。在 BW 案例中,像 CPU 个数、内存对 CPU 的比率、硬盘的个数和配置这样的硬件因素,以及在预先指定版本的基础上,详尽的测试,以确定最优配置。在 SAP 的案例中,硬件配置并不是精确指定的,不过却有许多可用的配置样本。此外, SAP 最佳实践对 DB2 的配置提供了建议值。如果您正在使用它们其中之一的 DB2 系统的话,那么这些系统都提供了经过良好测试的配置指南。你通常应该利用它们对于更普通的经验法则的优势。
我们来考虑一个建议系统,这个系统不同于 BW,我们并没有有一个详细的硬件配置。虽然深入研究系统配置已经超出了本文的范畴,但是这儿有一些基本的配置指南只需要我们花时间去理解和应用。我们的目的是找出几个能让系统拥有良好性能的关键配置决定。
对于系统性能,CPU 的能力是在配置中一个主要的独立变量。因为所有其它的硬件配置向来取决于它,很难预测完成一个特定工作量需要的 CPU 能力。在商务智能(BI)环境下,我们可以合理地估算出每个处理器内核 200-300GB 的原始数据。对于其它的环境,一个健全的做法是基于一个或者多个 DB2 系统估算总的 CPU 需求。例如一个新系统需要处理 50% 的用户,每个用户运行的 SQL 的复杂度类似一个现有系统,可以合理地假设需要增加超过 50% 的 CPU 能力。同样,要预测 CPU 使用的其它因素改变,如不同的吞吐量要求,更多或更少的触发器或者参考完整性,等… 都应该被考虑到。
一旦我们对 CPU 需求有了很好的认识,就能利用已有信息进行开发,硬件配置的其它方面也会开始整理就绪。显然我们必须考虑到该系统的所需的磁盘容量在千兆字节或 TB,最重要的因素就在 I / O 的每秒( IOPS)的性能,或以兆字节每秒的数据传输。实际上,这取决于涉及多少个单独的磁盘。
这是为什么呢?虽然 CPU 的发展在过去十年在速度上有了惊人的增长,然而磁盘的发展却更多的在它们的能力和成本上。虽然在磁盘搜索时间和传输率上已经有了提高,但是仍然无法更上 CPU 的速度。因此为了达到现代的系统总体性能需求,使用多个磁盘比之前任何时候都要重要,尤其是对于那些需要驱动繁重随机磁盘 I/O 的系统。很多时候,诱惑来自于使用最低的磁盘数目来存放所有数据的系统,然而这通常会导致非常差的性能。
在使用 RAID 存储的情况,或者单个可选址驱动,凭经验估计合理的配置是最少 10 到 20 个磁盘每个处理器内核。对于存储服务器,有一个类似的推荐值,不过有一点需要额外的小心。存储服务器在分配空间的时候更着眼于而容量非吞吐量。了解数据库存储的物理布局,对于确保不会出现逻辑分开的存储由于疏忽发生物理重叠的现像来说,是一个非常好的主意。例如,对于一个 4-way 的系统应来说,该有 8 组每组 8 个驱动。然而,如果 8 组共享同样的 8 个底层驱动,配置的吞吐量将受到非常严重的降低。参见 <insert storage BP paper reference here> 和 <insert physical database design BP paper reference here>
更多信息请参见存储配置最佳实践。
为 DB2 事务日志分配专门的非共享的磁盘是很好的实践。这因为日志的 I/O 特性与 DB2 容器有很大的不同。日志 I/O 与其它类型的 I/O 的竞争能导致日志成为一个瓶颈,尤其是那些有大量行写入行为的系统。
通常, 一对 RAID-1 磁盘能够提供应每秒高达 400 个的事务合理的写负载提供日志吞吐量。如果有更大的吞吐率,或更大量的日志(例如,大批插入)就需要更大的日志吞吐量,这可以通过在 RAID-10 配置中添加硬盘来提供,并通过一个写入高速缓存磁盘控制器连接到系统中。下面的故障诊断章节会讲述如果发生日志瓶颈怎么办。
由于 CPU 和磁盘有效的操作在不同的时间尺度(纳秒 VS 微秒)我们需要分离它们以获得合理的性能。这就是内存来发挥的作用。在一个数据库系统中,内存的主要作用是避免 I/O,归结为一点,拥有更多内存的系统能工作得更好。幸运的是,在过去几年中内存的成本已经有了显著的下降,并且系统拥有几十到上百 GB 的内存已经不在罕见了。通常,对于大多数应用程序每个处理器内核拥有 4 到 8GB 内存是比较合适的。
为了达到比较好的性能,有一些相关参数需要调整。我们是假定 AIX 系统是 5.3 或者更高版本来给的这些建议。此外如果在你的系统中已经有了一些特定的设置(如,一个 BW 或者 SAP 配置),那么它们提供的设置将比下面的通用指南有更高的优先级。
ps – elfk | grep aio
的输出并且判断是否所有的异步 I/O(AIO)核心进程(aioservers)消耗同样数量的 CPU 时间。
对于在 Solaris 或 HP-UX 上运行的 DB2,根据系统的大小,利用 db2osconf 工具来检测和推荐内核参数。 db2osconf 允许你基于内存和 CPU 指定核心参数,或与一般缩放系数来比较现有系统配置和未来期望的配置。一个好的方法是使用缩放系数 2 或者更高的缩放系数来运行大型系统如 SAP 应用程序。通常情况下,db2osconf 向你提供了好的起点来配置 Solaris 和 HP-UX,但是由于它无法考虑到现在或者未来的工作负载,它不能带来优化后的值。
当一个 Linux 系统被用作 DB2 服务器时,可能不得不修改一些 Linux 的一些内核参数。因为 Linux 的发行变化和这个系统的高度灵活性,我们将只讨论一些基于 linux 实施中需要确认的最重要的设置。
SHMMAX(一个共享内存的最大值)在一个 64 位系统必须至少设为 1G - 1073741824,反之 SHMALL 参数必须设置数据库服务器的 90% 可用内存。SHMALL默认值是 8GB 。其它重要的 Linux 内核配置参数以及它们对 DB2 的推荐值是:
使用 DB2 数据分区特性(DPF),通常并不是纯粹由数据容量决定,而更多的是工作负载的性质。大多数 DPF 部署在数据仓库和商业智能上是一个常规的指导方针。对于大型的复杂查询环境 DPF 是被高度推荐的,因为它的 share-nothing 架构提供了优异的可扩展性。对于小一些的不大可能快速增长的数据集市(达到 300GB),一个 DB2 企业服务器版本(ESE)配置是一个很好的选择。然而大型的或快速增长的 BI 环境将从 DPF 中获利。
虽然处理一个完整 DPF 系统设计已经超出了这篇文章的范畴,但是一个 CPU 到分区的基本描述还算简单。一个典型的分区系统通常每个分区拥有一个处理器内核。例如,一个有 N 个处理器内核的系统可能有一个编目分区和 N 个数据分区。如果这个编目分区将被大量使用(例如,拥有单分区维度的表),那么它最好被分配一个处理器内核。如果这个系统将支持许多并发活动用户,就可能每个分区需要两个内核。
作为一个一般性的指南,你应该在每个分区上计划大约 250G 活跃的裸数据。
在 InfoSphere Balanced Warehouse 的文档中有关于 DPF 配置最佳实践的更深入的信息,也包含对于 non-Balanced Warehouse 部署的有用资料。
除了影响数据库性能的行为之外,代码页或代码集的选择和比较的顺序也许会对性能造成很大的影响。由于 Unicode 允许客户在他们的数据库中比传统单字节代码页呈现更多类型的字符串,使得 Unicode 的使用变得越来越普遍。事实上,它也是 DB2 9.5 的默认值。然而由于 Unicode 代码集使用多字节来呈现一些单独的字符,这将增加磁盘占用和内存需求。如,UTF-8 代码集是一个最常用的 Unicode 代码集,每个字符使用一到四个字节。一个字符串从单字节代码到 UTF-8 代码集在迁移过程中的扩大因素是非常难预测的。因为它取决于多字节字符的使用频率。对于典型的北美内容,通常没有扩大。对于大多数西欧语言,音标字符的使用一般导致 10% 的扩大,但是您的成本会有所不同。
此外,相对于单字节代码页,使用 Unicode 会导致额外的 CPU 开销。首先,如果发生了扩充,越长的字符串处理工作就越久。其次,也更显著的是,该算法采用更先进的 Unicode 整理序列,如 UCA500R1_NO,这比系统整理的典型单字节代码要昂贵得多。而这完全是由于 Unicode 串行排序成文化正确性的方式的复杂性造成的。操作受到了包括排序,字符串比较,like()处理以及创建索引的影响。
如果正确显示你的数据 Uincode 是必须的,那么请仔细选择校验顺序
详细的数据库物理设计已经在 Sam 的数据库物理设计文章中很好的覆盖了,但是为了达到我们的意图,我们将在这里讨论两个最高阶的最佳实践。
DB2 数据库配置初始设置
数据库配置建议程序,也就是通常所说的 autoconfigure 命令,它根据你提供的系统指南确定一个比较好的数据库配置参数初始值。 Autoconfigure 的确对默认配置的设置有所改进,也是一个用来获得初始配置值的推荐方法。根据不同的系统特性,对 autoconfigure 的推荐值进行一些额外的微调是必要的。
使用 autoconfigure 的建议:
DB2 最新版本不论在实例启动还是数据库启动的时候都显著地增加了自动调整或者在操作过程中动态调整参数的数目。除了那些手动精心调试的系统,这对于大多数系统自动设置会带来最好的性能。这主要归功于 DB2 的自调整内存管理器(STMM),它动态调整 DB2 系统中数据库内存总量的分配,如四个主要的内存消费者:缓冲池,lock list,包缓存以及排序堆。
因为那些参数都是基本应用于各个分区的,对于分区环境 STMM 需要注意几点。在分区环境中 STMM 将在一个分区上(DB2 自动选择的,但是可以被废除)持续检查内存需求,判断并把堆大小的更新值推向所有启动了 STMM 的分区。由于所有的分区都使用相同的值,STMM 在各分区的数据总量,内存需求以及综合活动水平都非常统一的 DPF 环境中工作最佳。如果个别分区有数据倾斜或者有不同的内存需求,STMM 则应该在那些分区上停用,而在更一致的分区上启用。例如,STMM 通常应该在编目节点上停用。
对于数据分布发生倾斜的 DPF 环境,不推荐进行跨集群的内存调整,STMM 可以在“调试阶段”有选择临时的使用,以用来帮助确定比较好的手动设置堆大小:
配置顾问工具通常在可应用的用于启用自我管理或自动配置。这包括自动 runstats(非常有用),但是不包括自动重组和自动备份。它们同样非常有用但是为了达到最大的效果需要根据你的环境以及时间表进行配置。自动统计信息应该默认关闭。它有很高耗费并且应该在可控的环境下临时的与复杂语句一起使用。
某些参数没有自动调整设置,也不能被配置顾问程序调整。这些参数就需要明确的被处理。(注:我们将只考虑与性能相关的那些)
可以毫不夸张的说拥有正确的统计信息常常是获得 SQL 性能的关键,尤其是在复杂查询的环境中。比起重复在其它文章里面已经写得很好的部分,我们更愿意向读者介绍“写和调优查询语句来优化性能”。
如果你将 DB2 作为一个 SAP 这样的 ISV 应用程序的数据库服务器来运行,可能需要一些重要的最佳实践来评估特定的应用程序。最直接的方法就是可以把 DB2 注册变量 DB2_WORKLOAD 的值设成‘ SAP ’来启用一批为 SAP 工作负载优化了的注册表变量。
也可以应用其它建议和最佳实践,如选择代码页 / 代码集以及整理序列,它们同样需要预先确定值。更多细节请参考第三方应用程序文档。
像 SAP Business One 这样的许多 ISV 应用程序,autoconfigure 命令可以成功的用于定义初始配置。然而,它不应该在 SAP NetWeaver 安装中被使用,因为在 SAP 安装过程中一个 DB2 配置的初始设置已经被应用了。另外,SAP 有一个强大的可供选择的最佳实践步骤。根据 SAP Note 它记录了首选的 DB2 参数设置。例如 SAP Note1086130-DB6:DB2 9.5 标准参数设定。
要特别注意的是,SAP 应用程序使用 DB2 DPF 功能是需要付费的。 SAP 主要在它们 NetWeaver Business Intelligence(Business Warehouse)中使用 DPF 。建议的布局是把 DB2 系统编目、维度和 master 表加上 SAP 的基础表放在 0 号分区。这这样布局是由于这个分区的工作负载不同于其它分区。因为 SAP 应用程序服务器运行在这个分区,仅这个分区可以分配多达 8 个处理器,而且 SAP BW 工作负载变得并行度越来越高,许多简短的 SQL 语句并行运行,分区的数据将通常少于其它的应用程序。换句话说,每个分区将需要不止一个 CPU 。
要获取更多关于 DB2 和 SAP 初始安装的细节,请参考 SAP Service Marketplace(service.sap.com)或者SAP Developer Network
在设定一个初始系统配置后,实施一个监控策略就变得非常重要。这将使你能随着时间的流逝对许多重要的系统性能度量监视元素进行跟踪。这在给你的关键数据初始配置带来改进值以更好适应你的需求的同时,它也同样可能会在软件升级、数据量或者用户人数增加、或者新应用程序开发等方面给你带来新的问题。
我们拥有数百种度量监视元素以供选择,但是由于产生数据的总量,收集所有数据会产生相反的作用。我们所希望的尺度是:
DB2 有很多的监视元素,我们将选择符合需求的那些。就像人的身体,心率是一个很好的但不是最好的度量监视元素,因为它是基于很多因素的变化度很高-它太敏感了。心率的变化并不代表我们的”系统”有了问题。然而,身体的温度是一个很好的度量,因为它非常的稳定,却对很多我们可能关注的问题非常敏感。
区分操作监控(那些我们日常做的基础的事情)和异常监控(我们搜集额外数据来帮助诊断问题)的主要的差别是操作监控只需要轻量级(它的测量并不消耗太多的系统资源)和一般的资源 - 留意任何可能出现在系统中的潜在问题。在这个部分,我们将主要专注于操作监控。
DB2 提供了一些极好的资源来监控数据,最主要的是快照监控器和在 DB2 9.5 以及以后版本中的工作负载监控管理(WLM)汇总功能。它们都专注于概要数据、计数器、计时器、柱状图、等等… ,来维护系统中所有运行活动。随着时间的推移,通过取样我们能得出在这期间的平均活动情况,这会产生非常丰富的信息。
和照相类似,快照和汇总统计信息向我们提供了一张单独的系统活动画面。在某些情况下它是如同闪光摄影一样是即时的,但是更多的情况下它是‘定时曝光’的,显示了在相当长时间内发生的事情。 DB2 同样提供了‘动画’监控,它记录了一系列单独的活动。这由跟踪这类的机制完成,比如事件监控器(尤其是语句事件监控器)WLM 活动监视器,它们是紧密相关的。比起我们从快照的得到的摘要,它们提供了对系统活动更多更全面的细节记录。然而,跟踪会产生大量的数据并对系统产生非常大的影响。因此它们比起操作监控来,更适用于异常监控。
没有任何理由限制我们只能使用 DB2 提供的度量监视元素。事实上,非 DB2 数据比起作为一个好的背景资料,更多的是判断性能问题的关键。用户,应用程序,操作系统,存储系统,网络,所有这些可一个提供对系统性能有价值的信息。在 DB2 之外的度量监控元素是生成一个完整的系统性能全景图像的非常重要的一部分。
由于我们打算在整个系统生命周期内对操作的度量监视元素正常的搜集信息,拥有一种可以管理所有数据的方法非常重要。对于我们将有的对数据可能的用途,比如长期的性能倾向(例如,我们想比较的任意两个数据集合可能相隔数月)。 DB2 本身非常适合对这种数据进行管理。分析和比较数据也变得非常简单;对于长期的数据存储和组织,我们也已经有了一个强大的基础架构。
DB2 8.x 和 9.x 的趋势是通过 SQL 接口会产生越来越多的监控数据 。由于我们可以简单的重定向管理视图数据,这使 DB2 监控数据的管理非常简单,比如,回到 DB2 表。更深入的,事件监控和活动监控数据也能写入 DB2 表提供类似的好处。由于绝大多数监控数据可以如此简单的存进 DB2,对 DB2 存储系统度量监视元素(如来自于 vmstat 的 CPU 利用率)进行小的投资也是很容易控制的。
这些来自于数据库快照度量监视元素(db2 get snapshot for database on
dbname
)。如上面所提到的,为了分析和便于长期管理,最佳实践就是通过相应的管理视图(db2 select … from sysibmadm.snapdb
)来访问那些元素。注意,为了 snapshot 表函数和管理视图可以访问数据,实例级的监控器开关需要打开。例如,开启 DFT_MON_BUFPOOL 是为了收集缓冲池的监控数据。幸运的是它们都属于动态开关而且开启或关闭它们不必重启实例。在下面的例子中,我们将强调管理视图中用来判断每一个度量监视元素的列。
关于 DPF 的注释:如果你正在运行一个多分区环境,你需要在监控的查询语句中包含 DBPARTITIONNUM,以区分各个分区的返回记录。
1. 通过COMMIT_SQL_STMTS
,SELECT_SQL_STMTS
和UID_SQL_STMTS
,
得到
执行 SELECT 语句和 INSERT/UPDATE/DELETE 语句的事务的数目。
100% * (POOL_DATA_L_READS – POOL_DATA_P_READS)
/ POOL_DATA_L_READS
100% * (POOL_INDEX_L_READS – POOL_INDEX_P_READS)
/ POOL_INDEX_L_READS
100% * (POOL_TEMP_DATA_L_READS - POOL_TEMP_DATA_P_READS) / POOL_TEMP_DATA_L_READS
100% * (POOL_TEMP_INDEX_L_READS - POOL_TEMP_INDEX_P_READS) / POOL_TEMP_INDEX_L_READS
得到缓冲池命中率,分别对于数据,索引,和临时数据的测量结果。
缓冲池命中率是一个最基础的度量监视元素,对让系统如何有效利用内来存避免磁盘 I/O,提供了一个重要并全面的方法。 80-85% 或更高的数据命中率, 90-95% 或更高的索引命中率通常被认为对一个 OLTP 环境很好,当然可以通过计算缓冲池快照的数据得到对单独的缓冲池的命中率。
虽然那些度量监视元素通常都很有用,不过对于像数据仓库这样经常允许大表查询的系统,数据命中率经常会低得不可救药。因为数据是首先读到缓冲池然后在为其它数据腾空间被回收之前不再使用。
3. 通过
(POOL_DATA_P_READS+ POOL_INDEX_P_READS +
POOL_TEMP_DATA_P_READS + POOL_TEMP_INDEX_P_READS)
/ COMMIT_SQL_STMTS
(POOL_DATA_WRITES + POOL_INDEX_WRITES)
/ COMMIT_SQL_STMTS
得到每个事务的缓冲池物理读写。
这些度量监视元素和缓冲池的命中率都非常相似,但是目的略有不同。我们可以谈论命中率的目标值,不过每个事务的读写目标值没有相似的可能。为什么我们要被这些计算而困扰呢?因为磁盘 I/O 是数据库性能的一个主要因素,用多个角度对它进行观察是有好处的。同样的,那些计算包也括了写入操作,否则命中率只与读取有关。最后,如果孤立地看,它非常难以判断。例如,是否一个 94% 索引命中率值得去提高。如果每小时仅进行 100 次逻辑读,并且其中 94 次在缓冲池中,去保持最后的 6 次把它们变成逻辑读不是浪费时间。然而,如果 94% 的索引命中率是对每个事务执行了 20 次物理读(可以进一步被划分成数据,索引,常规,临时)统计得来,缓冲池命中率很可能值得进行一些研究。
这里要注意,度量监视元素并不只有物理读写,不过对于每个事务都规格化了。我们通过许多度量监视元素遵循了这一趋势。目的就是把对度量监视元素的数据收集从持续时间和系统繁忙程度上分离开来。通常这会得到保证,我们将的到相似的度量监视元素的值,而不管我们是否非常精确的知道数据怎样以及何时收集。当然在数据搜集过程中的时间连贯性是很好的事情,然而标准化将这种需求从“关键”减到“很好”。
4. 通过 ROWS_READ / ROWS_SELECTED 来计算数据库在行查询的行读取命中率。这给我们的计算表明了为了找到匹配的行从数据库表读取的平均行数。数字越低表明查找数据越有效,并且通常表明使用索引会更有效。例如,系统作了很多表查询而且需要扫描上百万行的数据以判断是否符合结果集的要求,在这种情况下这个数字就会非常的高。另一方面,对表的访问是通过完全匹配的唯一索引实现的,在这种情况下这个统计结果就非常的低。注意,那种只访问索引的查询计划(不需从表读取行)不会增加 ROWS_READ 。
在一个 OLTP 环境中,这个度量监视元素的结果不高于 2 或 3,就表明大多数访问都是通过索引而非表扫描。这个度量监视元素是一个简单的方法来监控访问计划在一段时间内的稳定性。
5. 要计算每个事务花在排序上的总时间。这是一个处理排序统计信息的有效途径,因为任何额外的开销都是由于被自动包括在内的溢出排序造成的。也就是说,你可能也想收集 TOTAL_SORTS 和 SORT_OVERFLOWS 来简化分析,尤其是你的系统过去发生过排序问题。
6. 通过
1000 * LOCK_WAIT_TIME / COMMIT_SQL_STMTS
来计算每 1000 个事务锁等待的总时间。
过多的锁等待时间经造成成较差的反馈时间,所以监控非常重要。注意我们标准化 1000 笔事务是因单个事务的锁等待时间一向很低。放大到 1000 笔事务给我们一个更容易把握的简单衡量。
7. 通过
1000 * (DEADLOCKS + LOCK_TIMEOUTS) / COMMIT_SQL_STMTS
计算每千笔事务发生的死锁和锁超时数目。
虽然死锁在大多数生产系统中比较少,锁超时却很经常。应用程序通常不得不以相似的方法处理它们 - 重头开始运行这个事务。监控这种较少发生的情况有助于在 DBA 还没有注意到时就避免许多死锁 / 锁超时在系统上造成明显的额外负载。
8. 通过
1000*POOL_DRTY_PG_STEAL_CLNS/COMMIT_SQL_STMTS
计算每千笔事务中触发的‘ dirty steal ’操作。
一个‘ dirty steal ’是触发缓冲池页清除的最差方法。本质上,SQL 语句的处理需要新的缓冲池页面操作是不连续的,当更新发生在牺牲页面则将写入磁盘。如果 dirty steal 被允许频繁发生,它们将对吞吐量和反映时间产生明显的影响。因此,它们在我们需要提防的列表中。
9. 通过
1000*PKG_CACHE_INSERTS/COMMIT_SQL_STMTS
计算每千笔事务的包缓存插入。包缓存插入是系统正常执行的一部分;然而,如果数目过大这将明显的消耗 CPU 时间。在很多良好设计的系统中,一旦系统处于稳定运行状态,只会发生很少的包缓冲插入。因为系统是使用 / 重用静态 SQL 或先前准备好了的动态 SQL 语句。 SQL 编辑和包缓存插入不能避免。然而,这个度量监视元素专门监视第三种状态-应用程序无意识造成的不可重用的准备语句或者经常使用的 SQL 语句中的不重用参数标记搅动包缓存。
10. 通过
LOG_WRITES/COMMIT_SQL_STMTS(LOG_WRITE_TIME_S + LOG_WRITE_TIME_NS / 1000000.0) /COMMIT_SQL_STMTS
计算每个事务的活动日志数。
事务日志很有可能成为系统瓶颈,无论是因为
高度活跃,或者不正确的配置,或是其它什么原因。通过监控日志活跃程度 - 日志写的次数和写的时间 - 我们能发现问题,不管是 DB2 这边的(也就是,应用程序发起的日志请求增加)还是操作系统那边的(经常由于硬件或者配置问题导致的日志文件系统性能降低)。
11. 通过
sysibmadm.snapfcm_part.TOTAL_BUFFERS_SENT
sysibmadm.snapfcm_part.TOTAL_BUFFERS_RCVD
来计算在 DPF 上,分区间的快速通信管理器发送和接收缓冲请求块的数目。这些结果给出了集群中不同分区间的数据流的速度,通常的也可以得出数据是否平衡。从不同分区接收到的缓冲请求块的数目如果明显不同,这可能预示哈希分布到每个分区的数据总量发生了倾斜。
12. 注意,查询 sysibmadm.snapfcm_part 提供了所有系统分区对的流信息-不仅是发送也包括了当前节点的接收,这也是 GET SNAPSHOT FOR FCM 得到的。像下面列子为 DBPARTITIONNUM 添加一个谓词来返回当前节点的数据。
select DBPARTITIONNUM, FCM_DBPARTITIONNUM, TOTAL_BUFFERS_SENT, TOTAL_BUFFERS_RCVD from sysibmadm.snapfcm_part where DBPARTITIONNUM = current DBPARTITIONNUM
如上面提到的,虽然 DB2 监视元素提供了大量的关键运行数据, 增加其它类型的数据收集同样重要。首先,我们需要 DB2 在一个正常基础上抓取它自己的配置信息。获得数据库和数据库管理器配置的正常的备份,DB2 注册变量和模式定义帮助提供我们所有更改的历史记录,并有助于解释监控数据变化的原因。
其次,监控整个系统负载同样非常重要。如果 CPU 或者 I/O 的使用达到饱和,这将造成系统瓶颈,仅用 DB2 快照来探测可能会比较困难。所以,最佳实践就是,在基于 UNIX 的系统上正常地使用 vmstat 和 iostat(对网络问题使用 netstat) 或者 windows 上的 perfmon 来监控系统负载。一般情况下,比起精确的匹配通用值,你将更多的去寻找什么样的改变对于你系统正常的。
最后同样重要的是,在商业逻辑层面,从基于 DB2 的吞吐量和反映时间标准的意义上来说,抓取应用程序的性能视图也非常重要。它有和终端用户直接相关的好处,以及它通常包含了所有可以造成瓶颈的因素,比如演示逻辑、应用服务器、Web 服务器、多层网络、等等。 这数据在设置或者验证一个服务层协议的过程中可以非常重要。
以上度量监视元素显示了在一个正在进行基础上的核心数据集。虽然快照每五到十五分钟收集一次,监视元素和系统负载数据依然结合的很紧密。在大多数系统中数据总量与时间的推移毫无关系。同样的,通常搜集这些数据将增加 1% 到 3% 的额外 CPU 开销,对于收集这些重要的系统度量监视元素相关数据来说,这是很小的代价了。因为配置信息一般很少变动,所以一天搜集一次通常就足够了,这样做在不产生多余数据的情况下这是有好处的。
根据你的系统环境情况,你或许会发现对那些核心度量监视元素之外收集附加信息是有好处的。
如果我们打算向下钻取并挖掘出额外的监控信息,比起提前预料哪些域可能有需求并只收集那些信息而言,最简单的就是搜集所有管理视图中我们感兴趣的元素。
基本上前面提到的所有单独的监控元素都是基于一个单分区环境提出来的。同样的我们搜集的大量非 DB2 性能数据,如 vmstat 和 iostat,也都是针对单个操作系统实例的统计信息(虽然或许跨了多个逻辑分区)。这对匹配我们用来控制系统的 DB2 配置参数有监控粒度的意识是有好处的。然而在 DPF 中我们同样必须能监控分区间的活动,比如为了能发现分区间的数据量不平衡,等等。
幸运的是,我们从管理视图中收集的 DB2 监控信息包括了一个 DBPARTITIONNUM 列值既能帮助我们根据分区号码查询监控信息,又能对分区间进行比较。
一般情况下,我们期望在同一个分区组中的所有分区的监控统计信息能相对一致。明显的不同可能意味着数据倾斜。我们需要跟踪的分区间的比较信息的例子包括:
如果通过这些度量监视元素我们发现任何数据分区看起来比同一分区组中最不活跃的数据分区明显更加活跃(例如,忙碌 10-20%),尤其是如果这个比较忙碌的分区 CPU 或者 I/O 出现饱和,那么这个数据分区很可能需要检查数据倾斜,找出每个大的多分区的表哈希分布到各个分区的行数将验证数据倾斜是否存在。
select count(*),dbpartitionnum(P_PARTKEY)from tpcd.partgroup by dbpartitionnum(P_PARTKEY)
DB2 白皮书‘物理数据库设计最佳实践’讨论了如何使用 DB2 Design Advisor 来在你系统中选择正确的分区键,以避免数据倾斜同样最小化 non-collocated 连接。
select count(*),dbpartitionnum(P_PARTKEY)from tpcd.partgroup by dbpartitionnum(P_PARTKEY)
第二部分我们将介绍问题诊断。
就算是配置最仔细的系统也终究会发现它仍然需要一定的性能调优,并且这时我们已经搜集了的运行监控数据,将来非常便于搜集。
保持一种系统的方法来调优和进行故障诊断对我们非常重要。当发生了一个问题,为了解决这个问题,很容易随意的进行调整。然而,当我们这么做了,事实上定位到问题的可能性非常低,甚至让问题更糟糕。性能调优的一些基本原则:
性能问题往往分为两大类:影响了整个系统的问题和只影响了部分系统的问题。比如某一特定应用或 SQL 语句,在研究的过程中-种类型的问题可能转化为另外一种类型的问题,或者相反。例如造成整个系统性能降低可能是一个单独的语句,或者是整个系统的问题只是在一个特定的区域被发现。
下面我们从整个系统的问题开始。
我们发现的所有导致性能降低的原因的方法就是从高层入手并逐渐提炼我们的诊断。这个“判断树”策略可以帮助我们尽可能早的排除那些不能解释我们所看到症状的因素,适用于整个系统或者更加局部的问题。我们将把瓶颈分成下面 4 种普通类型:
在开始一个对 DB2 调查之前,首先考虑一些准备问题常常是有帮助的,比如:
磁盘瓶颈的基本症状是:
可能最终我们可能需要添加磁盘,但现在我们将检查我们是否能通过调优 DB2 系统消除这个瓶颈。
如果存在一个磁盘瓶颈,系统管理员可以帮忙映射一个繁忙设备镜像的文件系统路径。从这里你可以决定 DB2 如何使用这些受到影响的路径 :
我们将分别考虑这几种情况。
为了判断是什么导致容器成为瓶颈的,我们需要判断都有哪些表存储在这那个表空间而且最活跃。
进一步向下钻取,我们需要找出什么造成了这个表的高水平的活跃程度。是动态 SQL 语句造成的高度活跃?通过 sysibmadm.snapdyn_sql.TBSP_ID 查询动态 SQL 快照,来找出我们感兴趣的那些涉及这个表的语句:
select … from sysibmadm.snapdyn_sql where translate(cast(substr(stmt_text,1,32672) as varchar(32672))) like ‘ %<tbname>% ’ order by …
列返回能包含行的读和写,缓冲池活跃程度,执行时间,CPU 时间,等等。我们能在列上使用 ORDER BY 子句,比如 ROWS_READ,ROWS_WRITTEN 和 NUM_EXECUTIONS 来集中那些对表有最大影响的语句。注意我们假设这里的表名在 SQL 语句的头 32672 个字符中。这个假设虽然不完美,却在大多数情况下正确,也是需要使用 LIKE 。
select … from sysibmadm.snapdyn_sql where translate(cast(substr(stmt_text,1,32672) as varchar(32672))) like ‘ %<tbname>% ’ order by …
是否是静态 SQL 语句导致的高活跃程度?在这里我们需要使用系统编目表和 db2pd 来找出哪写语句最活跃。查询 syscat.statements, 参考那些我们关注的表:
select PKGSCHEMA, PKGNAME, SECTNO, substr(TEXT,1,80) from syscat.statements where translate(cast(substr(text,1,32672) as varchar(32672))) like ‘ %<tbname>% ’
一旦我们有了涉及到我们感兴趣的那些表的静态 SQL 语句的包名和片段数字,我们就可以使用 db2pd – static 来找出它们中哪些是高度活跃的。 Db2pd – static 的输出都有一条从实例启动并执行过的每一个静态 SQL 语句的记录。 NumRef 计数器这条语句已经运行了多少次,并且 RefCount 计数器显示了当前有多少 DB2 代理程序正在运行这条语句。监视 db2pd – static 结果中的每一条调用记录。 NumRef 值的迅速攀升、 RefCount 的值经常超过 2 或 3,往往表明这是一个高度活跃的语句:
select PKGSCHEMA, PKGNAME, SECTNO, substr(TEXT,1,80) from syscat.statements where translate(cast(substr(text,1,32672) as varchar(32672))) like ‘ %<tbname>% ’
如果我们能确定并得出一个或多个 SQL 语句导致了 I/O 瓶颈,下一步我们需要确这个语句是否可以被优化以降低 I/O 。这个语句是否发起了一个不期望的表扫描?这可以通过用 db2exfmt 检查查询计划以及比较这个问题语句的 ROWS_READ 和 ROW_SELECTED 来验证。由于在表扫描中使用了过时的统计信息或有索引问题,经常在临时查询的时候不可避免会发生表扫描,但是一个导致过多 I/O 并造成瓶颈的重复查询还是应该被讨论的。另一方面,如果受到的影响的表非常小,那么增加缓冲池大小对减少 I/O 和消除瓶颈或许已经足够了。 详情参考这里对于查询优化和物理设计的最佳实践文章。
在我们讨论索引容器之前,先介绍两个数据容器磁盘瓶颈的情况:
在后面懒惰系统的瓶颈章节,有更多关于如何诊断和解决这两个问题信息。
一个发生在容器中的瓶颈,更多的可能是表活跃而不是索引活跃,但是一旦我们排除了表活跃的原因,我们就应该调查是否是索引活跃造成的问题。应为我们没有索引快照可以一用,就不得不通过间接的发现问题。
select dbpartitionnum, tbsp_id, tbsp_name, pool_index_p_reads, pool_index_writes from sysibmadm.snaptbsp T where T.tbsp_id = <tablespace ID of hot container>
一个很大并不断增长的 POOL_INDEX_P_READS 或 POOL_INDEX_WRITES 值表明这个表空间有一个或多个‘忙碌的索引’。
查询 syscat.tables 和上面的 snapcontainer.TBSP_NAME 匹配 INDEX_TBSPACE 。
select t.tabname, i.indname from syscat.tables t, syscat.indexes i where t.tabname = i.tabname and coalesce(t.index_tbspace, t.tbspace) = <name of table space with hot container>
索引扫描通常很划算,所以基于这一点研究是否能在缓冲池中放入更多的索引而非直接从硬盘读取是很合理的。增加缓冲池的大小,或为索引指定专门的缓冲池,可能足以降低 I/O 来消除平均。注意,在数据仓库环境中的索引通常非常大,分配足够的缓冲池来消除 I/O 不大可能。在那种情况下,通过增加额外的容器以提高磁盘 I/O 带宽来消除瓶颈或许更加有效。
在我们找到了一个‘ hot table ’后,如果我们不能通过调优消除索引 I/O 瓶颈,或许我们需要更进一步的向下钻取,以找到导致索引 I/O 的 SQL 语句。不幸的是,我们并不能再一次像之前我们所做的那样只挖掘 SQL 语句文本,至少 I/O 瓶颈和具体的索引没有直接连系。
利用索引名称确定相应的表,然后用表名和上面描述的方法从活跃的表上找到可能使用这些索引的动态或静态的 SQL 语句。(这并不保证和表相关就一定会被使用。)那么我们需要使用 db2exfmt 来确定是否这些语句使用了索引。
从另一方面,如果这个繁忙的容器属于一个临时表空间,那么我们就需要考虑两个可能的原因。
select dbpartitionnum, total_sorts, total_sort_time, sort_overflows from sysibmadm.snapdb
STMM 会尽全力避免这种情况;然而如果你没有使用 STMM 来控制 sheapthres_shr 和 sortheap,你可能需要手动来增加这些值。
select dbpartitionnum, tbsp_name, pool_temp_data_p_reads, pool_data_writes from sysibmadm.snaptbsp where tbsp_id = <tablespace ID of hot container>
假设现在我们已经确定了一个发生以上类型瓶颈的容器 - 但是有时却会出现这种能情况,我们看不到任何明显的原因。没有繁忙的表,没有繁忙的索引,没有繁忙的 SQL 语句。可以调查几种可能的原因。
如果在这点上我们没有找到发生容器磁盘瓶颈具体的原因,至少我们已经排除了大多数‘可调整问题’,而且应该考虑增加而外的磁盘吞吐能力来提高这个‘问题’表空的性能。
虽然容器磁盘瓶颈很普遍,日志磁盘瓶颈却能对系统更大的影响。这是因为日志速度降低能影响系统中所有的 INSERT/UPDATE/DELETE 语句,不仅是某些表或索引。像其它类型的磁盘瓶颈最主要的症状就是 iostat/perfmon(90% 或者更高)。日志瓶颈也会造成事件监控器中的更长的提交时间,在应用程序快照中更多的代理程序处于‘ commit active ’状态。
如在这个章节提到过的对于日志配置,强烈建议在数据运行中,日志不和任何‘ active ’对像共享磁盘,比如容器,等等 。这是在发生日志瓶颈的时候需要首先反复确认的事情之一。
如果日志有它自己的磁盘,那么我们需要了解瓶颈的性质。
System Bottleneck > Log Disk Bottleneck > Large Number of Log Writes
过多的数据写入同样可以造成日志瓶颈。如果随着设备利用率越来越高,iostat 也会显示写入日志设备的数据超过 4k 字节很多,这表明比起高事务率,数据量对产生这个问题负有更多的责任。或许根据你的具体环境可以降低记日志记录数据的量 :
无论哪种情况 - 不管是日志的高写入频率还是数据写入量高造成的日志瓶颈 - 要消除问题的原因往往是不可能或者不切实际的。一旦我们确认日志配置遵循了上面描述的最佳实践,或许就需要通过提高日志系统的能力来解决问题。要么通过添加额外的磁盘到日志 RAID 队列中,要么提供一个专门的或者升级了的磁盘缓冲控制器。
DB2 诊断日志路径― db2diag.log 存放的地方 - 繁重的磁盘写入能造成整个系统的性能下降,这很难分离,因为普通的 DB2 监控元素并不跟踪它。在多分区环境中所有分区都写入同样的诊断日志路径,它一般是通过网络共享 NFS 文件系统。类似于分区间同步,从许多分区对 db2diag.log 的并发写入可能会导致很高的网络通讯和 I/O 负载,并因此降低系统性能。正如在前面配置章节提到的,解决这个问题最简单的办法就是为每个分区指定一个单独的诊断日志路径(并指定一个专门的诊断日志文件)。
设置 DB2 的 diaglevel 数据管理配置参数为 4 会增加诊断信息的数据量,这会导致明显的性能影响 - 尤其在一个大型的多分区(DPF)环境。性能急剧下降甚至可能造成 DIAGPATH 文件系统满并最终使系统停止。为了避免这种情况,你应该确认诊断日志文件系统有足够的可用空间,通过归档诊断信息或者分配一个专门的文件系统给 DB2 存放诊断信息。
CPU 瓶颈表现在两个方面:
同样我们也应该考虑到用户模式和系统模式上不同的 CPU 消耗。一种是处理器正在运行操作系统内核以外的软件比如 DB2 应用程序或者中间件,导致用户 CPU 时间增多。一种是在运行操作系统内核的时候系统内存增多。这两个在数量上是分开显示的,并且根据它们之间的分布情况,可以帮助我们找到 CPU 瓶颈的原因。用户和系统 CPU 时间比率在 3:1 到 4:1 之间是正常的。如果在有瓶颈的系统中,用户和系统时间比率高于这个区间,我们应该收件调查用户 CPU 时间增加的原因。
在 DB2 服务器上造成用户 CPU 瓶颈的许多原因可以通过抓取快照和语句事件监控器来诊断。我们可以使用应用程序快照或查询 sysibmadm.snapappl 管理视图来向下钻取,以找出是什么用户消耗了大多数 CPU 时间:
select appl.dbpartitionnum, appl_name, agent_usr_cpu_time_s + agent_usr_cpu_time_ms / 1000000.0 as user_cpu from sysibmadm.snapappl appl, sysibmadm.snapappl_info appl_info where appl.agent_id = appl_info.agent_id and appl.dbpartitionnum = appl_info.dbpartitionnum order by user_cpu desc
同样(并且更又有用),通过动态语句快照,或查询 sysibmadm.snapdyn_sql 管理视图,我们也能确定什么 SQL 语句正在使用绝大多数 CPU 时间:
select substr(stmt_text,1,200), total_usr_cpu_time + total_usr_cpu_time_ms / 1000000.0 as user_cpu from sysibmadm.snapdyn_sql order by user_cpu desc
通常情况下,我们查找一个或多个语句,它们消耗‘比它们平均份额更多’的 CPU 。这转化并增加 TOTAL_USR_CPU_TIME 和 TOTAL_USR_CPU_TIME_MS 的值
同时,我们应该考虑静态 SQL 语句。如上面所提到的,快照监控器并没有包含这类信息。所以我们需要使用语句事件监控器,或者 WLM 活动事件监控器,来收集它们的 CPU 使用信息。有一些推荐的步骤可以用来把语句事件监控器的开销减少到最小:
把所有这些放在一起,并且从 LIST APPLICATIONS 得到我们关注的连接对应的应用程序 ID,我们将得到跟下面一样的结果:
create event monitor stmt_evt for statements where appl_id = '*LOCAL.DB2.075D83033106' write to table connheader(table stmt_evt_ch, in tbs_evmon), stmt(table stmt_evt_stmt, in tbs_evmon, trunc), control(table stmt_evt_ctrl, in tbs_evmon) buffersize 512
对 WLM 活动监视器也有类似的原则。一个大的 BUFFERSIZE,单独的表空间和 TRUNC 选项都是减少开销的好思路。 WLM 活动监视器不支持 WHERE 子句,不过在活动监视器被定义的时候,在工作量或者服务类型里已经隐含了一个范围。和 WHERE 子句相同,这也能非常有效的降低性能开销和收集的数据量。注意如果在活动监视器使用了 WITHOUT DETAILS 字句 , 将提供我们所需要的 CPU 消耗的基本信息。提高到 WITH DETAILS 或者 WITH DETAILS AND VALUES 会提供其它的有用信息,但是如果监视开销堆你的环境是一个问题,那最好还是从 WITHOUT DETAILS 开始,然后在需要的情况下启用 DETAILS 或 VALUES 。
我们并不总是能够减少一个 SQL 语句请求的 CPU 量,但是在某些情况下我们可以影响它。
如果没有 SQL 语句看起来消耗了大量的 CPU,也有很多潜在问题会导致整体 CPU 消耗增加。
String procNameVariable = "foo"; String query = "SELECT language FROM " + "syscat.procedures " + "WHERE procname =" + " ‘ " + procNameVariable// inject literal value + " ‘ ";
System Bottleneck > CPU Bottleneck > User CPU Bottleneck > Utilities Running?
为了尽快完成工作,DB2 实用工具被设计成扩展良好并充分利用系统资源。那就是说在一个实用工具正在运行时,可能 CPU 使用会有显著的增加。 Load 和 runstats 是一个实用程序的很好的例子,它们经常导致高 CPU 使用,但是在正常情况下,其它的实用程序也能这样。正在运行的实用程序可以通过 LIST UTILITYES SHOW DETAIL 命令看到。
如果实用程序正在执行,我们可以向下钻取来判断它的 CPU 使用情况。在 Unix 和 Linux,在 DB2 9.5 引入线程引擎之前只需通过一个简单的ps命令,就可以看见实用程序许多的工作进程(伴随这 CPU 的使用,等)到 DB2 9.5 db2pd – edus 命令显示了 DB2 引擎中的所有线程(见DB2 Process Model),包括用户和系统的 CPU 使用。这对决定是否某个线程是 CPU 瓶颈的时候非常有用。
设置 UTL_IMPACT_PRIORITY 可以有助于限制 BACKUP 和 RUNSTATS 对系统的影响。另外 RUNSTATS 的开销和运行时间可以通过两个方法降低(1)收集统计信息时仅对那些会作为谓词的列(因此它需要统计信息)如果知道的话。(2)使用样本统计信息,也是很好的建议,在后面的“写和调优查询以优化性能”提到。
默认情况下,在 LOAD 命令将对每个 CPU 都创建一个格式化程序线程(db2lfrm),但是通过使用 CPU PARALLELISM n 选项,我们可以把格式化程序减少到 n,来为剩下的系统留出更多的 CPU 能力。注意,通常情况下,通过 UTL_IMPACT_PRIORITY 或 CPU PARALLELISM 等来限制一个实用程序会成比例的延长使用程序的运行时间。
System Bottleneck > CPU Bottleneck > User CPU Bottleneck > Temporary Object Cleanup Overhead
当一个系统临时表不再需要然后可以删除了的时候,DB2 必须从缓冲池中移除它不在需要的页面。如果这经常发生,而且如果临时表和普通用户数据共享缓冲池,会导致耗费额外的 CPU 时钟周期来解决冲突和处理页面。比起复杂查询系统,这个问题在事务处理系统更常见。如果表快照显示有很多临时表被创建和销毁,最佳实践是把临时表放到它们自己的的缓冲池里面。这会消除多于的冲突和处理开销,并对降低 CPU 实用有好处。
在大多数 CPU 受限的环境中用户 CPU 往往是决定因素,不过系统 CPU 有时也能成为决定因素。虽然我们能诊断出很多原因,但是能最终解决的只有极少数。
系统 CPU 时间高的一个原因是与之相关的 DB2 在操作系统(OS)中上下文切换率过高。一个上下文切换是 OS 用来切换它需要处理的不同任务。上下文开关被系统中不同的规则触发。然而当上下文切换得太频繁,它们自己最终可能导致消耗大量 CPU 时间。在 Unix,上下文切换在 vmstat 中在‘ CS ’列有记录。每秒超过 75,000 到 100,000 次的上下文切速度被认为是非常高了。
在 DB2 系统中导致上下文切换率高的原因是大量的数据库连接。每个连接都有一个或多个的数据库代理进程为它工作,所以如果连很活跃-尤其对于很短的事务-会导致高上下文切换率何高 CPU 消耗的结果。避免这种情况的一种方法是开启 DB2 连接集中器。它允许多个连接共享一个代理程序,因此降低了代理数目(节约了内存占用),并降低了上下文切换率。
设备中断也会导致 CPU 时间高。一个设备(如网卡)发生一个中断就需要操作系统的‘注意’。一次中断的成本并不高,然而如果中断的频率太高,系统的总的负载会非常高。幸运的是,现在的网卡何磁盘转适配器已经从 OS 中高度独立出来了,比起前几年的产品,现在只产生了非常少的中断。来自磁盘的显著中断开销很少,不过在网络密集的客户端 / 服务器系统(像许多 SAP R/3)网络中断造成的开销可能会非常高。有些步骤可以用来降低网络在服务器上造成的开销,不过这类调试超过了本文讨论的范围。在这样的场合你最好还是让你的网络管理员来定位并解决问题。
如果应用逻辑(尤其是较长的事务)能被写入一个 SQL 存储过程,这会有助于减少上下文切换和网络通信量。这么做不仅是把应用程序逻辑存入服务器,在上下文切换问题范畴,它也直接把逻辑推入 DB2 代理程序。这就消除了代理程序和客户应用程序之间的 SQL 调用和结果的进出流 - 从而减少了上下文切换。
在一个 DB2 系统中,我们通常尽可能的让系统有很少的空闲内存并努力开发系统内存。不幸的是,如果我们过多的分配了内存 - 就像错误配置 DB2 或者其它软件一样,使用了超过系统物理内存的总量 - 页清除操作将造成系统 CPU 开销(磁盘开销也有可能)。这种情况在 UNIX 上通过低空闲内存和 vmstat 动态输出众较高的页面换入 / 换出,来确定。修正的办法就是把内存分配降到触发页清除操作起点之下。
文件缓存消耗了内存是稍微有点棘手的情况。为了避免 I/O,OS 通常使用空闲内存来缓存磁盘数据。虽然文件缓存使用的内存在需要的时候 DB2 可以使用,我们总是希望避免 DB2 和文件系统在内存上发生‘拔河’的情况。由于文件系统缓存处理它自己是发生在用户模式(它不消耗系统 CPU)而虚拟内存管理又能增加系统 CPU 使用,在这篇文章前面的‘ DB2 配置’章节中建议了要避免系统缓存影响 DB2 。在 AIX 上,使用 vmo 参数 LRU_FILE_REPAGE=0(同样在上面讨论过)能有助于确保 DB2 外的系统缓存开销在可控的范围。
拥有庞大内存总量的系统 - 100G 或者更多 - 如果系统没有配置使用大内存页就会产生额外的 CPU 开销。操作系统是以页为最小粒度来管理内存的(注意这和 DB2 的页有所不同)。一个典型的页大小是 4KB -这意味着操作系统必须管理 100G 内存的 250,000,000 个页表项。大多数操作系统都支持更大的页大小,这有助于减少虚拟内存管理的开销。以 AIX 为例,支持的最大页大小达到了 16G 。这虽然在实际中几乎用不到,不过有其它的页大小可供手动选择。在大多数拥有庞大内存的系统的最佳实践是确保在启用了 64-KB 页,在 AIX 中 DB2 可以使用它们。这是在良好性能和最小化使用大页面带来的副作用之间的折衷。在 Linux 中,DB2 必须通过DB2_LARGE_PAGE_MEM来手动启用对大数据页的支持。
在 AIX 上,vmstat -P ALL 显示了系统提供并使用了的页大小是多少。如果系统使用了 64KB 的页面并且数据库正在运行,通过 vmstat – P ALL 你可以看到非常多的 64KB 页被分配。如果系统有很大的物理内存却没有使用 64KB 页,这会导致高于正常水平的系统内存消耗。
系统 CPU 瓶颈 – 总图
系统有充足的内存并得到正确的配置是良好性能的关键。否则,如果没有恰当的内存访问,数据在填满缓冲后就将转向 I/O - 在这个过程中常常会造成磁盘瓶颈。同样,虽然总量小一些却很重要的内存也被用来存储元数据以及运算结果,比如 SQL 查询计划和锁。如果它们缺少内存,系统不得不取消或销毁那些重要信息,并重新运算要不就以额外的处理来补偿-增加了 CPU 的开销。因此,一个内存瓶颈经常能把自己伪装成磁盘或 CPU 问题。
下表把我们在前面讨论过的可能由于底层内存的原因造成的磁盘和 CPU 瓶颈再回顾一下。
瓶颈类型 | 主要症状 | 内存问题潜在的造成 / 影响瓶颈 |
---|---|---|
磁盘 | 数据或索引表空间瓶颈 |
|
磁盘 | 临时表空间瓶颈 |
|
磁盘 | 日志磁盘瓶颈 |
|
CPU | 重复保缓存插入造成的 CPU 瓶颈 |
|
CPU | 过多的系统 CPU 时间花费再 VMM 上 |
|
这是最常见的有 CPU 或磁盘瓶颈症状的内存瓶颈,并且是在分析这种问题时内存问题的主要可能性。然而在内存短缺的时候也是经常发生的(像 vmstat 报告的)-伴随着低性能让我们把这放到第一的位置-是明显的症状。如果进一步调查数据(vmstat)显示持续活跃的页面调度(有可能伴随系统 CPU 使用的升高),这表示系统内存压力过大。
DB2 的内存分配分成两大类:
无论是直接指定堆大小还是启用 STMM,判断 DB2 内存实际用量的最好办法就是查看 database,database manager 和应用程序快照的内存使用部分(或 sysibmadm.snapdb_memory_pool snapdbm_memory_pool, 和 snapagent_memory_pool 管理视图),它们提供了数据库,实例和应用层面各自的配置堆大小和当前堆大小。这些让你检查配置的和当前堆和应用程序的分配,以及检查当前总的分配。
DB2 9.5 内存使用的最高限制是通过 INSTANCE_MEMORY 数据库管理配置参数,和 DATABASE_MEMORY 数据库配置参数。在大多数系统中,它们默认为 AUTOMATIC, 这意味著实例和数据库的内存的使用可以上下浮动。(它们的当前值通过 get database manager configuration 和 get database configuration 命令的 SHOW DETIAL 选项)因此,DB2 的内存管理系统是设计来避免我们在这里讨论的内存瓶颈问题。为什么仍然发生内存瓶颈?
如前面提到的,当文件系统缓存对于 DB2 这样的消费者是技术上存在的,DB2 也能成为大量文件缓存的原因(尤其对于在内存能释放给其它内存用户之前,修改的数据必须存到磁盘)如果产生了额外的内存需求,这可能导致发生页清除。
如果在这个服务器上存在很强的非 DB2 的内存需求,INSTANCE_MEMORY 参数应该被设置成 AUTOMATIC,或降低到 DB2 在系统中能使用的内存范围。
因为 STMM 被设计来处理内存压力,在需要的时候释放内存给操作系统,如果没有启动 STMM 这种情况会经常发生,或者涉及的系统(如 Solaris)不支持内存释放回操作系统,或当数据库内存需求非常动态(如,很快的创建 / 销毁数据库连接,或者数据库活跃很短周期,等。)
第四,也是最有意思的一类瓶颈,我们接下来一起来看一下‘懒惰系统’瓶颈。这表现为在前面几个瓶颈可能都不存在。没有(明显的)CPU,磁盘或者内存(或者网络,或…)瓶颈,系统也不忙。
在‘懒惰系统中’一个最常见的原因是锁争抢。幸运的是,锁争抢是很容易在快照数据中被检查到的。快照元素 lock_wait_time 和 locks_waiting 通过 sysibmadm.snapdb 分别显示总的锁等待时间和当前在等待锁的代理进程数,活动代理等待锁的百分比很高(如,20% 或者更高)与 / 或 锁等待的时间增加是发生瓶颈的明显迹象。
虽然不能判断每个语句的锁等待时间,但是通过动态 SQL 语句快照和语句事件监控器中被延长的执行时间、相关的 CPU 消耗以及 IO 活动,通常还是可以合理的判断出语句收到锁等待影响的时间。也就是说,应用程序快照同样报告了应用程序的锁等待时间,这对缩小在系统范围内引起锁等待的可能性的范围来说非常有用。我们可以从 sysibmadm.snaplockwait 视图中得到更多的锁等待信息。它显示:
注意,不像其它许多 DB2 快照监控数据 , 锁的信息的存在周期是非常短暂的。除了 lock_wait_time 是总共的,其它大多数锁的信息在锁释放后也释放了。因此,在一段时间内周期性搜集锁和锁等待快照非常很重要,连续的场景也更容易被理解。像前面所介绍的,分析大量快照数据的最佳实践是通过管理视图并把它存入 DB2 。这尤其对于来自 snaplockwait 的数据是这样,它由应用程序数据,数据库和锁快照组成,并且不能通过快照命令得到。
虽然不像其它快照类型,与仅通过锁监控开关启用快照功能相比,锁快照的总开销是抓取快照本身。所以,虽然抓取快照并存入 DB2 很平常,但是过于频繁的快照会对它自己造成瓶颈。
有很多方法有助于降低锁争抢和锁等待时间
锁升级也会成为发生争抢的主要原因。反之,经过良好设计的应用程序持有的个别行锁或许不会发生冲突,锁升级导致的块或表级别的锁常常会导致对象串行化以及严重的性能问题。数据库快照报告了一个全局的锁升级的总和(sysibmadm.snapdb.lock_escals)。通过检查写入 db2diag.log 中的消息(DIAGLEVEL 3),当锁升级发生的时候这很容易确定是哪个表上的升级 。
当一个应用程序消耗了他被允许的那一部分锁列表(取决于数据库配置参数 MAXLOCKS,它表现为锁列表大小的百分比),锁升级就被触发。因此增加 MAXLOCKS 和 / 或 锁列表可以降低锁升级的频率。同样,如上面提到的,降低应用程序持有的锁数目(通过增加提交频率,降低隔离级别,等)将有助于减少锁升级。
当锁等待的时间成为十分微妙的瓶颈的时候,死锁和锁超问题时就很难被忽略了,因为它们俩都对应用程序返回负的 SQL 码。虽然许多应用程序会简单的重试失败事务没有报出死锁并最终取得成功。在这种情况下能够最直接反映潜在死锁问题的是在 sysibmadm.snapdb 管理视图中的死锁监控元素。如上面提到的,我们建议把这作为搜集日常操作监控数据的一部分。
死锁的成本有所不同,它的成本直接和回滚的事务成正比。同样,每 1000 笔事务发生死锁次数超过一次通常意味着有问题。
死锁的频率有时可以很容易降低,通过保证所有应用程序以相同的顺序访问它们的数据 - 例如,访问(并且也锁定)行在表 Table A 中 , 接着是 Table B,接着是 Table C,等。如果两个应用程序以不同的顺序在相同对像上持有互斥的锁,它们发生死锁的风险会很大。
默认的死锁事件监控器db2detaildeadlock 将记录所有死锁信息并存在 deftdbpath(数据库管理器默认数据库路径),例如在 <dftdbpath>/NODE0000/SQL00001/db2event/db2detaildeadlock.
像所有事件监控器一样,它会带来少量的额外开销,但是能跟踪死锁带来的好处超过了这小小的性能降低。
锁超时对系统而言具有同死锁相同的破坏力。因为普通的死锁事件监控器不会跟踪锁超时,我们需要另外一个机制。 DB2 9.5 提供了一个技术用来产生一个基于文本关于锁超时的报告,它基于死锁事件监控器,在引擎中增加了其它基础构造。比起之前的版本,这极大的简化了锁超时的诊断。产生锁超时报告的流程在 developerworks:“New options for analyzing lock timeouts in DB2 9.5 ”中有描述。
比起代理程序自己读取数据,DB2 预取程序读取数据查询大量的数据对磁盘进行连续读执行的效率要高很多。这有多种原因 ,
当代理程序将需要一个页面范围的数据的时候,它会排队提出预取的请求。当代理程序需要要使用一个页面的时候,如果预取程序还没有开始它的 I/O(就是说,如果他还没有最终被预取程序取到,或如果这个请求还在预取队列),代理程序将自己读取那个页面。这会减少代理程序等待预取程序的频率(它将之等待实际进行中的 I/O)。然而,如果我们像这样回到使用代理程序 I/O,预取的所有好处都不复存在。
这种问题的症状包括:
100% * (pool_data_p_reads – async_data_reads) / pool_data_p_reads
这样可以在数据库层面通过对 sysibmadm.snapdb、或者通过缓冲池层面的 sysibmadm.snapbp、在动态 SQL 语句层面的 namic SQL statement level with 计算
这个问题的最大可能性是预取器的数目(数据库配置参数 NUM_IOSERVERS)太少。在 DB2 v9 及以后可以有 AUTOMATIC 设置,而且后来使用像表空间并行这样的元素等,来计算预取器的个数,一般情况下不再需要调整。不过,在低预取率的时候调整显得还是必要的,流程如下:
如果预取仍然低于同等操作水平,就非常需要验证 prefetchsize 是否被正确设置。DB2 Information Center对 于对这个验证流程已经进行了详细的讨论,我们就不再这里重复了。
类似于预取的另一个关于缓冲池页面清除的问题,如果强制代理进程终止它们的正常处理来执行 I/O,则通常应该有一个 DB2 的‘工作线程’来处理。然而在这种情况下,代理进程不得不进行写操作(更改页面)而非读取。这常常会涉及到类似‘页清除操作’。
应该说这个症状和上面老套的‘预取缺乏’不大一样。在一个有很多并发 DB2 代理进程的线事务处理(OLTP)环境中,缺少页面清除会导致更多的问题。如果它们不能找到干净的缓冲页就不得不自己进行页清除,这可能潜在的造成很多额外的单个页面写入容器。这意味着在这种情况下,我们可能看到一个 I/O 瓶颈,而不是一个通常意义上的‘懒惰系统’。发生的次数取决于连接的数目,页面清除程序的性能,等等。
一个相关症状是‘爆炸性的’系统活跃,如在 vmstat 中看到的。系统可能在短时间内运行很好,代理进程工作正常,在接下来的一段时间大多数代理进程会被阻塞,并自己刷新一个脏页面到磁盘。这将在 vmstat 中显示为高 I/O 等待和代理进程运行队列段时间空闲。等代理进程完成了页清除,性能又恢复如常 - 这将周期性重复。
在 DB2 ’ s 监控数据中,页清除的次数(在 sysibmadm.snapdb 中 pool_drty_pg_steal_clns)是是否出现问题最佳指示器。我们通常希望在一个流畅运行的系统中很少发生页清除操作,因此页面清除次数的任何异常的增长都由于某些原因导致的。
如果页清除下降并且发生换页操作,要检查的第一件事就是页面清除程序的数目(数据库配置参数 NUM_IOCLEANERS.)DB2 9 和之后的版本支持 AUTOMATIC 设置,这是遵循当前分区中每颗处理器一个页面清除程序的最佳实践。注意,在 DB2 9.5 中超过推荐值得多余的页面清楚程序会最终有损于性能。
在 DB2 8.2 中 DB2 支持两类页清除程序 - ‘典型’被动页清除程序(默认),和主动页清除程序。
客户端应用程序和 DB2 服务器之间的请求以及前端与后端的响应和同步流,都意味著它们都是整个系统性能的角色之一。例如,在一批应用程序的运行时中的增加请求数,可能会导致系统缓慢,不过这也可能是由于应用程序对 DB2 的请求成功率下降的原故。这类问题的症状和 ‘懒惰系统’非常接近的模式。
对 DB2 的请求成功率减少的症状包括:
如果应用程序端变慢则显示有问题,可能的原因包括
对 DB2 的请求成功率减少的症状包括:
如果有应用程序端度量标准,比如商业层事务吞吐量或响应时间可能表现为变慢。
如果应用程序端变慢则显示有问题,可能的原因包括
到现在为止,我们已经处理了系统中的整体性能问题 – 高层磁盘、CPU、内存和懒惰系统问题。但是性能问题并不总是以这样的形式出现。通常,整个系统运行正常,不过有一个用户或应用程序,或存储过程,或一个 SQL 语句 – 出现了问题。处理小范围的问题和系统范围的性能问题有什么不同?
一旦我们确定了一个或多个问题 SQL 语句,以及我们了解它们所面对的瓶颈,我们就可以应用多种在前面章节讨论的方法。尤其是涉及挖掘‘ hot SQL statements ’、hot table 的技术 – 我们关注在定位问题中涉及的因素。最佳实践:
配置:
监控:
问题诊断:
幸运的是,在本文中提出的诊断性能问题方法论用在应用程序上也一样,不管是普遍的还是特定问题。我们所需要做的就是抽取系统可以提供的监控数据的相关部分。
假设我们有一个应用程序,它运行在我们期望的级别之下。在我们可以开始诊断问题之前,需要在系统上定位这个应用程序的范围
1 .了解应用程序名字和应用程序使用的授权 ID,LIST APPLICATIONS 命令告诉我们‘ appl ID ’(例如,LOCAL.srees.0804250311139),这是定位这个应用程序详细监控数据的关键。
2 .对于特定应用程序监控数据,应用程序快照是一个极好的资源,而且通过指定刚才得到的 appl ID,我们可以专注于 我们感兴趣的连接上。
db2 get snapshot for application applid '*LOCAL.srees.080425031139'
在这里(或从 sysibmadm.snapappl 和 sysibmadm.snapapplinfo),我们可以判断很多关于应用程序的重要信息,比如在抓取快照时的正在执行的语句、缓冲池命中率、排序总时间、选择的行和读取的行的比例,以及 CPU 和花费的时间。在排序中,我们可以得到了很多和我们用在诊断系统级别问题相同的信息,然而在这种情况下只侧重我们关注的信息。
3 .为了深入研究,我们也可以使用在语句事件监控器中的应用程序 ID 作为一个 WHERE 子句的子句,只专注于我们工作的这个应用程序搜集的事件监控信息。这将向我们提供应用程序的每条语句执行时间、缓冲池和 CUP 消耗信息。
虽然我们对改变全局 CPU 消耗或磁盘活动(不要忘记,整体很好)并不关注,但是理解状况是否发生在运行中的哪个应用程序却仍然十分重要。如果系统是 CPU 受限,而且我们的应用程序是 CPU 饥饿状态,则它的性能将会受到影响。类似,磁盘活跃情况也一样。
在收集了很多应用程序快照、事件监控的跟踪后,我们现在几乎拥有和系统范围问题一样的监控数据。我们的基本目标就是判断我们应该把时间花费在应用程序的什么地方 – 这也是瓶颈所在。应用程序中的哪些 SQL 语句运行时间最长?哪些语句消耗了绝大多数 CPU,或导致了绝大部分的磁盘 I/O ?模仿我们在系统范围的判断树来回答这些问题。
本文考虑了 3 个关键范围,它们对于在理解尝试避免你的系统性能降低时候非常重要:配置、监控和性能诊断。
我们的建议包括硬件和软件配置,它们可以帮助你确保良好的系统性能。我们讨论了很多监控技术这将帮助你在操作方面和问题诊断方面理解系统性能。同样为了有步骤的,有条不紊的处理问题,我们展示了一批 DB2 性能诊断的最佳实践。
如果你的系统配置恰当而且监控良好,你就可以有效的解决可能出现的性能问题,因此减少总的拥有成本并提高你的业务的投资回报。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。