内容


Domino 应用程序性能故障检修

第 1 部分:故障检修技术和编码技巧

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: Domino 应用程序性能故障检修

敬请期待该系列的后续内容。

此内容是该系列的一部分:Domino 应用程序性能故障检修

敬请期待该系列的后续内容。

这些年来,我们看到过很多杰出的 Domino 应用程序。有创造力的架构、精心构思的用户界面、准确的代码 — 我们已经见过所有这些甚至更多。然而,我们也看到了许多有性能问题的 Domino 应用程序。从架构到代码低效,很多原因导致了这些问题。由于难于获得和了解故障检修工具和技术,用户(及任何解决这些问题的人)经常陷入困境之中。在这个由两部分组成的系列文章中,我们将注重于索引和编码技术,以及用来帮助用户查找问题代码的新工具。

在我们的系列文章的第 1 部分,将解释可靠的性能故障检修过程,以及一个如何按照此过程为真实的客户应用程序快速减少性能问题的案例。我们还讲述了一些技巧,帮助优化视图索引和代理。本系列文章的第 2 部分将介绍 Lotus Notes/Domino 7 用于监视和解决代理性能问题的新工具。本系列文章适用于经验丰富的 Notes 应用程序开发人员。

识别问题

速度缓慢的应用程序(或服务器)会在 IT 组织中触发一连串的电话呼叫,包括给 Lotus/IBM 的电话支持和咨询服务。有两种方法可以处理这个问题。第一种方法是识别瓶颈然后扩展它们。从定义看出,这是一个持续的过程,但是通常这里会有一个相当清晰的收益平衡点。第二种方法是小心构筑和计划应用程序和服务器,从而使您不会首先陷入到这些瓶颈中(说起来容易但做起来难)。这里我们主要使用前一种方法,但是也会给一些建议来实现后一种方法。

我们发现下列四个步骤可以帮助识别瓶颈。

了解详细信息

当被告知应用程序(或服务器)速度缓慢时,要做的第一件事情是与熟悉该应用程序的人详细地谈一下,并询问一些突出的和详细的问题。通过多年来询问这些问题,我们发现通常会在下面三个关键领域找到有意义的答案:

  1. 问题在哪(拓扑结构或因为视图按年代顺序排列)?我们想确定减速是否发生在 Domino 应用程序、服务器、网络中等等。我们发现一些有帮助的问题是:
    • 出现减速时,是在该服务器上执行的所有操作都出现了减速,还是仅有一个应用程序中的操作出现了减速?
    • 如果该服务器上的所有操作都受到了影响,那么其他服务器怎么样?甚至文件服务器?
    • 如果网络中的所有操作都受到了影响,那么该网络与您所在大厦、副楼或楼层中的人们是否是隔离的?
    • 稍微变化一下角度,这些问题是否都发生在一天的特定时间?仅发生在特定类型的计算机上?都是比较老的计算机上?或者具有相同 OS 的计算机上?
  2. 问题在哪(操作)?我们想确定应用程序的哪些区域或哪些特定用户操作与性能问题有关。我们想要详细信息,例如:
    • 打开数据库时,减速是否会影响您?打开视图时呢?在视图中滚动时呢?如果影响,是所有视图还是特定视图受到了影响?如果仅有特定视图受到影响,至少应该对这些速度缓慢视图中的一个或两个进行标识。
    • 创建、编辑、保存或读取文档时是否会发生减速?如果发生,指定这些操作。同时,对于每个表单的文档都这样吗?还是仅有某些特定文档会发生减速?当然,也要指定是哪些表单出现减速。
    • 单击特定按钮时是否会出现减速?这是一种想象的情形,因为如果我们可以标识出特定按钮,则需要检查特定的代码。
  3. 什么发生了变化?几乎在每个案例中,客户都认为没有什么值得注意的东西被更改了。如果该客户知道一些重要的东西已经被更改了,他将会跟踪该更改,而不是求助您!可以帮助查出事实的一些焦点问题可能包括:
    • 此应用程序(或服务器)的速度是否一直缓慢?
    • 如果不是,是否当添加更多用户时它会慢下来?
    • 最近是否向该应用程序添加了新功能?
    • 最近软件或硬件是否进行了升级?

推理

收到关于上述问题的答案后,便可以开始整理一个或多个关于问题的假定。例如,如果听说只要某人处理 Main 表单的文档,应用程序就会慢下来,这可能让您得到下面的结论:需要处理关于该表单的代码的某些东西。然后您可以让应用程序开发人员来检查该表单,以改善性能。或许只要用户单击特定按钮,应用程序就会慢下来,这种情况您可以直接查看该按钮代码。

