内容


IBM WebSphere 开发者技术期刊

使用 WebSphere Portal V5.1 开发包含静态内容和动态内容的高性能网站

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: IBM WebSphere 开发者技术期刊

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

此内容是该系列的一部分:IBM WebSphere 开发者技术期刊

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

引言

从 Web 开发的观点来看,最理想的网站应该允许内容提供者和管理员在向访问者提供内容时无需考虑内容的提供方式。事实上,最理想的内容和应用程序提供方式应该是以最方便最可行的方式自动向站点访问者提供信息。不过,到目前为止,由于考虑到大容量、高性能的网站的性能和可伸缩性,故而有必要将静态内容和动态应用程序区分开来。这两个术语的含义如下:

  • 对于静态内容而言,为所有用户提供的信息都是相同的。很多情况下,静态内容都存储在服务器上的 HTML 文件中,用户使用 Web 浏览器对服务器进行访问。静态内容也可以由内容管理系统之类的应用程序生成。
  • 动态内容通常为使用 Web 浏览器向站点访问者呈现其用户界面的应用程序。

目前的网站使用不同的技术提供静态内容和动态应用程序。这种异构的方法增加了提供多种类型内容的网站的复杂性。不过,通过使用 IBM WebSphere Portal,可以将这两种类型的内容组合在一个门户中,使得网站管理更为简单。WebSphere Portal V5.1 大幅度提高了静态内容的提供流程,能以最高效的方式提供所有类型的内容。通过将 WebSphere Portal 作为提供动态应用程序和静态内容的公共机制,能通过门户维护的链接将静态页与动态页进行链接,从而实现一致的交叉引用。

将静态内容和动态应用程序结合,还大幅度提高了网站的价值,特别在向访问者呈现无缝集成的用户界面而使用户不会觉察到内容类型的差别时,这一点尤为突出。

让我们来看一个高级示例,以演示此类无缝集成:访问 IBM Internet 网站的访问者可以通过集成的站点搜索引擎查询“WebSphere Portal”,从而得到关于此产品的信息资源列表。访问者可以通过结果集中找到的链接阅读产品文档。访问者也可以找到 WebSphere Portal 目录,然后可以再搜索用于与其后端系统集成的 Portlet 的目录。从这里我们就可以看出动态应用程序(本例中为 IBM 网站搜索和目录)与静态内容(产品文档页)可以如何结合以供站点访问者使用。

WebSphere Portal 中的缓存技术

门户站点集中了多个独立组件(称为 Portlet)提供的内容和应用程序,这些 Portlet 都是独立开发的 Web 应用程序,在门户容器中执行。Portlet 可以维护状态。门户服务器协调多个 Portlet 的执行与标记聚合。WebSphere Portal 能提供灵活的缓存功能,从而提高同时提供静态内容和动态应用程序的网站的性能和可伸缩性。WebSphere Portal 通过组件状态优化缓存使用与利用。门户将组件响应存储在作用域设置为组件状态的缓存中。应用程序响应和静态内容的有效生存期和作用域可能有所不同,与静态内容页相比,通常应用程序的生存期较短,作用域也较小。

WebSphere Portal 在多个级别上使用缓存。通过使用 WebSphere Portal 的组合缓存技术(如自适应页面缓存、Portlet 缓存以及对象缓存),可以提高同时包含静态部分和动态部分的网站的性能和可伸缩性。

在缓存命中的情况下使用这些不同的缓存技术获得的性能提高与出现缓存命中的可能性之间存在一个折衷关系。通过使用自适应页面缓存将门户页标记全部缓存,可以在每次缓存命中的情况下获得最佳性能提高,但只有在请求的页面与缓存的响应完全相同的情况下才会出现缓存命中。页面要完全相同,则需要构成该页的组件生成的所有标记片段都完全相同。

将整个页分解为组件片段可以提高缓存命中的几率。利用 Portlet 缓存,门户会在响应请求前将缓存的 Portlet 片段聚合为完整的页。这种情况下,只需要所请求的 Portlet 片段与已存储的响应完全相同即可,而这提高了缓存命中的可能性,但并不能在每次缓存命中时提供同样的性能提高(仍然需要在门户上进行聚合)。对象缓存可以达到最高的缓存命中率;只要后端没有更改数据,存储在缓存中的此数据就有效。这种情况下,Portlet 根据缓存的数据呈现标记片段,而门户将标记聚合为完整的门户页。

静态内容和动态应用程序的内容生存期和作用域的差别也可以通过使用异构系统基础设施得到缓和,在异构基础设施中,静态内容和应用程序寄宿于独立的环境中;静态内容由 HTTP 服务器或内容管理系统提供,而应用程序则寄宿在应用服务器或门户服务器环境中。用户体验向最终用户隐藏了一个事实,即实际上不同的两个站点在同时运行。应用程序和静态内容交叉链接,使站点访问者能够在两个内容集间无缝地转换。此方法的缺点在于明显地增加了复杂性和维护工作。

本文将介绍一个在 WebSphere Portal 进行缓存的示例使用场景,并提供关于 WebSphere Portal 缓存架构的详细信息以及在 Portlet 和门户站点内利用这些功能的可能方式。

示例场景

我们的示例场景涉及到一个内部网门户站点,该站点同时提供静态内容和动态应用程序。让我们了解一下此门户站点如何为提高性能和可伸缩性进行了优化,以及它是如何使用 WebSphere Portal V5.1 中的缓存功能的。

图 1. 门户内容拓扑示例
图 1. 门户内容拓扑示例
图 1. 门户内容拓扑示例

该门户站点由两个主要区域组成,这两个区域的内容类型也不同:

  1. News——包含由 Portlet 组成的两级页面,这些 Portlet 向员工提供关于技术、产品及客户的新闻文章。这些 Portlet 显示的新闻文章由一个内容管理系统提供。此内容更新频率较低,且由许多用户共享,所以在 News 区域的内容被归为静态内容
  2. MyWork ——包含由员工在日常工作中用来与同事进行协作的 Portlet 组成的页面。这些 Portlet 与公司建立以提高员工效率的协作基础设施集成。此内容更改频繁,是由动态应用程序组成的。

以下部分描述为了最高效率地使用缓存机制而应用于这两个区域的设计原则。

News:静态内容

我们的门户站点的 News 区域包含具有 Portlet 的页面,这些 Portlet 提供来自内容管理系统的静态内容。门户的此区域的行为和静态网站的行为相似,但却向员工提供与他们的协作应用程序集成的单一环境。门户的此区域的所有页面均提供给内部网门户的所有用户;用户并不个性化这些页面,而且这些页面上内容对于每个人都是相同的,而这正是静态网站的典型特征。这些站点内容的更改频率也不相同,Tech 页面的新闻文章每分钟都在变,而 Products 页面的内容仅在每天早上更新。

内容 Portlet 提供不同的视图。例如,某些 Portlet 显示带链接的最新文章列表,如果用户单击了这些链接中的某一个,将在同一个 Portlet 中的同一页面上显示相应的文章,或在特殊的文章显示 Portlet 中显示此文章。

这些页面中的每一个都包含导航区域,用于供用户在 Portlet 内导航。此导航区域对于所有用户都是一样的。所有用户都可以共享来自缓存中的这些页面的标记。

MyWork 区域内可用页面集对于每个用户都是不同的,因此这些页的导航不应该包含在可缓存的页面中。在我们的门户站点中,是通过以下方法实现的:为门户的 News 区域内所有页面提供直接导航,而不为 MyWork 区域内的页面提供直接导航。要访问门户的 MyWork 区域中的页面,用户首先导航到 MyWork 主页面(News 区域内的所有页面都可以直接访问此页面),然后在 MyWork 区域内直接一页一页地导航。

