新的体系结构带来新的挑战
Edwards 认为,从客户/服务器向多层体系结构的改变影响了数据库性能优化和调整的几个重要方面 — 两个最重要的方面是资源治理以及数据库工作负载的跟踪。
暗藏的资源泄漏
Edwards 解释说:“在拥有专用 Oracle 服务器进程的传统客户/服务器环境中,保护资源的方法完全不同。Oracle 会话启动和停止过程所在的应用程序连接具有非常有限的生命期。因此,假如存在一些效率较低和较差的资源治理,比如应用程序无法关闭游标或应用程序有内存泄漏 — 那么,当连接断开时,这些都被自动清除,泄漏及低效率的影响和持续时间不太明显。在多层世界里,您倾向于拥有一个由应用服务器多次重复启动和使用的连接池。因此,假如有游标或内存泄漏,则它们会增加和持续存在,并不会消失。资源泄漏 — 如连接泄漏、内存泄漏和游标泄漏 — 具有明显的影响,并可能最终导致产品应用程序或环境发生故障。”
Edwards 经常被召来,尝试解决非常重要的硬件服务器、数据库或应用程序由于这种泄漏而无法正常工作的情况。他回忆道:“有一次,一个大型的产品级硬件服务器 — 它支持多个全天候工作的 oracle 数据库 — 由于 PGA 内存泄漏而反复崩溃。数据库应用程序和配置导致操作系统耗尽了可用的虚拟内存(物理内存和交换空间) — 我们在一个 oracle 实例中发现了内存泄漏,大小总计超过 45 吉字节!在另一个案例中,连接的泄漏使应用服务器的连接池不可用;应用程序中不良的连接治理导致应用服务器的多个实例被制约并挂起。而在另一个案例中,应用程序在不经常执行的代码体中具有大量游标泄漏。这些泄漏的最常见结果是单个连接数超出游标的最大数量 — 但有时整个 Oracle 实例会有危险。”
Edwards 认为,资源泄漏的潜在影响非常严重。“使其具有潜在危险的部分原因是,在测试或监视过程中很难发现它们,非凡是在它们与容量相关的情况下。它们往往会令人难以觉察地潜伏着,缓慢地侵蚀系统的宝贵资源,直到它们忽然膨胀堵塞,造成灾难性后果。”
跟踪损伤
跟踪和配置是调整的另外方面,Edwards 认为它们已受到体系结构变化的巨大影响。
他指出:“在客户服务器体系结构中(尤其是 Oracle 专用的服务器环境),会话与专用服务器进程具有独占的、一对一的关系。因此您可以打开跟踪功能,操作工作负载,关闭跟踪功能,然后从一个进程的一个跟踪文件中查看步骤的顺序 — SQL。您可以实际查看语句所执行的顺序。您知道该跟踪文件中只有您的语句,并且不必通过多个跟踪文件来重建您的会话。识别要跟踪的会话也更轻易,因为能够以特定的、可识别的 Oracle 用户名来执行每个用户的会话。”
他提示说:“在具有连接池的多层世界里,情况完全不同。应用程序本身并不总是明确地控制工作单元或者治理其自身的连接。应用程序端很少关注会话 — 因此,当您要进行跟踪时,您不知道是什么服务器进程将会获取该跟踪的输出。您不知道在哪个跟踪文件中 — 经常有很多跟踪文件 — 获取您的应用程序线程。此外,在一个进程的跟踪文件中,您可能拥有来自多个用户会话的步骤。因此,很难辨别哪些语句来自您自己的应用程序以及它们以何种顺序执行。更糟的是,所有的连接 — 有时同时有数百个连接 — 可能是以相同的 Oracle 用户(应用服务器用户)来执行 — 而不是以真实的、可识别的最终用户来执行每个连接。因此,您不能简单地识别和区分出需要检查的会话。”
Edwards 指出,这些复杂性给预见性的应用程序监视和容量计划造成了困难,并影响对已发现性能问题的处理。“假如您的最终用户说:‘咦,我的某些特定功能好象运行很慢。’假如没有数据库以外的补充信息,很难进行调查,并且很难了解该功能当前正在哪个连接上执行和涉及到多少个语句 — 而且难以判定问题的根源。SQL 效率不高?数据库或应用服务器有问题?假如偶然有争用和某种类型的等待事件,则可能很难进行识别和归类。判定性能为何没有达到最佳的原因已经成为复杂、曲折的过程,并且您必须使用更多的手段。”
调整的提示和技巧
Edwards 认为,有效调整多层体系结构的要害是以下三项策略:采取全局的观点、使用科学的方法论、采用从 SQL 开始工作的调整策略。
全局的方法
Edwards 说,由于多层体系结构中有许多级,常见的调整错误是每次只关注一级,而忽视了全局。“您需要具有更普遍、更全面的观点,因为您需要能够解释最终用户操作的时间。各层间通信的等待时间经常成为问题,并且这种问题不轻易测量、隔离或再现。我们可以独立查看每一层 — 应用服务器层、RDBMS 层、客户端层 — 而且可能每一层在其自身范围中都表现得很高效,但最终用户的体验仍然很糟。因此,您必须能够在所有不同层中以及在层间通信方面监视和估计时间。”
查看全局可能需要将不同小组的人们集合在一起,以便他们能够增加相互的了解。
Edwards 说:“在大多数机构中可能出现的情况是,DBA、UNIX 或系统治理员团队和网络团队都属于不同的组,他们没有必要了解其他人的事。操作系统工作人员不了解数据库工作负载,而数据库工作人员不了解操作系统的资源。网络团队也有自己单独的领域。我认为您确实需要全面了解 I/O、内存、CPU 以及网络的情况。您需要能够解释所有这些信息,了解它们,知道何时饱合或何时出故障,并知道选择什么方法来增加资源或减少问题。您越是能够使不同的团队在这方面协同工作并相互了解,效果就越好。”
科学的方法
Edwards 强调的调整的另一个方面是采用科学的方法。
他说:“您必须拥有评估性能问题并对其进行量化的经验化科学方法学,而不是基于假设或直觉而采取行动。所包含的部分原因是确保您得益于历史方面的性能情况:工作流状况如何、已经完成了多少工作、资源消耗程度有多大。假如您没有应用程序的历史资料,您就不了解如今情况的相对优劣,以及它们与以前的情况有多少差别。”
在查看历史数据时,Edwards 建议在具有工作流时应该主要关注工作流的模式。“您需要建立使工作流可猜测并具有一致性的方法。是否天天都有非常相似类型的指令事务,或者事务是高度即席的查询,其工作流的复杂性变化很大?在我的经历中,J2EE 和多层应用程序可能有一定程度的可猜测性、指示性,并且它们经常在本质上是事务型的,因此研究历史数据很有用处,用于建立将会洞察调整过程和容量计划的模式。”
SQL 居先的策略
在开始进行调整过程的实际步骤时,Edwards 果断主张从 SQL 开始。
他承认:“要调整环境,您总有事可做。如更改 I/O 规划、更改高速缓存的内存结构等等。但是当您更改 SQL 时,可以显著影响工作负载,假如您用相反方式来做,结果将完全相反。90% 的时间里,您只需通过调整 SQL 本身,即可显著减少资源的消耗,从而改变资源需求的情况(内存、cpu 和 I/O)。”
Edwards 解释说,从数据库端来看,多层体系结构中调整 SQL 的基本目标和方法与客户/服务器方式没有显著差别。
他指出:“在这种情况下,客户端不是 SQL 形式的应用程序或者 Visual Basic 应用程序和 C 程序,而恰恰是应用服务器本身。但是它仍在进行 SQL 调用,或者通过 SQL*Net 或者通过 JDBC 瘦客户端。我们需要在数据库端使用的方法学与此很相似。我们需要监视正在运行什么语句,并查看哪些语句成本最高(资源密集)。我们需要查看总计的资源消耗,查看我们是否当时被限制在某些点 — 内存、CPU、磁盘或网络 — 以及是否发生争用。”
为找出正在运行的成本最高的 SQL,Edward 从语句级数据收集开始。
他说:“完成这项工作有许多方法,或者通过手工创建的查询,或者使用 STATSPACK 或那些收集当前所执行 SQL 的统计信息的第三方实用工具。您可以根据逻辑 I/O、物理 I/O、分析与执行的比率和计数以及其他数值,找出成本最高的 SQL。您可以查看 I/O 的大小和数量、读写比率以及内存的数量。但是,假如有一个我可以看作 SQL 成本代理的因素,那么我查看它执行的逻辑 I/O 的数量 — 对我来说,这是可以用于了解特定语句相关影响的最有指导意义的单个量度。”
Edwards 说,在识别出哪些 SQL 语句的成本最高以后,就应该设置调整目标的优势级。“我们看着一条语句并提问:它是每月运行一次还是每年运行一次,或是天天运行数百次?您必须提供某种加权因素,以评判需要满足哪些语句 — 这些语句在形成历史观点方面很有用处。”
Edward 建议,在找到需要调整的 SQL 语句后,在可能的情况下应手动调整这些语句 — 这可能意味着完全优化它们。“经常出现的情况是,您需要退回去并且说:‘好吧,现在的总体业务目标是什么?’假如您正在调整一个包括十步的过程中的某个步骤,而您实际上可以将它压缩为包括两步的过程,则全局观点会为您节省很多时间和精力。”尽管调整高成本 SQL 是 Edwards 最优先考虑的,但他提示并不是所有的高成本 SQL 都可以更改。“不能更改的 SQL 可能是硬编码应用程序中的 SQL 或者是由 EJB 容器或类似工具生成的 SQL。在这种情况下,您可能希望更改数据或创建其他结构,这些结构能够导致执行计划的更改并具有更高的效率。”
其他调整策略
Edwards 的调整策略超越了 SQL 调整,他认为这时候“无法再进一步实质性地调整 SQL 工作负载 — 意味着应用程序的工作负载已经稳定。这是服务器环境调整 — 数据库、硬件和操作系统 — 最有效的时候了。”
在这种情况下,进行索引似乎是显而易见的选择,但 Edwards 建议仔细思考进行索引是否是对所怀疑问题的正确选择。