另一方面,如果听说在一天中执行任何操作时性能都好像会经常降低,或者服务器整体速度减慢,这可能表明服务器任务过载。首先要检查的一个任务是索引。通常很少会以导致频繁甚至持续的索引的方式来编写应用程序,并且随着用户和数据负载的增加,索引工作会变得越来越难。实际上,我们已经看到在生产服务器中,索引程序(indexer)会持续工作以保持视图的更新。在这些情况下,服务器无法为用户请求提供 CPU 周期,用户经常会觉得服务器没有响应。

数据收集

在任何情况下,任何所到之处,您都想收集数据来验证您的理论或为其争辩。这是个重复的任务,所以理想情况下,您总希望步骤 1 和 2 只花费几个小时,而不是几天。

根据您的理论,可以使用不同的工具来收集数据。在 Lotus Domino 的任何版本中,都可以自由的使用 Notes.ini 日志,这将会非常有价值。如果您认为视图索引有问题,可以开启 log_update=1。将此值放入到 Server Configuration 文档中时,同时会将此值放入服务器的 Notes.ini 文件中,在重新将其删掉之前,可以使其一直保留在那里(因为此设置通常不会向日志文件写入过多信息,许多客户都将此设置无期限地放在那里)。然后检查该日服务器的 log.nsf 的 Miscellaneous Events 视图,以查看索引程序在这天做了什么以及做了多长时间。可能您会看到如下条目:

01/04/2005 11:35:47 AM  Updating views in Merkle\CM.nsf
01/04/2005 11:36:22 AM  Finished updating views in Merkle\CM.nsf
01/04/2005 12:02:17 PM  Updating views in Merkle\CM.nsf
01/04/2005 12:02:39 PM  Finished updating views in Merkle\CM.nsf
01/04/2005 12:36:04 PM  Updating views in Merkle\CM.nsf
01/04/2005 12:36:15 PM  Finished updating views in Merkle\CM.nsf

注意:通常,在这六行之间您会看到数百行(如果不是数千行)的其他日志信息,所以搜索并复制/粘贴这些信息到文本文件中,从而可以将与此类似的相关行收集到一起,以便于分析。

无论是复制还是代理管理器,每个 Domino 任务都有与此相似的记录能力,所以收集其中任何任务的数据都相当容易。

分析并重复

分析收集的数据,确定是否在跟踪,然后重复询问问题、推理、收集数据及分析该数据的过程。

故障检修示例

在过去许多年里,我们检查了许多客户应用程序以帮助进行性能优化。我们看到的大部分性能问题都属于下面几类:

  • 表单设计
    这是其他时间要讲的一个主题。一般来说,需要优化编辑和读取模式的性能,同时考虑典型应用。
  • 代理
    我们在本文中讲述故障检修和一些编码技巧。
  • 视图索引
    我们也在这里讲述故障检修和一些编码技巧。

下面是一个实际客户案例的问题:客户报告一整天用户在应用程序中的所有活动的速度都很慢。虽然有时性能很好,但一天中较忙的时间通常都是低性能。进一步的询问指出,实际上任何客户操作都可能速度快,也可能速度慢,这使我们不必去追踪表单、代理及各种其他数据库操作背后的代码,而我们确信至少有一个服务器任务可能在过度的使用服务器资源。用户报告打开视图和在视图中滚动时经常会很慢确定了这个原因。我们决定追踪视图索引。

使用 log_update=1,客户收集某天的索引数据,然后我们查看这些数据并将与他们的数据库 Merkle\CM.nsf 相关的所有行提取出来。本文前面显示了其中六行。我们使用“pdating views in xyz.nsf”作为关键字进行搜索,其中 xyz.nsf 是我们感兴趣的应用程序的路径和文件名。我们删除了前面字母 u,这样可以不用考虑大小写。

我们发现这六行引人注意的是,它们都指出更新任务的周期是 30 分钟。通常,更新任务每 15 分钟运行一次,而且这在 Domino 服务器上是无法配置的。如果您看到更新任务在周期中花费多于 15 分钟来返回特定数据库,则只可能有两种解释: 数据库在一段时间内没有活动,从而对于一个或多个周期,更新任务跳过了该数据库。这在晚间或周末确实是您所期望的,但是对于一天中间繁忙的数据库,这就很可能不对了。

另外一种情况是更新任务花费多于 15 分钟来更新所有数据库中需要更新的所有视图。在这些时间里,通常将会看到性能迟缓,因为服务器正忙于满足视图索引需要。

