内容


Lotus Domino 应用程序性能调优,第 1 部分

Comments

应用程序的性能是衡量应用程序在某些环境中以及特定负载下运行效率的一个度量。应用程序的性能可以度量吗?答案是肯定的,只需要一个独立的测试环境即可,而该环境中需要包括一个类似于生产环境的网络,还需要用于模拟用户及其任务的测试软件,最后还需要大量的时间。在服务器性能测试中,可以很容易地排除 CPU、RAM、NIC 之类的变数,但应用程序的性能测试则不同,它需要非常精细地每次只测试一个视图中一个表单上的一个字段。就一些常规 Notes 应用程序的复杂度而言,这种级别的测试不仅冗长,而且看上去似乎无法完成。谁知道去钻研这些妨碍应用程序获得最佳性能的某一个设计元素、公式、脚本或属性将要花费多少时间呢?

但还是有更容易的方法,我们将会在本文中对此加以解释。根据我们数年来通过评测常规 Notes 应用程序来诊断与性能相关问题的经验,我们收集了对应用程序性能会产生影响的一些最常见的属性。在这个系列文章的第 1 部分中,我们将谈到数据库、视图和表单属性,这些都会影响应用程序的性能。为了取得最佳性能,我们将告诉您何时使用某些属性,何时不要 使用这些属性,适当的地方我们会提供代替的解决方案。本文假设您是一名有经验的 Notes 应用程序开发人员。

数据库属性

当应用程序被融入到生产环境中时,数据库属性常常被忽视。而实际上,通过启用和禁用某些属性,您可能会意识到这样可以获得性能提升,同时又不会造成功能性、开发时间或者管理资源方面的损失。我们将关注下面这些会影响性能的常见数据库属性:

  • Don't maintain unread marks(不维持未读标记)
  • Don't overwrite free space(不覆盖自由空间)
  • Maintain LastAccessed property(维持 LastAccessed 属性)
  • Don't support specialized response hierarchy(不支持专用响应层次结构)
  • Web access: Require SSL connection(Web 访问:需要 SSL 连接)

在 Database Properties 对话框上可以发现所有这些属性。前 4 条属性在 Advanced 标签页上,最后一条属性在 Database Basics 标签页上。

图 1. Database Properties 对话框 —— Advanced 标签页
Database Properties 对话框 —— Advanced 标签页
Database Properties 对话框 —— Advanced 标签页

Don't maintain unread marks(不维持未读标记)

大家都认为这条属性令人费解,因为它读起来像是一个双重否定句,但是在默认情况下,数据库中所有已读的和未读的文档都会被跟踪。这在讨论论坛中很有用,在那里,用户希望了解有哪些话题和回复是新的和未读的。然而,跟踪已读和未读文档会对应用程序的性能产生影响。例如,假设有一个包含 1,000,000 个文档的知识数据库。有 10,000 名用户访问这个数据库,其中很多人使用选择性的复制方式在本地复制该数据库。当用户进行复制时,由于本地和服务器上的复制品要同步它们的 Unread Marks 表,所以这时用户会经历一段时间的延时。这个过程花费的时间可能像真正的数据复制那么长。这意味着当用户进行复制时,他们要经历长时间的延时。很有可能,访问服务器上的数据库的用户在一开始打开数据库的时候,也会经历一个延时,因为程序必须通读 Unread Marks 表来判断应该在用户面前将哪些文档显示为已读/未读。这个延时虽然只有几秒钟,但在用户的印象中,这无疑是对该应用程序的一次打击。

为了禁用这个选项,可以选择 Database Properties 对话框 Advanced 标签页上的 Don't maintain unread marks 选项。在 Release 5 和 Notes/Domino 6 中,这个选项会影响整个数据库,而不仅仅是特定的视图。

Don't overwrite free space(不覆盖自由空间)

在 Notes Release 3 和更早的版本中,Notes 保留未加密的删除数据,直到数据库压缩期间没有剩余空间为止。Release 4 巧妙地修改了这项功能,用随机字符覆盖删除数据,使其不能恢复。(这就叫做覆盖自由空间。)在 Release 5 和 Notes/Domino 6 中,您可以选择启用/禁用这个功能。覆盖自由空间对数据库性能有负面影响。