WebSphere Portal V5.1 允许将这些页置入缓存代理中。缓存代理位于浏览器和服务器之间。代理接收来自浏览器的请求,并代表这些客户机从服务器请求内容。代理是缓存服务器响应的代理。对于后续的请求,缓存代理会直接从其缓存中将匹配的响应发送回客户机。通过使用缓存代理,每个页面都只需从门户交付一次,然后此页面将驻留在缓存中(直到内容无效时为止)。在内容的生存期内,对同一页面的后续请求都将由缓存代理直接响应,因而不会在门户服务器上生成工作负载。

MyWork:动态应用程序

该门户站点的 MyWork 区域包含供员工在日常事务中进行协作的一些 Portlet。门户的此区域针对动态应用程序进行了优化。始终为特定的用户请求生成门户页面,以确保门户能向当前用户提供最新的应用程序数据。

在示例场景中,一些协作应用程序提供给全体员工,而另一些协作应用程序仅提供给公司内某些选定的组。MyWork 区域内的导航链接应只向用户提供其得到授权可以访问的导航链接;如果用户对某页没有访问权限,该页将不会出现在导航中。门户为每个用户单独生成导航,以反映用户的权限。

WebSphere Portal 用户可通过添加 Portlet、删除 Portlet 或重新排列页面上的现有 Portlet来对 MyWork 区域内的页面进行个性化设计,以使门户适应他们最高效的工作方式。

MyWork 区域中的页面不由多个用户共享。如果将这些页面缓存在多个用户共享的页面响应缓存中,则可能会很快用完缓存内存,却不能提高缓存命中率。将作用域设置为私有的页面存储在浏览器缓存中能达到对缓存的最佳内存利用,同时其位置也尽可能地接近最终用户。

页面结构或页面内容会随每个用户请求而变化,因而不能使用页面缓存来存储页面响应。需要使用更为先进的缓存技术以提高页面性能和降低系统使用率。在动态更改的页面中,通常并非所有的 Portlet 片段都会随每次请求而更改;某些 Portlet 片段在响应多个页面请求期间都不会变化,因此可以为一个用户或多个用户的请求缓存。Portlet 内的标记片段从该 Portlet 维护的数据中生成。其中的部分数据可能每次请求都会更改,因而要为每个请求交付不同的片段;而其他数据部分则可能在一系列始终交付相同标记的请求期间不会更改。根据其更改特征设计数据结构,可以对跨多个请求或多个用户保持为常数的数据元素进行标识。可以使用数据缓存对那些更改频率低于页面请求频率的数据进行缓存。

WebSphere Portal 提供了内置缓存,Portlet 可以使用其提供缓存 Portlet 标记的 Portlet 缓存,从而改善 Portlet 片段请求的响应时间。如 JSR 168 规范中所定义(请参阅参考资料)的,在 Portlet 的描述符提供的缓存过期配置为每个 Portlet 定义 Portlet 缓存行为。WebSphere Portal 中运行的 Portlet 可以使用对象缓存来缓存这样一些数据对象,此类对象为单个用户的多个页面请求所共享,或为不同的用户执行的页面请求所共享。

WebSphere Portal 中的缓存架构

这里,我们将讨论 WebSphere Portal V5.1 中的扩展缓存架构。图 2 描述了在请求从用户的浏览器传到后端系统期间,WebSphere Portal 不同级别上的缓存功能。此基础设施的定义符合 HTTP 规范中缓存基础设施的定义(请参阅参考资料),此处将以一个简化的模型进行说明。

图 2. WebSphere Portal 中的端到端缓存
图 2. WebSphere Portal 中的端到端缓存
图 2. WebSphere Portal 中的端到端缓存

从浏览器发出请求(从图 2 左边开始):

  • 浏览器具有内置缓存,用于根据 HTTP 响应的标头中提供的信息存储 HTTP 请求的响应。利用自适应页面缓存,WebSphere Portal 对这些标头进行了细粒度的定义。如果可以在浏览器缓存中找到有效的响应,浏览器将不向网络发送请求,而直接将此内容向最终用户显示。如果未在浏览器缓存中找到匹配的有效响应,将把请求发送到网络上。
  • 网络中包含请求从浏览器到门户基础设施所经过的全部基础设施组件。在网络中,可以选择安装缓存代理。缓存代理可以通过浏览器的代理设置直接进行配置,也可以在不要求进行显式浏览器设置的情况下透明地工作。
  • 接收请求的缓存代理将在其缓存中搜索可能已经存在的匹配响应。如果找到匹配响应,会将其作为响应交付。如果没找到匹配请求,则将请求转发到所请求的原始服务器。根据响应标头中包含的缓存设置,可能会将响应存储在缓存中,作为后续请求的响应;将使用自适应页面缓存设置的标头进行此计算。
  • 转发的请求由门户基础设施接收。门户基础设施可能包含可选的反向代理,此代理被配置为代表原服务器接收请求。它并不需要在浏览器或网络中显式进行配置,反向代理的行为与缓存代理完全一样,它在其自身的缓存中搜索匹配响应,只有在没有可用的响应时才转发请求。来自反向代理的请求将被转发到反向代理服务器所知的门户服务器。
  • 门户服务器标识请求的页面,并将请求分解为对多个组件(如 Portlet 和 Theme)的多个请求,这些请求一起构成完整的页面。对于每个 Portlet 请求,门户将搜索其 Portlet 缓存以查找匹配响应。对于没有匹配响应可用的请求,将调用单个 Portlet 生成一个响应。然后会根据 Portlet 作为响应一部分提供的缓存元数据将接收到的响应存储在缓存中。
  • 接收 Portlet 请求的 Portlet 可使用对象缓存存储呈现相应响应所需的数据。仅当数据在对象缓存中不可用时,才会调用后端系统交付请求的数据。然后将由门户对所有组件响应进行聚合,以形成完整的门户页面。完整的门户页面将会作为接收到的请求的响应发送回去。
  • 响应通过处理传入请求的所有缓存向回发送,如果合适会将其存储在缓存中,然后将交付回浏览器进行呈现并向用户显示。
  • 用户的响应体验取决于从发送请求到在浏览器中显示响应的时间。由靠近用户的缓存对请求作出应答,可以减少网络跃距和网络延迟,从而尽可能地提高响应能力。优化的网站设计会让多个用户共享完整的页面,并让浏览器缓存或网络缓存提供这些页面,从而实现这一点。对于已缓存页面的请求再无需通过从浏览器到后端系统的整个基础设施了。

自适应页面缓存

在传统的观念中,通常对于应用服务器有一种假设,认为不可能在应用服务器外缓存动态生成的页面。另外,传统上还认为永远不能使用可能的代理服务器或浏览器缓存形式的现有缓存基础设施。在此传统的方法中,每个传入请求每次都需要应用服务器资源计算合适的响应。

使用 IBM 的自适应页面缓存专利技术,WebSphere Portal 突破了这些限制,提供了在称为远程缓存的位置中缓存动态生成的页面的机会,前提是组成页面的所有组件都发出信号,指示其为可缓存的内容。此方法的优点很快变得明显起来:对于此类可缓存的页面,第一次生成该页后就无需再往返于门户服务器了。如果能从缓存提供大量访问的页面,则整个门户基础设施的性能将大幅度提高。或多或少包含静态内容的图像页面,或仅显示 Portlet 已知的不同视图的页面,均可通过一个具体的 URL 进行寻址。(后一种情况可以通过提供其不同视图的呈现链接实现;请参阅上文。)