在这个客户的情况中,我们确信后一种情况是对的,这对于他们来说是有用的信息。但这不能解决问题。下一步就是再次开始问题、推测、数据收集和分析这四个步骤的过程。

如果更新任务花费大约 30 分钟完成,我们可以查看同一 Miscellaneous Events 文档中的日志文件以了解花费这么长时间的原因。一种可能性是看到了极多的数据库和视图。数量如此之多以至于虽然每一个索引的建立速度都很快,但是要为所有的数据库和视图建立索引则必须花费 30 分钟。这使我们会询问是否服务器数据库过载了。

另一种可能性是虽然没有如此多的数据库和视图,但是它们非常耗费时间。如果这是我们的看法,我们可能将记录改为 log_update=2,这样将为建立索引的每个视图记录时间戳,而不是在数据库级别进行记录。然后可以检查出花费如此长时间建立索引的特定视图。此设置通常会向 log.nsf 写入大量数据,因此,应该尽快关闭,或者至少减少为 log_update=1。

而第三种可能性是这一天中的确进行了大量数据更改。

我们应该从我们的记录以及直接从客户那里得出这些暗含问题的答案。他们可能不知道数据的数量是多少时,才属于过多,但他们可能告诉您应用程序是如何使用的,并提供每天所更改的数据量的近似值。

在我们客户的情况中,增加的记录中许多指向了花费很长时间来建立索引的视图。我们检查了那些视图(一些视图甚至不在他们的主要应用程序中),发现这些视图的编码导致每次访问这些视图时都要强制完全重新构建每个视图。因为它们的选择或列公式中有 @Now 或 @Today,每次用户打开这些视图时,该视图都必须从头重新构建,这是个非常耗费时间的过程。更糟的是,这是一台 Domino 5 服务器,而在版本 5 中,只要更新任务刷新数据库中的任何视图,这些时间/日期敏感的视图都会进行更新。

了解了这一点,客户记录了这些视图,使他们在满足他们的业务需要时,又不用时间/日期敏感的视图。性能立刻显著改善。解决这个问题共花费了我们大约 5 天时间,再加上他们的开发人员编码和测试成功的新方法又用了 10 到 20 天时间。

编码技巧

经过多年的观察及测试,我们发现了许多非常通用且重要的编码方法,就性能来说,它们可以很容易做到很好或者糟糕。下面是其中一些方法:

  • 时间/日期敏感视图。
  • 单击排序视图列。
  • 在代理中获取文档集合。

时间/日期敏感视图

如果视图的视图选择公式或任何列公式中有 @Now 或 @Today,则该视图被称为时间/日期敏感视图。从性能角度看,其暗指当由于任何原因刷新视图时,该视图会完全重新构建。重新构建视图可能会花费 50 到 100 秒,而没有 @Now 或 @Today 公式的同一视图的刷新则可能仅花费 100 毫秒。考虑到视图每天要刷新数百次,这将是个非常大的差别。

例如,假设用户打开一个视图;该视图将刷新。用户在视图中编辑和保存文档;该视图将刷新。用户看到闪亮的蓝色重新加载箭头并单击它;该视图将刷新。在以上任何一种情况中,如果视图必须重新构建,而不只是刷新,则该用户可能要等很长时间,该服务器可能也要加载很多东西。

在 Lotus Notes/Domino 6 中,更新任务完全忽略这些视图(请参见前面部分关于更新任务的说明)。这意味着该视图不会因为它的存在而影响性能。在 Lotus Notes/Domino 6 中,视图仅通过用户操作而导致问题。

另外,在 Lotus Notes/Domino 6 中,索引选项(自动刷新视图;自动,至多每 n 个小时一次;或手工)也很好用,这意味着可以手工刷新时间/日期敏感视图,用户将可以立即打开视图,而无需刷新,因此,无需服务器进行大量的工作。当这样设置索引选项时,仅当用户按 F9 或单击蓝色的重新加载箭头时,才刷新视图。普通视图还是由更新任务每 15 分钟刷新一次,但是因为更新任务跳过这些时间/日期敏感视图,所以该过程也不会引起刷新(或重新构建)。

最好不要包含过时的视图,但是如果它在 Notes/Domino 中是个可实行的选项,这实际上也是件好事。如果需要时常刷新视图,可以运行代理来更新视图或将视图的索引选项设为自动,至多每 n 个小时一次。

单击排序视图列