为了帮助您理解这一特性,我们拿桌面 PC 上删除的文档举个例子。在 Windows 操作系统中,当删除一个文档时,该文档直接进入回收站。然后您可以清空回收站,这样一来该文档似乎就会长期消失了。但是,假设在清空回收站以后,您又意识到还是需要这个文档。这个文档是不是永远消失了呢?不一定 —— 也许它不再出现回收站里,但它仍可能存在于计算机中。通过适当软件的帮助(例如 Norton Utilities),您可以重新取回被删除的文档。

所以为了安全起见,在删除一个 Notes 文档时,Notes 将覆盖被删除的数据,以防止任何人重新得到它。当按下 F9 或选择 View - Refresh 时,文档就会被删除。想象一下,您的 Notes 文档从

The quick brown fox jumped over the lazy dog

变成

XX XXXXXXXXXXXXX XXXXXXXXXXX XX X XXXXXXXXXX

注意:这个例子并没有确切地说明 Notes 是如何覆盖被删除的数据的。

至此,是否有人可以重获文档已经变得不重要了,因为数据本身已经被摧毁。注意,当您执行文档的软删除时,Notes 不会覆盖数据。只有硬删除才会引起覆盖。

在大多数情况下,没有必要保留被覆盖的数据。然而,在少数情况下,您可能希望 Notes 继续覆盖被删除的数据:

  • 对服务器和数据库的物理访问可能受到危害,使未授权用户得以访问它们。
  • 数据库未加密,或者 ACL 使数据库暴露在攻击威胁下。
  • 您的组织有一个安全策略要求有这种特性。

如果您的组织、服务器或数据库不存在这些情况,那么应考虑禁用该属性,方法是选择 Don't overwrite free space 选项。

Maintain LastAccessed property(维持 LastAccessed 属性)

Maintain LastAccessed property 这个选项是在 Release 4 中引入的。它跟踪文档最近被访问时的日期(也就是文档最近被读取或修改时的时间)。默认情况下,数据库只跟踪最近修改文档的日期,但是通过选择 Maintain LastAccessed property 选项,数据库也可以跟踪最近读取文档的时间。显然,为了取得最佳性能,只能继续不选择这个选项。

然而,对于任何将文档归档的人来说,这个选项是有价值的。例如,仍然以前面包含 1,000,000 个文档的知识数据库为例,假设每天要添加 1,000 个新文档到数据库。由于有这么多的文档要添加,我们发现有必要将一些老的文档归档。于是我们可以使用 Maintain LastAccessed property 选项来找出各个文档最近被访问时的时间,以此判断将哪些文档归档。我们可以设置归档功能,使其根据 LastAccessed 属性将最近 18 个月以来没有打开过或者读取过的文档归档。

您可能想使用这个选项来帮助归档某些数据库中的文档,在这些数据库中,文档会到达一个期限而变得过期,或者文档的生命周期比较短,例如讨论数据库,或者工作流数据库。但是,对于另外一些数据库,如果数据库中的文档访问得比较少,或者没有可跟踪的最近访问日期,例如咨询台应用程序,那么您可能又不想使用这个选项。

还应该记住一点: LastAccessed 属性不适用于 Web 应用程序。这个属性会忽略 Web 浏览器的读操作。

Don't support specialized response hierarchy(不支持专用响应层次结构)

Don't support specialized response hierarchy 选项允许应用程序利用专用的响应 @formulas: @AllChildren 和 @AllDescendents。这些函数使您可以基于特定的标准为父文档及其所有响应文档建立视图。以一个讨论数据库为例,假设它有 10,000 个主题和 100,000 个响应文档。假设您创建少量的视图,这些视图只显示其中某些类别,比如 Application Performance。如果只有 100 个主题属于这一类,那么可以预测,该视图将只显示那 100 个主题,以及它们所有的响应(以及对响应文档的响应等等)。Notes 传统上依赖于一个 Selection 公式,例如:

SELECT (Form = "Main Topic" & Categories = 
"Application Development") | @IsResponseDoc

不幸的是,这个公式会将 100,000 个响应文档全部返回。在您的推测中,其中大部分响应文档应该不会出现,因为视图会有一个响应层次结构。但事实上这些文档出现了,它们增加了视图的索引时间,也占用了磁盘空间。如果允许使用专用的响应层次结构(这在 Release 4 中是默认设置,在 Release 5 和 Notes/Domino 6 中则是可选的),那么可以使用一个略微不同的公式:

SELECT (Form = "Main Topic" & Categories = 
"Application Development") | @AllDescendants

这个公式会准确地返回您想要的一组文档,这样一来,视图的索引时间和磁盘空间需求便得到了满足。

至此,我们只告诉了您为什么应该启用该特性(也就是说,不选择上述选项)。但是,如果应用程序不需要使用 @AllChildren 或 @AllDescendants 的公式,那么程序没有理由维持这种信息,所以可以通过选择 Don't support specialized response hierarchy 选项来禁用专用响应层次结构,以缩短处理时间。

Web Access: Require SSL connection(Web 访问:需要 SSL 连接)

Web Access: Require SSL connection 选项启用每个 Web 事务的 SSL (安全套接字层)连接,这样一来,在客户机和服务器之间传输的所有数据都将被加密。启用 SSL 之后,您和用户都会感觉到性能大约降低了 10%。但是,每个应用程序的架构都可能影响这个百分比。在启用 SSL 时,每个信息包都将被加密,这样一来,需要在客户机和服务器之间来回进行很多传输的应用程序就需要进行很多加密。

例如:假设您有一个表单,它使用 SSL 来加密所有表单数据。该表单包含一个 @DbLookup 公式。SSL 加密客户机和服务器之间的每个事务,所以除了加密表单数据外,SSL 还加密了查找(lookup)事务。

图 2. Database Properties 对话框 —— Require SSL connection 选项
Database Properties 对话框 —— Require SSL connection 选项
Database Properties 对话框 —— Require SSL connection 选项

有时候为应用程序启用 SSL 是不可避免的。例如,在您组织的策略中可能会在特定应用程序上运行 SSL。还有一些时候,在某些环境下,例如客户机在一个国家,而服务器在另一个国家,SSL 的启用是需要得到保证的。如果您不能肯定一个网络是否值得信任,那么启用 SSL 是有意义的。但是,如果网络是可以信任的,而且您不认为这个网络会受到危害,那么应用程序就不需要 SSL,这样您和用户就不必面对下降的性能。

Create private views/folders

Create private views/folders(创建私有视图/文件夹)是一个 ACL 选项。被授予这个权限的用户可以创建私有视图和文件夹,并将它们存储在数据库所在的服务器上。由于需要额外的索引,创建大量视图,尤其是创建大型视图,会导致性能问题。还应注意的是,对于管理员或开发人员来说,存储在服务器上的私有视图和文件夹是难于删除的。

compact 和 updall 任务

虽然通过压缩应用程序和运行 updall 任务来刷新视图索引是很好的数据库实践,但这些做法通常不会提高应用程序的性能。不过也有例外情况,比如对于剩余空间占很大比例的数据库,但是对一个只有 5% 或 10% 剩余空间的数据库进行压缩并不能获得显著的性能提升。

视图属性

有一些关键的地方会影响视图性能:

  • 时间/日期敏感的公式(选择公式或列公式)
  • 动态列排序
  • Reader name 字段
  • ODBC 访问

时间/日期敏感的视图

时间/日期敏感的视图是指,它所包含的一个列具有时间/日期公式,例如 @Modified 或 @Now,或者具有包含时间/日期公式的选择公式。这些视图可以提供很好的功能性,但也要为之付出昂贵的性能代价。每过 15 分钟,Domino 服务器就会运行更新任务来刷新数据库中所有视图索引。这个任务是不可配置的(也就是说,您不能配置该任务,使其按不同的周期运行)。假设在早上 9:00 运行了该任务来刷新某个数据库中的所有视图。在 9:02,数据库中的一个文档被修改。在 9:15,更新任务被再次运行,并注意到数据库中有一个文档已经被修改。这个文档可能是通过电子邮件传入的,可能被复制、创建、更新、删除,等等,但不管如何,自上次更新任务运行以来,的确发生过一次文档修改,所以必须检查数据库来查找过期的视图。