WebSphere Portal 可以通过与页面相关的 URL 引用页面的完整视图;在 WebSphere Portal 中,此功能是通过将导航状态编码到 URL 中实现的。利用此功能,也可以通过 URL 从缓存中访问已缓存的页面。如果曾用于生成特定页面的标记的某个门户资源的服务器端状态发生更改,需要重新生成此页面,因而缓存的视图会变为无效。因此需要告知缓存已呈现的页面视图保留的有效时间。Portlet 需要将这类缓存信息作为 Portlet 呈现的页面的整体缓存信息一部分进行发布。其上具有此类 Portlet 的页面可能是存储并从缓存中提供的好候选对象。

不过,这一优点并非不受到任何限制。由 WebSphere Portal 维护的资源需要得到适当的管理。对于构成页面的某些组件,需要提供额外的信息,以便充分地利用此项技术。

远程缓存
在本文中,远程缓存一词指位于 WebSphere Portal JVM 进程之外的缓存,也有可能位于运行 WebSphere Portal 的计算机之外的位置。远程缓存可以为请求 URL 缓存全部的响应。访问缓存中的这些项的唯一方法就是请求 URL。因此,可能可以在缓存中找到已生成页面的完全呈现标记。

一般而言,WebSphere Portal 允许使用任何符合 HTTP 1.1 缓存功能规范(请参阅参考资料)的任何实现,以更好地利用缓存基础设施。HTTP 1.1 规范仅通过使用特定的 HTTP 请求类型即可使缓存项失效(在本文中,这与远程缓存等效)。由于 WebSphere Portal 无需完全了解其所在的远程缓存基础设施,因而它不能使用此方法使单个缓存项失效。WebSphere Portal 为远程缓存所使用的唯一失效机制是过期超时

需要区分由 HTTP 1.1 规范最初引入的两种远程缓存概念:

  • 共享缓存可由多个用户访问。大多数时间,不会针对此基础设施内的用户的非授权访问对其内容进行保护。反向和转发代理服务器通常在门户服务器环境中作为此类缓存使用。有时,也用公共缓存指此类缓存。
  • 非共享缓存只由单个用户访问。其内容专属于此特定用户。在基础设施中,通常由浏览器充当此类缓存。有时,也用私有缓存指此类缓存。

只有在可以计算附加的缓存信息(此信息随 WebSphere Portal 服务器响应一起发送)的情况下,这两种缓存才能成功地缓存页面。HTTP 1.1 规范定义了此类响应标头,并说明了如何处理特定的缓存项。

图 3. 远程缓存
图 3. 远程缓存
图 3. 远程缓存

WebSphere Portal 以能最佳利用远程缓存上可能可用的缓存功能的方式在其生成的响应中提供此信息。自然地,在这些响应标头中需要以下两个项,以通知缓存如何对生成的响应标记进行处理:

  • 缓存作用域——指示来自 WebSphere Portal 的响应(即一个完全呈现的页面)是否在共享缓存或非共享缓存中可缓存。此值告知可以在基础设施中的何处缓存页面;例如,页面是否可以缓存在浏览器中(非共享缓存或私有缓存)或反向代理中(共享缓存或公共缓存)。(浏览器也可以缓存共享的页面,但这又对此类页面增加了一级缓存。)
  • 缓存过期时间——告知缓存项的有效时间(或多长时间刷新一次),因此可以在这段时间内从缓存提供响应。

WebSphere Portal 将根据远程缓存中进行的缓存而为其响应设置以下相关的 HTTP 1.1 标头:

  • 缓存作用域:
    Cache-Control:public
    Cache-Control:private
    Cache-Control:no-cache
  • 缓存过期时间:
    Cache-Control:max-age delta-seconds

(如果对这些响应标头提供的值没有疑问,则可以使用某个工具使其变为可视,此工具可以作为一个代理,位于 WebSphere Portal 基础设施和浏览器之间,也可以作为浏览器的插件实现。详细信息请参阅参考资料。)

缓存信息的提供者
WebSphere Portal 如何确定呈现的页面是否可以实际缓存在远程缓存中?哪些数据是进行这样计算的必需数据?

为了进行此缓存,WebSphere Portal 将访问完全呈现页面所需的全部必要组件,并对这些组件可以提供的信息进行聚合。这也意味着,如果要最佳地实现此类页面的缓存功能,每个组件都必须提供关于其自身的缓存信息。另外,WebSphere Portal 维护了全局最大值以限制缓存值;例如,最大缓存过期时间,或完全关闭远程缓存中的缓存的时间。

图 4. 聚合缓存信息
图 4. 聚合缓存信息
图 4. 聚合缓存信息

因此,管理员必须在其门户设置中提供此信息,而 Portlet 开发人员也可以向要实现的 Portlet 的部署描述符和代码中添加信息。如果组件不提供任何此类信息,WebSphere Portal 将依赖于每个组件的全局缺省值。全局缺省值的设置与算法将在下文中予以说明。

表 1 提供了关于提供者及其提供的数据(供在远程缓存中进行缓存时使用)的概述。需要使用此数据计算总体缓存信息。

表 1. 缓存信息的提供者

门户资源缓存作用域(共享或非共享)缓存过期时间(以秒为单位)忽略缓存中的访问控制(True 或 False)
门户(全局设置)XX
门户页面XXX
ThemeXX
Portlet 定义XX
Portlet 窗口XX

如表中所列出的,缓存信息的提供者为:

  • 门户——缓存信息的全局最大值基于管理员在属性文件提供的若干值。由 WebSphere Portal 根据这些属性值在内部计算全局最大值。另外,如果某些提供信息的组件没有提供任何与缓存相关的信息,则可以使用后备机制的全局设置,不过这一点没有在此表中得到体现。请参阅全局缺省值与全局最大值,以了解这些值的计算方式及其所基于的设置。
  • 当前所请求的门户页面——在此处,门户页面指可以通过 WebSphere Portal 用户界面管理的门户资源。不能将此与 HTTP 响应中完全呈现的页面(如 HTML 标记)混淆,后者包含从门户页面生成的所有标记,可以在远程缓存中进行缓存。
  • 与该门户页面关联的 Theme
  • 当前请求的门户页面中所有 Portlet 的 Portlet 定义
  • 当前请求的门户页面中所有 Portlet 的 Portlet 窗口

引入了忽略缓存中的访问控制设置以确保如果页面上发布的信息为安全敏感信息,则不会在缓存中存储此页面。如果完全呈现的页面存储在共享缓存中,则那些不具有该页面访问权限的用户仍然可能猜测出此类页面的 URL,从而从缓存中加载其内容。远程共享缓存通常不提供任何缺省安全机制。如果真的需要考虑这样的环境,必须将此设置为 False,以保证不会在远程共享缓存中对此类敏感页面进行缓存,从而确保无法通过猜测 URL 访问此类页面包含的信息。

Portlet 窗口可以在呈现时为远程缓存提供信息,因为它们可以根据自身的内部知识执行一些计算,从而可以动态地发布此信息。利用此 WebSphere Portal 功能,可以使用不同选项缓存单个 Portlet 的多个视图。Portlet 窗口本身可以在呈现时确定其输出是否可以缓存,以及应在何种缓存作用域下进行缓存。

如果某个 Portlet 窗口在呈现时不发布任何此类信息,WebSphere Portal 将转向 Portlet 定义或(如果 Portlet 定义没有提供)全局缺省值提供的缓存相关信息。

出于性能方面的原因,在 JSR 168 容器中引入了一个附加(冗余)设置,该设置告知容器在呈现时 Portlet 是否将提供远程缓存信息。WebSphere Portal 可以通过部署描述符使用此信息,因此可以减少计算工作。

对于遗留 Portlet,WebSphere Portal 将使用全局缺省值。遗留 Portlet 既不通过部署描述符提供缓存信息,也在不呈现时提供远程缓存信息。

对于未经身份验证的页面,WebSphere Portal V5.1 将保持与较早版本的兼容性,在早期版本中,这些页面都是可以缓存的,只由全局工作参数进行管理。