这是个非常好的功能,虽然它不是 Notes/Domino 6 的新功能。它允许用户基于进行了这样标记的任何列对视图重新排序。该功能速度很快,为用户提供如此快速的重新排序,以至于很容易相信该功能对性能有益。但它不是这样的。

从性能的角度看,每个小的单击可排序箭头都好像是在构建新的视图,该视图与原始视图非常相似,只是排序不同。所以,如果具有 10 MB 大小的视图且有四列标记为单击可排序(升序或降序),那么现在视图大小将为大约 50 MB,它建立索引的时间将是原来视图的五倍。如果那四列同时具有升序和降序箭头,则共有八个箭头,那么现在该视图将为大约 90 MB,将花费原始视图九倍的时间来建立索引。

您应该谨慎使用此功能。将所有视图列都标记上向上/向下箭头不一定会使应用程序更容易使用,但它一定会使应用程序更慢。特别地,您应该确保隐藏查询视图(仅由后端代码使用)没有任何单击可排序列,因为这完全是一种浪费。

获取文档集合

经过多年来分析客户应用程序,我们发现代理代码(以及表单事件中的代码,如 PostOpen 和 QueryClose)中常常需要获取文档集合,然后从这些文档中读取数据或向其中写入。事实证明您如何获取文档集合对于所编写的代码的性能至关重要。

我们要强调这一点。虽然获取适当的文档集合就性能而言好像并不重要,而集合的大小以及利用它来做什么才是唯一重要的,这看起来似乎很自然。但是恰恰相反,在代码优化方面,如何获取该集合经常可能是相当大的、很变化无常的难题。我们大概按照性能降低的顺序来讲述一些不同的技术。

如果您想获取文档的集合并需要读取一些可以显示在视图中的值,则使用 view.GetEntryByKey 或 view.GetAllEntriesByKey 获取适当的 NotesViewEntry 或 NotesViewEntryCollection 句柄,然后读取适当的 ColumnValues 是获取数据的最快方法。您可能想知道执行代码时,如果必须对此视图建立索引,是否会降低性能。我们的经验是经常可以看到在不到 100 毫秒内便完成对具有多列信息的查询视图建立(或刷新)索引。因此,我们认为这实际上不是问题。当然,您还需要创建一个搜索视图,或者一些其他视图,并且要尽可能的改进,不过拥有这些视图所能节约的成本远远超过了更新其所耗费的较少的开销。

如果不论什么原因,需要读取的数据不能合理地显示在视图上,那么您需要处理后端文档,从而可以直接访问它们的 NotesItems。在这种情况下,可以通过 view.GetDocumentByKey 或 view.GetAllDocumentsByKey 来使用 NotesDocument 或 NotesDocumentCollection。

注意:如果通过使用 set doc = view.GetNextDocument ( doc )“查看视图”,则还需要使用 view.AutoUpdate = False,这有两个原因。首先,它会大大提高速度。其次,它允许您更改文档,甚至删除文档,而您处理下一文档时代码不会失败。

就性能而言,使用 db.ftSearch 获取这些后端 Notes 文档的句柄与通过视图访问这些文档一样快。如果关键字是来自富文本字段中的搜索,这实际上是您唯一的选择。当然,使用此方法的快速性能需要更新的全文索引。使用 db.ftSearch 还需要注意复杂的语法,以及结果集合的大小是有限制的,除非使用 Notes.ini 变量覆盖那个最大值。

从性能角度看,使用 db.Search 返回小文档集合所获得的性能不好;不过,它可以执行搜索,而无需考虑正在构建的视图或全文索引,可以轻松进行特殊查询。这意味着可以对其他人拥有的数据库执行这些搜索,而您是无法在该数据库中创建视图或全文索引的。另外,如果集合很大,db.Search 则变得有竞争力。一旦集合大约是数据库中文档数的 5% 到 10%,db.Search 将成为获取集合的最快方法。这意味着在包含 100,000 个文档的数据库中,如果搜索返回大约 5,000 多个文档,则使用 db.Search 实际上将是您最好的选择。

结束语

我们希望本文中介绍的技术将使您更好地了解性能问题故障检修的过程,并希望这个分为四步的过程对您将来的工作会是个很好的向导。如果索引和编码技巧可以帮助您创建性能更好的应用程序,或许您很久之后才需要使用这个过程。但是如果您发现自己需要解决应用程序中的性能问题,请查看本系列文章的第 2 部分,了解 Lotus Notes/Domino 7 性能故障检修工具。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Lotus
ArticleID=95771
ArticleTitle=Domino 应用程序性能故障检修: 第 1 部分:故障检修技术和编码技巧
publish-date=06062005