至此,所有可能包含已修改文档的视图都已经被标为 out-of-date(过期)。所有对时间/日期敏感的视图都被标为 being out-of-date(即将过期)。所以,除了对那些可以合理假设需要更新的视图进行更新外,索引程序(indexer)还需要更新所有时间/日期敏感的视图。但事情却变得更糟。这些视图不能刷新,它们只能重建,这样将花费更多的时间。我们来看看到底要花多长时间,通过一些敏感的诊断,您将发现,普通视图可能要花 100 毫秒的时间来刷新,但时间/日期敏感的视图通常需要 10-50 (而不是毫秒)的时间来刷新,因为它们是真正需要重建的视图。在一台有很多数据库的繁忙的服务器上,由于每隔 15 分钟就要检查很多的视图,您的环境会无法容忍仅仅一个视图就花去这么多时间。

还应注意,将 View Properties box Refresh 字段设为 Manual (而不是像大多数情况那样设为 Automatic),这将为用户快速打开视图,而不会影响这 15 分钟的 Update 任务。

图 3. View Properties box - Refresh 字段
View Properties box - Refresh 字段
View Properties box - Refresh 字段

如果没有将视图刷新设置为 Manual 方式,那么每当用户打开视图,就要进行一次重建。当然,使用这种设置意味着,当用户打开视图时,视图不一定要是最新的,所以必须在性能优势和潜在的过期数据的缺点之间作出权衡。

时间/日期敏感的视图是一个非常有用的(但也很昂贵)的选项,所以使用时要谨慎。

检查日志文件
如果您不确定视图刷新或重建的时间有多长,那么可以使用日志文件。在 Server Configuration 文档中设置 Log_update=2,以便记录索引程序何时刷新/重建视图。日志文件列出它所刷新/重建的每个数据库中的每个视图,使您可以跟踪在特定视图或数据库上花费的时间。通过一点点实践,您就可以熟练地发现服务器上的任何问题。

时间/日期方案
您可以为时间/日期敏感的视图实现一些不同的方案:

  • 在 Selection 公式中使用 @Text,Time/date Views in Notes: What Are the Options? 对此作了描述。这种方案有一定的局限性,但是非常有用,并且性能很好。
  • 运行一个代理来标记那些应该出现在 ex-time/date sensitive 视图中的文档。例如,如果您有一个视图,该视图显示 Status = "Open" 并且 DueDate 在今天之前的文档中,那么您可以在每天晚上运行一个代理,将那样的文档标记为 OverDueFlag = "Yes"。这样,视图选择公式就只需要检查那个标记。当文档关闭时,该标记也被删除。虽然对于单服务器数据库来说,这是一个不错的解决方案,但是,如果用户常常使用本地复制,那么这就不是一个好的解决方案,因为这样用户就不得不每天复制代理的数据更改。同样,如果要将数据库复制到世界各处的几十个服务器,您可能也不希望使用这种方案。
  • 创建一个按日期将文档归类的视图。这种解决方案很简单,以致常常被忽视。仍使用上面的例子,为所有 Status = "Open" 文档创建一个视图,这些视图是按照其 DueDate 归类的。用户可以通过滚动到适当的日期类别,很容易地检查过期的文档或者快要过期的文档。

列排序

列排序这个选项允许用户按升序、降序或同时使用这两种顺序对视图中的列排序。视图中的列上的每个排序箭头都会增加视图索引,同时还会增加刷新视图的时间。从用户界面和维护的角度来看,采用一个含少量排序箭头的视图比采用包含多个排序箭头的视图要好。但是从性能角度来看,关键是避免在视图中添加大量的排序箭头,而不必减少视图的总量。更具体的度量是:将两个排序箭头添加到视图中会使索引大小/时间增长大约三倍,添加四个排序箭头会使视图的索引大小/时间增长四倍,依此类推。

技巧: 检查那些只是用来查找的隐藏视图,以保证这些视图中没有使用排序箭头,如果有的话,应该删除这些箭头。

Reader name 字段

Reader name 字段不是视图属性,但它们可以影响视图的性能。Reader name 字段可以提供文档安全性,但对显示包含 reader name 字段的那些文档的视图来说,存在负面影响。例如,假设您有一个用于 10,000 名雇员的 Human Resource 数据库,还有一个常规视图(没有分类),该视图显示所有 10,000 个文档。由于 Reader Names 的约束,每个雇员只能看到他/她自己的文档。当一名雇员打开该数据库时,Domino 服务器对这些文档排序,以确定应该将哪些文档显示给该用户。通常,在没有 Reader Names 的情况下,大概是前 30 个文档显示给这个用户,刚好占满屏幕。您可以在任何数据库中做一个简短的测试来确认这一点,方法是打开一个视图,然后按向下箭头键。一开始快速地滚动十几行的样子,然后会有一个暂停,暂停时间一般不超过一秒,这个时候服务器在获取接下来要显示的另一块数据。然后滚动 30 来行的样子,接着又是一次暂停,依此类推。