缓存信息的计算
构成页面的每个组件为远程缓存提供的所有缓存信息都需要进行聚合,将其合并为呈现页面的两个总体值:缓存作用域缓存过期时间。WebSphere Portal 会将这些值附加到考虑缓存的门户响应中。请记住,由于 HTTP 1.1 规范的要求,在一次响应中,WebSphere Portal 只能为此目的附加所选 HTTP 标头的一个值集。

计算过程通常就是对缓存作用域和缓存过期时间均使用最小值,以确保以下事项:

  1. 过期不会超过组件所提供的任何值。
  2. 按照组件所提供的值正确选择了缓存作用域。

很容易确定若干个过期值中的最小值,而两个可能的缓存作用域最小值却不是那么明显。

由于“非共享”的缓存作用域值比“共享”的缓存作用域值限制更多,所以采用与小过期时间比较大过期时间限制更多的类似方法得出结论,确定“非共享”的值要比“共享”的值小一些。

对于 Portlet,有一种特殊的机制应用于提供的每个缓存过期值和缓存作用域值。Portlet 窗口提供的值始终优先于 Portlet 定义提供的值。这意味着不管 Portlet 窗口的值高于或低于 Portlet 定义的值,将始终使用此值(如果提供的话)。如果 Portlet 窗口没有为缓存过期或缓存作用域提供值,则会将 Portlet 定义中的值作为该 Portlet 的提供值。

(下一部分将讨论在组件未提供值的情况下的缺省行为。)

如果将某个门户页面的忽略缓存中的访问控制设置为 False,将不能对完全呈现的页面进行缓存。为了确保不在远程缓存中缓存门户页面,需要将该门户页面的缓存过期值或全局范围内的对应值设置为 0。

全局缺省值与全局最大值 WebSphere Portal V5.1 还引入了缓存的全局缺省值和最大值,这使得 WebSphere Portal 有能力在组成呈现页面的组件没有发布缓存信息的情况下提供可缓存的页面。

全局缺省值和最大值是通过对属性文件中提供的设置(请参阅 How WebSphere Portal contributes global values of cache information)和确定请求是否经过了身份验证的结果进行计算得到的;后者是一个瞬时值,在文件或数据库中没有持久表达形式。

图 5. 全局 RemoteCacheInfo 计算流程:过期值
图 5. 全局 RemoteCacheInfo 计算流程:过期值
图 5. 全局 RemoteCacheInfo 计算流程:过期值
图 6. 全局 RemoteCacheInfo 计算流程:作用域
图 6. 全局 RemoteCacheInfo 计算流程:作用域
图 6. 全局 RemoteCacheInfo 计算流程:作用域

全局最大值提供到呈现的页面的总体缓存信息中。它具有和其他缓存信息提供者(如 Portlet、Portal 页面和 Theme)同样的权限。

只要 Porlet、门户页面或 Theme 未提供任何缓存信息,就将使用全局缺省值

Portlet 缓存

通过使用自适应页面缓存方法,可以将完整页面缓存在远程缓存中。不过,完整的页面通常由许多 Portlet 的聚合组成。每个 Portlet 都会产生一个标记片段,此标记片段在页面上和其他 Portlet 的片段进行组合,就形成该页面的最终标记。然而,Portlet 所产生的单个标记片段也可能可以缓存。在这一部分中,我们将说明 WebSphere Portal 如何利用片段缓存来缓存单个 Portlet 片段(请参阅 Portlet 缓存示例应用程序)。

片段缓存支持两种主要的缓存实例:对象缓存实例Servlet 缓存实例

对象缓存提供 Java™ API 以缓存任意的 Java 对象(请参阅对象缓存与状态处理),而 Servlet 缓存功能则缓存 Servlet 请求发送程序所包含的输出。Portlet 由 Portlet 容器通过请求发送程序调用,因此,由于 Portlet 的标记是 Servlet 的标记,故而适合对其进行缓存。由于 Portlet 具有聚合特征,而 Porlet 标记又依赖于该 Portlet 的导航状态(不属于传递给请求发送程序的 URL),Portlet 容器在缓存此 Portlet 标记时需要执行额外的步骤:

  • 需要计算片段的缓存键,以确定是否向此键提供了 Portlet 的完整导航状态。在 Servlet 环境中,此状态应该已编码为指向 Servlet 的 URL 的一部分。由于不对 Portlet 直接寻址,而只是间接地作为聚合页面的一部分进行访问,因而 Portlet 没有包含此导航状态的直接 URL。Portlet 容器转而提供了一个自定义 ID 生成机制,将帐户呈现参数、Portlet 模型、窗口状态以及 mime-type 包含在内。利用此方法能以彼此独立的方式缓存 Portlet 的不同视图。
  • 对于 HTTP 缓存,在出现可能修改资源的服务器端状态的资源交互时,缓存项将失效。对于 HTTP,此类交互建模为 POST 请求,因此这类请求将使所访问的资源的缓存项失效。对于 Portlet 缓存,等效的交互机制为 Portlet 操作。当 Portlet 上出现操作时,Portlet 容器将确保此 Portlet 的缓存项将失效。为了确保不会显示已过期的标记,容器将使 Portlet(窗口)的所有导航状态的缓存项全部失效。不过,尽管此方法能保证一致的呈现,但却潜在地使过多的缓存内容失效了,因此 Portlet 开发人员应对其 Portlet 的交互流进行建模,使其操作链接仅用在交互会修改服务器端状态(如后端状态或会话状态)的情况下(这种情况很少见)。应将在不同导航状态间切换(如模式更改、切换 Portlet 屏幕等等)的交互建模为呈现链接,以确保对缓存的最大化利用。
  • Portlet 标记通常由启用与 Portlet 的交互的链接组成。通过使用 PortletAPI,Portlet 可以在呈现链接和操作链接间进行选择,还可以将参数与每个 URL 进行关联。作为任何链接调用的结果,Portlet 可能会定义一个当前呈现参数集。对于呈现链接,呈现参数为在被调用的链接上编码的参数。而对于操作链接,将计算呈现参数以将其作为操作处理的结果。门户框架保证即使最终用户与页面上其他 Portlet 或构件(如页面导航)进行交互,也会保留页面上每个 Portlet 的呈现参数。这意味着页面上每个 URL 都需要包含该页上的所有 Portlet 的所有呈现参数。而这样的结果就是单个 Portlet(其中包含链接)的标记依赖于该 Portlet 在页面上的上下文。

然而,片段缓存方法假定所缓存的标记独立于上下文;否则从前一个上下文中生成的缓存的标记就不能与当前上下文中的标记进行聚合。

WebSphere Portal 将确保专用标记片段将被缓存到包含独立于上下文的 URL 的片段缓存中。这一点是通过对缓存片段而不是非缓存片段应用不同的 URL 生成机制实现的。从缓存检索到的用以聚合到门户页面中的片段需要了解当前的页面上下文。WebSphere Portal 会对缓存的片段应用 URL 重新编写机制,以确保此片段中包含正确的聚合页面导航状态上下文。

图 7. Portlet 缓存
图 7. Portlet 缓存
图 7. Portlet 缓存

通过在其 portlet.xml 描述符(请参阅Portlet 描述符示例),Portlet 可以广告它们能够在片段中缓存。要使用片段缓存功能,需要在 WebSphere Application Server 管理控制台的 Web Container 区域激活 Servlet 缓存(请参阅 Portlet 描述符示例)。WebSphere Application Server 还提供了一个缓存监视器企业应用程序 (CacheMonitor.ear),此应用程序在可视化片段缓存的内容方面非常有用。

对象缓存和状态处理

自适应页面缓存和 Portlet 缓存提供了强大的方法,用以通过避免可能很费时的 Portlet 标记生成过程来缩短呈现时间。高效使用 Portlet 编程模型(有关 JSR 168:Portlet 规范的信息,请参阅参考资料),并有效利用 WebSphere Portal 的状态处理概念,也可以大幅度减少仍然需要呈现标记的情况下生成标记所需的时间。

本部分将介绍这些状态处理概念,并说明如何将 WebSphere Application Server 提供的 DistributedMap 用于使会话保持较小,并同时改进响应时间和可伸缩性。还提供了一个示例应用程序,以演示这些概念的实际应用(请参见附录 E)。

状态处理
WebSphere Portal V5.1 增强了其 JSR 168 编程模式的实现,支持以下可供 Portlet 使用的状态类型:

  • 持久性状态,通过 PortletPreferences API 公开。Portlet 实现人员可以使用首选项在门户的最终用户会话中存储和检索数据。
  • 会话状态,通过 PortletSession API 公开。会话状态表示服务器上保持的具有有限生存期的数据,其生存期由 Portlet 容器进行管理。使用会话状态的目的是为了保存不能从另一个状态或当前交互重新计算的瞬时信息。
  • 导航状态,通过 PortletRequest 作为呈现参数或交互参数公开。导航状态代表特定于 Portlet 上当前视图的信息。此状态的生存期就是 Portlet 请求的生存期。Portlet 容器确保在最终用户与其他 Portlet 构件(即页面上的其他 Portlet 或 Theme 中的导航)交互期间,将管理 Portlet 的导航状态。导航状态是为 WebSphere Portal 启用浏览器的“后退”按钮的关键概念。
图 8. WebSphere Portal 状态
图 8. WebSphere Portal 状态
图 8. WebSphere Portal 状态

甚至早在 Portlet 的设计阶段,就需要将 Portlet 管理的各个状态进行区分,并对其进行适当的编码,这一点非常重要。特别地,由于可能在不同导航的组合中访问同一个会话,因此应将导航状态和会话状态设计为彼此正交。如果用户使用“后退”按钮调用包含 Portlet 特定的状态的书签,或打开与原始窗口共享会话的新浏览器窗口,并在两个窗口中独立导航,通常会发生这种情况。

Portlet 所生成的每个链接都属于以下两种类别之一:

  • 操作链接,触发对 Portlet 操作阶段的调用。Portlet 在此阶段可以随意改变会话状态或后端状态,并在操作阶段结束时关联新的呈现参数。这些呈现参数将在操作请求后的呈现请求中失效。这种灵活性的缺点在于有性能损失,因为将在页面上其他 Portlet 开始呈现之前调用操作阶段。只有在操作结束后,这些 Portlet 才能开始它们的呈现,而如果启用了 WebSphere Portal 的并行 Portlet 呈现功能,则这些呈现可以并行执行。另外,操作链接应该始终编码为 POST 链接,以与针对 WWW 的 W3C 架构建议(请参阅参考资料)相符。
  • 呈现链接,将新的呈现参数集与调用链接时发出的请求关联。由于调用了呈现链接,将不会调用 Portlet 的操作阶段,Portlet 必须使用新的呈现参数集呈现其视图。由于调用呈现链接,因此 Portlet 不可修改会话状态或后端状态。呈现链接提供了与 Portlet 交互的最高效的方法(使用 JavaScript™ 的原始客户端交互除外),只有在已修改了导航状态的情况下才适合使用。应将呈现链接编码为 GET 链接。

有关这些概念的应用程序示例,请参阅附录 E

对象缓存
在标记生成期间或操作执行期间,经常有必要访问慢速后端或执行一些较为费时的计算。可以将此类操作的结果进行缓存,以使后续请求的执行速度更快。不过,Portlet 会话并非缓存此类信息的位置,因为 Portlet 会话基本上都是由不可重新创建的数据组成的。Portlet 容器(最终为应用服务器)将确保在群集环境中会话状态将跨节点故障保留,甚至能够在群集中复制。此管理需要使用资源。而且,不能在会话的生存期结束前自动丢弃会话中的缓存数据(而在低内存条件下需要释放内存)。

会话状态缓存的状态区分开很重要。Portlet 应该使用缓存(而不是会话)保存缓存的数据,以在节约系统资源的同时增强性能。来自导航状态、会话状态或后端状态的可以重新创建的所有数据都适于进行缓存。缓存与会话相比,其优点在于缓存中的数据可以由于低内存事件、超时等等原因而丢弃,而且缓存基础设施不需要像处理会话数据一样使用很多资源保证缓存数据的可用性。

WebSphere Application Server 利用 DistributedMap 提供了一种有效的方法,可供任何 Web 应用程序用于存储任意 Java 对象。DistributedMap 接口是用于动态缓存的简单接口,使用此接口,通过将引用存储到缓存中的对象,J2EE 应用程序和系统组件可以缓存和共享 Java 对象。DistributedMap 是由应用服务器管理的 J2EE 资源,可以通过 Java 命名和目录接口 (JNDI) 查询从 Web 应用程序进行访问。Portlet 应在其初始化阶段进行此查询,并应将缓存实例的引用作为 Portlet 的实例变量保留。可以在一个服务器上配置多个 DistributedMap 实例,其中每个实例都具有不同的 JNDI 名称和缓存特征。最重要的特征包括:缓存大小、缓存项的缺省超时值和共享策略。有关 DistributedMap 的管理和接口的更多信息,请参阅参考资料中的 WebSphere Application Server 信息中心。

必须对 Portlet 进行编码,以使其能够预期缓存未命中;即,不依赖于缓存信息可用这一假设。特别要注意,不能将缓存作为在 Portlet 的请求周期中的操作阶段和呈现阶段共享数据的手段。由于低内存条件和通过管理控制台进行了缓存大小的管理修改,因此可能将缓存配置(暂时)为完全不缓存数据。Portlet 特别需要做好在呈现阶段重新创建信息的准备(例如,通过访问后端)。从性能的观点来看,最好在呈现阶段尽可能多地进行所需的后端交互,因为同一页面上的其他 Portlet 可能会并行呈现。在理想的情况下,呈现页面的延迟为该页上所有 Portlet 延迟的最大值(如果所有 Portlet 顺序呈现的话,就为延迟的总和)。

使用 DistributedMap 时,Portlet 需要确保其在此缓存中使用的键不会与其他 Portlet 在同一个缓存中使用的键冲突。要确保这一点,可采用多种方法:

  • Portlet 开发人员确定缓存是为多个 Portlet 应用程序共享的,还是特定于 Portlet 应用程序的。如果缓存可以共享,Portlet 可以使用预定义的 JNDI 名称“services/cache/distributedmap”访问全局共享的缓存。如果缓存为特定于应用程序的(即供现有的基于相同 WAR 文件的所有 Portlet 应用程序),Portlet 可以通过以下方法预配置其缓存:通过在 WEB-INF/classes 目录中提供 distributedmap.properties 文件,或通过将缓存的 JNDI 名称设置为配置参数。然后,管理员就可以使用 WebSphere Application Server 的管理控制台生成适当的 DistributedMap 实例了。
  • Portlet 开发人员通过将作用域标识符作为前缀添加到键前,可以确定缓存项的作用域。例如,可以使用和组合以下作用域来生成相关的缓存键:
    • 会话作用域,可以通过使用 sessionID 作为前缀指定。
    • Portlet 窗口,可以通过使用 JSR168 API 的 getNamespace() 方法生成 Portlet 窗口专用的缓存键。尽管 JSR168 API 只保证命名空间对于单个页面是唯一的,但 WebSphere Portal 可以确保命名空间不会随时间的变化而变化。
    • 用户作用域,可以通过将用户的 ObjectID 或 DN 作为键前缀指定。