然而,在 HR 应用中,服务器不能将数据填满用户屏幕。这本来不是问题,但数据库无法知道它不能填满屏幕,所以它继续将所有 10,000 个文档排序,查找更多显示给用户的文档。遍历了所有文档之后,最后服务器才会停止查找,并显示惟一的一个文档,但这样一来,延时就会很可观。在一个独立的环境中,由于这样的延时,很容易使大量用户超时。

有一些方案可以帮助避免这种问题:

  • 将视图分类,通过选择 "Collapse all when database is first opened" 选项,在一开始的时候就消除类别。虽然这种设置对性能有一点点干扰,但在这种情况下还是可以节省很多时间的。
  • 避免为了只显示含有文档的类别而选择 "Don't show categories having zero documents" 选项。选择这个选项的效果与使用常规视图一样:在为用户显示内容之前,服务器不得不检查所有 10,000 个文档。
  • 使用显示单个类别的嵌入式视图。使用 @UserName 公式,只显示用于那个用户的文档。这种方案有很好的性能优势,并且对于 Web 浏览器,表现同样出色!

注意,不管用户使用的是 Web 浏览器还是 Notes 客户机,与视图中 reader name 字段相关的性能问题是一样的。

ODBC Access

ODBC Access 属性 "Generate unique keys in index" 为数据库交互性提供唯一键。您可以使用该属性来更快速地进行查找。方法如下:假设您有一个讨论数据库,其中包含 10,000 个主题和 100,000 个响应文档。该数据库包含一个隐藏的视图,其中只列出这 10,000 个主题,以便于查找现有的所有类别。如果为这个隐藏视图选择 ODBC 访问属性,那么可以使每种类别的文档减少到一个。这一属性消除了所有重复的文档。通过在隐藏视图上使用 @DbLookup,可以获得更快的查找速度,因为这样极大地减少视图的大小。例如,如果在数据库中只有 50 个类别,那么这个隐藏的视图就只包含 50 个文档,而不是 10,000 个之多。

图 4. View Properties 对话框 —— ODBC Access 属性
View Properties 对话框 —— ODBC Access 属性
View Properties 对话框 —— ODBC Access 属性

注意,如果文档选择了多个类别,那么需要在视图列公式中使用附加代码来确保所有类别都被显示,并且能够被查找。

表单属性

只有一个表单属性可以影响应用程序的性能:Automatically refresh fields。当对某一表单上启用 auto-refresh 时,每当从一个字段转移到另一个字段,auto-refresh 就会更新表单上所有之前的字段。

图 5. Form Properties 对话框 —— Automatically refresh fields 选项
Form Properties 对话框 —— Automatically refresh fields 选项
Form Properties 对话框 —— Automatically refresh fields 选项

例如,当转移到一个表单上的第二个字段时,auto-refresh 会更新表单上的第一个字段;当转移到第三个字段时,它会更新第一个和第二个字段,依此类推。这种特性最终会降低应用程序的性能,当表单使用工作流和查找时更是如此。对于包含验证公式的简单表单,auto-fresh 的性能影响要小得多。对于复杂的表单,应考虑使用 exit 事件,而不是使用 auto-refresh。

结束语

在本文中,我们研究了影响应用程序性能的最常见的一些属性。然而,常规应用程序只有惟一一个影响应用程序性能的因素组合。虽然通过启用或禁用本文讨论的那些属性可以提高性能,但仍然有必要测试应用程序,看看是否可以进一步提高应用程序的性能 —— 记住,应用程序性能测试可能比较困难,并且很花时间。在本系列接下来的文章中,我们将考察会影响应用程序性能的代理和代码。


相关主题


评论

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Lotus
ArticleID=161706
ArticleTitle=Lotus Domino 应用程序性能调优,第 1 部分
publish-date=04012003