有关这些概念的应用程序示例,请参阅附录 E

除了缓存数据外,DistributedMap 还允许显式地使各个键失效。映射的实例可以配置为共享,也可以配置为非共享。共享映射将试图同步保留群集中不同节点的映射实例的内容,而非共享缓存则包含特定于节点的数据。不过,对缓存进行失效操作却始终分布在整个群集中。出于性能考虑,最好将缓存配置为非共享,并显式地对缓存项进行失效操作。由于 Portlet 交互本身的特性,通常在操作阶段对缓存项进行失效操作,而缓存的访问和填充则通常在呈现阶段进行。

结束语

IBM WebSphere Portal V5.1 允许您从单个门户运行整个网站(包括动态应用程序和静态内容)。可以在您的门户内多个层次上使用缓存。新引入的自适应页面缓存概念支持对完整门户页面进行缓存。门户将自动确定哪些聚合页面可以缓存,并自动设置页面标头以将站点中的静态部分缓存到反向代理或浏览器中。初始访问后,就可以和常规静态网站一样的速度从缓存中提供这些页面了。通过为包括在页面中的组件标记片段指示恰当的生存期和缓存作用域,站点高度动态的部分将自动在页面中呈现。

对于部分动态的页面,WebSphere Portal 支持 Portlet 缓存,以便只对交互 Portlet 或显示实时内容的 Portlet 提供的页面动态部分按请求进行呈现,而 Portlet 所呈现的、具有一定有效时间的静态或半静态部分将从 Portlet 缓存中获取(直到过期为止)。

在实现交互应用程序(必须按请求呈现)的 Portlet 内,可以使用对象缓存优化单个呈现操作的性能。

自适应页面缓存、Portlet 缓存及对象缓存,通过与各种在 WebSphere Portal 代码库中实现的内部性能增强功能配合使用,允许您在 WebSphere Portal 5.1 上运行整个高性能网站。与采用以门户产品为核心并辅以采用不同管理方式的常规 Web 服务器的混合方法相比,此方法可降低总体拥有成本,并同时提供更好的可管理性。

附录

以下的附录部分提供更为详细的技术细节,描述每种受影响的组件提供与远程缓存相关的信息的方式。也可以使用此信息作为管理员或 Portlet 开发人员需要完成的事项的清单使用,以在 WebSphere Portal 中允许一组页面在远程缓存中进行缓存。

附录 A:提供远程缓存值的组件

门户页面如何提供缓存信息

缓存作用域和缓存过期时间值以及“忽略缓存中的访问控制”设置均可在 WebSphere Portal 图形用户界面中通过门户页面的编辑页面属性管理功能进行设置。也可以通过 XML 访问脚本设置这些值,如清单 1 所示:

清单 1
<!-- Page with cache scope "shared" and cache expiration time 30 seconds -->
<content-node 
   action="update" 
   uniquename="wps.xmplPage" 
   ordinal="last" 
   content-parentref="parentPage" 
   themeref="xmplTheme" 
   active="true" 
   allportletsallowed="false" 
   create-type="explicit" 
   type="page"
>
   <supported-markup markup="html" update="set"/>
   <localedata locale="en">
   <title>Example Page</title>
   </localedata>
   <parameter name="remote-cache-scope" type="string" update="set">
      SHARED
      </parameter>
   <parameter name="remote-cache-expiry" type="string" update="set">
   30
   </parameter>
   <parameter name="IgnoreAccessControlInCaches" type="string"update="set">
   TRUE
   </parameter>
   <!--more content node stuff should come here -->
   . . .
   
</content-node>

参数名称 remote-cache-scope、remote-cache-expiry 和 IgnoreAccessControlInCaches 均为用于提供此信息的保留字。

Theme 如何提供缓存信息

缓存作用域和缓存过期时间值不能在 WebSphere Portal 的 Theme 图形界面中设置。可以通过 XML 访问脚本设置这些值,如清单 2 所示:

Listing 2
<!-- Theme with cache scope "shared" and cache expiration time 40 seconds -->
<theme 
   action="update" 
   active="true" 
   objectid="xmplTheme" uniquename="wps.theme.example">  
   <parameter name="remote-cache-scope" type="string" update="set">SHARED</parameter> 
   <parameter name="remote-cache-expiry" type="string" update="set">40</parameter>
</theme>

参数 remote-cache-scope 和 remote-cache-expiry 是用于提供此信息的保留字。

Portlet 定义如何提供缓存信息

Portlet 定义将通过其部署描述符提供缓存信息。仅支持符合 JSR 168 规范的标准 Portlet 发布此信息。对于 IBM 遗留 Portlet,WebSphere Portal 将假设全局缺省值对于未经身份验证的页面仍然有用。

清单 3 显示了一个发布缓存信息的标准 Portlet 的部署描述符 (portlet.xml):

Listing 3
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app 
   id="XmplPortletApp"
   xmlns=http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
   version="1.0"
   xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
   xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd
   http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" >
<!-- Example Portlet -->
   <portlet>
      <description>
         Remote Cache Information Example Portlet 
         with cache expiration of 100 seconds.
      </description>
      <portlet-name>Example Portlet</portlet-name>
      <display-name>Example Portlet</display-name>
      <portlet-class>
      com.ibm.wps.example.dzierzon.rci.RemoteCacheInfoSetterPortlet
      </portlet-class>
      <expiration-cache>100</expiration-cache>
      <supports>
         <mime-type>text/html</mime-type>
         <portlet-mode>edit</portlet-mode>
         <portlet-mode>help</portlet-mode>
      </supports>
      <supported-locale>en<>/supported-locale>
      <portlet-info>
         <title>Example Portlet</title>
         <short-title>XmplPortlet</short-title>
         <keywords>Remote, Cache, Performance, Test</keywords>
      </portlet-info>
   </portlet>
</portlet-app>

在上例中,假设给定了一个 <expiration-cache> 节,此节在 JSR 168 规范中被定义为 Portlet 标记片段的门户缓存的通用缓存过期时间。由于没有必要区分内部缓存过期值和远程缓存过期值,WebSphere Portal 会将此作为该 Portlet 定义为远程缓存定义的提供值使用。

此处仍然缺少缓存作用域值 (<remote-cache-scope>) 和另一个 WebSphere Portal 出于性能原因引入的值 (<remote-cache-dynamic>),后者可以先期指示 Portlet 窗口是否会动态发布缓存信息 (<remote-cache-dynamic>)。利用此设置,WebSphere Portal 能够在其设置为 False 的情况下简化 Portlet 容器中的计算。

由于在 JSR 168 规范中定义了此部署描述符,所以 WebSphere Portal 使用此部署描述符的一个扩展发布缺少的值 (ibm-portlet-portal-ext.xmi)。例如:

清单 4
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app 
   version="1.0" 
   xmlns=http://www.ibm.com/xml/ns/portlet/portlet-app_1_0_ext.xsd
   xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
 xsi:schemaLocation="http://www.ibm.com/xml/ns/portlet/portlet-app_1_0_ext.xsd
   http://www.ibm.com/xml/ns/portlet/portlet-app_1_0_ext.xsd" 
>
<!-- The href must match the portlet name in the portlet.xml file-->
   <portlet href="Example Portlet">
      <remote-cache-scope>SHARED</remote-cache-scope>
      <remote-cache-dynamic>true</remote-cache-dynamic>
   </portlet>
</portlet-app>

Portlet 窗口如何提供缓存信息

Portlet 窗口可以在呈现时发布缓存信息。这意味着 WebSphere Portal 将引入或扩展现有的 Portlet 编程接口,此接口可以在呈现时确定要为缓存作用域和缓存过期时间发布哪个提供值。

JSR 168 规范定义了一个通用缓存过期时间值,Portlet 可以在呈现期间随时自行进行设置。由于没有必要区分内部缓存过期值和远程缓存过期值,WebSphere Portal 也将此值作为该 Portlet 窗口用于远程缓存的提供值使用。

清单 5 显示了在呈现时发布缓存过期时间和缓存作用域的标准 Portlet 的片段:

清单 5
. . . 
import com.ibm.wps.util.RemoteCacheInfo;
import javax.portlet.RenderResponse;
. . .
/* Do rendering */
public void doView(RenderRequest renderRequest, RenderResponse renderResponse)
   throws PortletException, IOException {
   /* Some code might happen here */
   . . . 
   /* Publish an expiration time of 200 seconds during rendering */
   renderResponse.setProperty( 
      RenderResponse.EXPIRATION_CACHE, "200" );
   /* Publish a cache scope value of "shared" during rendering *)
   renderResponse.setProperty( 
      RemoteCacheInfo.KEY_SCOPE, RemoteCacheInfo.Scope.SHARED_STRING );
   /* Some other code might happen here */
   . . . 
}

由于 JSR 168 规范中未定义缓存作用域,因此 WebSphere Portal 将提供一个名为 RemoteCacheInfo 的接口,此接口提供键和值的静态字符串,用以设置呈现响应中的缓存作用域信息(如上例所示)。也可以选择直接使用以下字符串:

  • 缓存作用域属性键:portlet.remote-cache-scope
  • 缓存作用域属性值:SHAREDNON_SHARED

WebSphere Portal 如何提供缓存信息的全局值

WebSphere Portal 中有三个影响与远程缓存中的缓存相关的全局值的全局设置:

  • public.session ——指定即使对于未经身份验证的(匿名)用户,是否也应创建会话。
  • public.expires ——远程缓存的缓存过期时间(以秒为单位),只针对未经身份验证的用户。WebSphere Portal V5.1 之前的版本支持此设置,为了实现向后兼容,仍然在某些计算中考虑此设置。请注意,如果值为 -1 则认为其为无限大,因此是一个比 0 大的值。
  • remote.cache.expiration ——远程缓存的远程缓存过期(以秒为单位),同时适用于用于经过身份验证的页面和未经身份验证的页面。此设置是在 WebSphere Portal V5.1 中引入的。请注意,如果值为 -1 则认为其为无限大,因此是一个比 0 大的值。

在属性文件 NavigatorService.properties 中可以找到上述的所有属性,此文件位于以下目录中:<portal-install-root>/shared/app/config/services。编辑此文件后,需要重新启动 WebSphere Portal 以使其生效。请记住,如果 WebSphere Portal 安装在群集上,则需要以同样方式在群集中的每个节点上更新此文件。

另一个可能提供总体缓存信息的属性就是请求是否为未经身份验证的请求。此信息布保留在文件或数据库中,需要对传入的每个 WebShpere Portal 进行此项检查。

附录 B:远程缓存信息计算示例

作为一个例子,我们假设以设定了以下的门户页面和设置:

图 9. 远程缓存示例页面
图 9. 远程缓存示例页面
图 9. 远程缓存示例页面

存在一个提供以下值的门户页面:

  • 远程缓存过期:100 秒
  • 远程缓存作用域:SHARED

与此页面关联的 Theme 提供以下值:

  • 远程缓存过期:40 秒
  • 远程缓存作用域:SHARED

在该门户页面上有两个 JSR 168 标准 Portlet。这两个 Portlet 都将 remote-cache-dynamic 的值设置为 True 以告知 Portlet 容器它们也将在呈现时提供远程缓存信息。

第一个 Portlet 的 Portlet 定义提供的值为:

  • 远程缓存过期:15 秒
  • 远程缓存作用域:SHARED

第一个 Portlet 的 Portlet 窗口提供的值为:

  • 远程缓存过期:20 秒
  • 远程缓存作用域:SHARED

第二个 Portlet 的 Portlet 定义提供的值为:

  • 远程缓存过期:100 秒
  • 远程缓存作用域:NON_SHARED

第二个 Portlet 的 Portlet 窗口也提供以下值:

  • 远程缓存过期:100 秒
  • 远程缓存作用域:NON_SHARED

门户通过 NavigatorService.properties 文件中的设置提供以下全局值:

  • public.expires:60 秒
  • remote.cache.expiration:50 秒
  • public.session:False

对此页面的请求为:

  • 未经身份验证的。

步骤 1:计算全局值

在第一步中,WebSphere Portal 将计算全局缺省值和全局最大值,如全局默认值和全局最大值中的流程图所示。

此算法得到结果为:

  • 远程缓存过期的全局最大值:50 秒
  • 远程缓存作用域的全局最大值:SHARED

在所给的示例,还得到以下的值:

  • 远程缓存过期的全局缺省值:50 秒
  • 远程缓存作用域的全局缺省值:SHARED

请注意,全局缺省值和全局最大值并不一定相等。如表中所示,有时候两类值也会不同。

由于我们的所有相关提供者(门户页面、Theme 和 Portlet)都提供了自己的远程缓存信息,因此没有必要使用全局缺省值,也就没有必要进行进一步的计算。

步骤 2:计算远程缓存过期值

在第二步中,WebSphere Portal 将计算所有组件提供的信息的远程缓存过期最小值。

正如前面所提到的,对于 Portlet 有一个特殊的机制处理提供的缓存过期值。Portlet 窗口提供的缓存过期值始终优先于 Portlet 定义提供的值,而不会考虑二者的相对大小。如果 Portlet 窗口没有提供缓存过期值,则将使用 Portlet 定义中的值。在我们的示例中,则这将导致使用一个比第一个 Porlet 中指定的值更大的缓存过期值。

第一个 Portlet 的 Portlet 定义15 秒
第一个 Portlet 的 Portlet 窗口20 秒
第一个 Portlet 的结果值20 秒
第二个 Portlet 的 Portlet 定义100 秒
第二个 Portlet 的 Portlet 窗口100 秒
第二个 Portlet 的结果值100 秒

现在已经计算了所有提供值的最小值,如下所示。

门户页面100 秒
Theme40 秒
全局最大值50 秒
第一个 Portlet20 秒
第二个 Portlet100 秒
结果值20 秒

步骤 3:计算远程缓存作用域

在第三步中,WebSphere Portal 将计算所有组件提供的信息的远程缓存作用域最小值。

对于缓存过期值,也有一个针对 Portlet 缓存作用域提供值的特殊机制。Portlet 窗口提供的缓存作用域始终优先于 Portlet 定义所提供的值,而不考虑二者的相对大小。如果 Portlet 窗口没有提供缓存作用域值,则将使用 Portlet 定义中的值。在我们的示例中,由于 Portlet 窗口的缓存作用域与 Portlet 定义的作用域相同,所有这个机制并没有得到明显体现。

第一个 Portlet 的 Portlet 定义SHARED
第一个 Portlet 的 Portlet 窗口SHARED
第一个 Portlet 的结果值SHARED
第二个 Portlet 的 Portlet 定义NON_SHARED
第二个 Portlet 的 Portlet 窗口NON_SHARED
第二个 Portlet 的结果值NON_SHARED

现在已经计算了所有提供值的最小值,如下所示。

Portal 页面SHARED
ThemeSHARED
全局最大值SHARED
第一个 PortletSHARED
第二个 PortletNON_SHARED
结果值NON_SHARED

WebSphere Portal 进行了所有的计算后,将把完全呈现的页面的相应的标头写回 HTTP 响应。在我们的示例中,这些标头可能为:

  • Cache-Control:private
  • Cache-Control:max-age=20

附录 C:远程缓存中的缓存检查单

当为自适应页面缓存修改了门户设置时,您可能希望开始分析系统,以了解门户产生意外响应的情况。此处给出排除故障时首选需要检查的项目:

  1. 使用工具检查 HTTP 响应标头。响应标头是 WebSphere Portal 为远程缓存中的缓存提供的唯一附加信息。
  2. 如果响应标头设置正确,则调查浏览器或代理服务器不按预期工作的原因。

如果没有按照预期的方式设置响应标头,则检查以下各项:

  1. 特定页面的所有 Portlet 定义都实际提供缓存信息吗?检查部署描述符和部署描述符的扩展。
  2. 是否有一个 Portlet 意外地覆盖了部署描述符的设置?跟踪所有自定义 Portlet 以了解此可能性。
  3. Portal 页面是否提供了正确的信息?检查图形用户界面中或该门户页面的 XML 访问导出的输出文件中的设置。
  4. Theme 是否提供了正确的信息?检查该 Theme 的 XML 访问导出的输出文件中的设置。
  5. 对 WebSphere Portal 的请求是经过验证的,还是未经验证的?请求验证与否可能会影响全局缺省值。使用工具(请参阅参考资料)以确定响应是否包含会话 Cookie,如果包含,则认为请求是经过验证的请求。
  6. 提供的全局值是否正确?请注意为了与以前版本的 WebSphere Portal 兼容而采用的特殊行为和计算过程。检查全局缺省值和全局最大值中说明的算法。

附录 D:Portlet 缓存示例应用程序

此示例应用程序演示 Portlet 缓存中讨论的 Portlet 缓存。

介绍

该示例应用程序包含一个由多个页面组成的 Portlet,其中显示当前的页码、时间戳、三个用于浏览可用页面的链接以及一个“Invalidate me!”操作 URL。随机数只是用于演示目的。

图 10. Portlet 缓存示例
图 10. Portlet 缓存示例
图 10. Portlet 缓存示例

整个内容是 WebSphere Applications Server 的 Dynacache 引擎提供的片段。如果用户重新加载 Portlet,除非两个请求之间缓存过期,否则随机数不会更改。

图 11. Portlet 缓存示例
图 11. Portlet 缓存示例
图 11. Portlet 缓存示例

由于缓存键包含来自于导航状态参数的相关信息,因此可以缓存同一个 Portlet 的多个视图。

Portlet 描述符

清单 6
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" version="1.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd 
	http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
    <portlet>
        . . .
<!-Expiration value is in seconds, -1 = no time limit, 0 = deactivated-->
	<expiration-cache>3600</expiration-cache> <!- 1 Hour cache -->
        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
        </supports>
        . . .
    </portlet>
</portlet-app>

管理控制台

图 12. 管理控制台
图 12. 管理控制台
图 12. 管理控制台

附录 E:对象缓存的示例应用程序

此示例应用程序按照对象缓存与状态处理所述演示对象缓存和 JSR168 状态处理概念的应用。

介绍

示例应用程序由显示 IBM 的当前股票报价的 Portlet 组成,该 Portlet 允许用户将一定数量的股票添加到其购物车中。该 Portlet 由两个屏幕组成,第一个显示当前的股票报价和购物车中当前的股票数量,第二个屏幕提供一个输入字段,允许用户输入要添加到购物车中的股票数量。该 Portlet 使用 Web 服务查询当前的股票价格。此服务寄宿于某个 Internet 市场数据提供程序中,延迟时间可能很长。

图 13. CacheTest Portlet
图 13. CacheTest Portlet
图 13. CacheTest Portlet
图 14. CacheTest Portlet
图 14. CacheTest Portlet
图 14. CacheTest Portlet

状态处理

该示例应用程序将要显示的屏幕类型作为呈现参数存储,将购物车的内容(股票的数量)作为会话参数存储。这样就允许用户在显示购物车中股票数量时使用“后退”按钮在两个屏幕间切换。(“后退”按钮不会更改购物车的内容。)用于在两个屏幕间切换的“click here”链接被编码为呈现链接,且直接将目标屏幕作为链接本身上的一个参数编码。

在第一个屏幕中:

清单 7
<% url = renderResponse.createRenderURL();
url.setParameters(renderRequest.getParameterMap());
url.setParameter(Constants.KEY_VIEW, Constants.VALUE_VIEW_BUY);
 %>
<p>Click <a	href="<%=url %>" title="Go Shopping">here</a>
to add stocks to your shopping cart.</p>

在第二个屏幕中:

清单 8
<% url = renderResponse.createRenderURL();
url.setParameters(renderRequest.getParameterMap());
url.setParameter(Constants.KEY_VIEW, Constants.VALUE_VIEW_STOCK);
 %>
<p>Click <a	href="<%=url %>" title="Go Home">here</a>
to go to the main view without buying.</p>

请注意,呈现链接包含下一个请求的呈现参数的全集,而不只是相对于当前呈现参数的修改。正是由于这个原因,代码才首先将当前呈现参数集与呈现 RUL 关联,“url.setParameters(renderRequest.getParameterMap());”,然后才修改此集以使其表示下一个屏幕。

在这个非常简单的示例中,通过复制当前呈现参数集并只覆盖一个键,就可以计算新的呈现参数集。在更为复杂的场景中,要生成呈现 URL,可能需要进行更为复杂的计算。如果此计算需要很长时间,Portlet 应该为 URL 缓存呈现参数,且应使用当前的呈现参数集作为键(请参见下一部分)。不过,Portlet 绝不能缓存 URL 本身。

对象缓存

对于此示例应用程序,呈现期间的延迟是由于访问远程股票报价服务所造成的。对于本示例,没有必要显示实时股票信息,为了获得更快的显示性能,最好使用旧的股票价格进行交易。该 Portlet 使用应用服务器提供的 DistributedMap 并通过提供一个 distributedmap.properties 文件部署它自己的缓存:

图 15. DistributedMap
图 15. DistributedMap

其内容如下:

/services/cache/StocksCache
cache.instance.0.cacheSize=1000

然后将在 Portlet 的初始阶段对缓存进行解析,并将其作为实例参数保留:

清单 9
public class CacheTestPortlet extends GenericPortlet implements Constants {
	protected DistributedMap cache;
. . .
	public void init(final PortletConfig cfg) throws PortletException {
		// lookup the dynacache
		try {
			final InitialContext ic = new InitialContext();
			cache = (DistributedMap)
                           ic.lookup("services/cache/StocksCache");
		} catch (NamingException ex) {
			throw new PortletException(ex);
		}
		// default handling
		super.init(cfg);
	}

在呈现阶段,Portlet 将使用 JSP 生成标记所需的所有信息填充 Bean。其中的一条信息就是股票报价,此信息要么从缓存中获得,要么从后端系统检索获得。

清单 10
final String cacheKey = resp.getNamespace() + "IBM";
// try to get the stocks value from the cache
final Float cachedValue = (Float) cache.get(cacheKey);
if (cachedValue != null) {
	aBean.setFromCache(true);
	aBean.setValue(cachedValue.floatValue());
} else {
	// get the value from the Web service
	final StockquoteStockQuoteServiceLocator loc = 
      new StockquoteStockQuoteServiceLocator();
	final StockquoteStockQuotePortType port = loc					
		.getStockquoteStockQuotePort();
	final float fValue = port.getQuote(aSymbol);
	// update the bean
	aBean.setFromCache(false);
	aBean.setValue(fValue);
	// update the cache
	cache.put(cacheKey, new Float(fValue));
}

相关主题


评论

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=WebSphere
ArticleID=91009
ArticleTitle=IBM WebSphere 开发者技术期刊: 使用 WebSphere Portal V5.1 开发包含静态内容和动态内容的高性能网站
publish-date=06152005