高可用性要求一种合适的基础结构但是如果没有将该基础结构与JEE应用程序设计策略进行协调平衡性能很可能就会受损 如果您在高可用性硬件和软件基础结构方面投资了一笔数目可观的资金您就必须保证应用程序具备高可用性-至少应保证JEE(Java 平台企业版)中普遍存在的做法可保证应用程序具备高可用性别忘了当您将数据库和应用程序服务器的群集与群集软件进行组合时您将会获得一个相当有效的组合这里的群集软件包括Oraclei数据库和Oraclei应用程序服务器(OracleiAS)中的软件这些群集软件既可以将请求自动发送到可用的服务器还可以提供透明的应用程序失败处理当您在JEE体系结构中增加这类数目众多的混合状态管理机制(具有状态的Web会话和无状态Web会话具有状态的商业组件和无状态商业组件自动复制或备份beans等等)时您应该同时保证具备高可用性 不幸地是这种普遍的做法并非完全正确尽管服务器与相应软件的群集可以提供高可用性但是它们却无法保证高可用性事实上某些高可用性功能(如JEE的状态管理机制)的过度使用就可能会降低应用程序的性能进而降低整体的可用性 即便使用最好的体系结构要真正实现高可用性其中的关键一步就是从一开始就把高可用性考虑到应用程序的设计中来因此您需要从以下几个方面来特别关注应用程序的设计 · 便捷的状态管理 投入一定时间来识别并确定应用程序的状态然后将状态精确映射到各种可用的状态管理机制避免过度使用某一类型的机制而导致性能降低 · 仔细的层次设计 分析应用程序是否真正需要很多层层次会增加复杂性导致性能劣化并且降低可用性 · 失败处理策略 确定并处理那些基础结构无法自动检测和修复的失败 如果在应用程序设计的各个步骤中额外多投入一些时间同时应用本文所描述的各种策略那么应用程序的可用性将会显着增强 便捷的状态管理 要确保实现高可用性您就需要具备有效的状态恢复机制如果一个组件失败系统在处理新的请求之前必须先恢复该组件所保持的状态 JEE提供多种便捷的状态管理机制但是这些机制常常被过度使用而过度使用这些机制经常带来一些不幸的结果包括 JavaServer Pages (JSP)页中的会话范围的JavaBeansHTTP会话对象servlets以及用于商业组件的有状态会话bean等在内的这些状态管理机制可以识别并确定失败时必须保持的状态所有这些机制都使用存储在内存中的Java 对象来表示应用程序的状态在HTTP会话过程中以Java形式来保存这些对象可以为编程人员提供必要的便捷但是却很容易会忘记进行相关备份所需的代价 应用程序服务器(如OracleiAS)通过在数据库文件或者备份服务器的有效内存中对这些存储在内存中的Java 对象的副本进行备份就可以在必要时积极采取相应的恢复措施对Java 对象进行备份时常常要求使用代价昂贵的 Java 串行操作如果将许多大型的Java 对象用于状态管理(这是一种常见的应用程序设计策略)就会使JEE 状态管理机制负载过重因此应用程序的性能将会劣化到极低的级别这会让人无法接受当然这也与高可用性的目标背道而驰(我们认为一个速度极慢的应用程序不具有高可用性) 作为这种 JEE 标准方法的另一可选方法您应该关注多数大型 Web 站点(这些站点同时又具备高可用性)所使用的模型在该模型中应用程序的状态主要保存在持久稳固的存储器(如数据库)中同时在内存中进行了缓存处理以便改善响应时间(这与JEE模型不同JEE模型中一开始就将状态存储在内存中然后由应用程序服务器进行备份)这里最关键的不同之处就是对于大型的Web站点模型应用程序的写进程已投入一定时间来识别并确定应用程序状态的关键片断同时还设计了一种有效机制(缓存)用于从应用程序对缓存进行访问因而中间层组件的失败并不需要恢复中间层的状态而仅需重新启动缓存这是因为需要时可以从后端再次导入相关的状态 一些大型的 Web站点更进一步它们对应用程序的状态进行分离然后将其分别存储在稳固持久的后端存储器和客户端浏览器中一些状态以cookie的形式保存在浏览器中这样就隐藏了 HTML 形式的元素或 URL 参数这种技术不仅提供了更高的可用性而且还提高了应用程序的整体品质如果浏览器处于未连接状态这种技术允许终端用户很容易地重新开始连接会话 现在很清楚了JEE应用程序开发人员需要预先投入一定时间来分析应用程序状态然后根据特定策略将其映射到适当的可恢复存储器中 接下来的一个问题就是如何确定哪些状态应该映射到后端数据库而哪些状态应该映射到浏览器幸运地是这个问题的答案通常是相当简单直接的它取决于所要映射的状态信息的类型 应用程序的状态通常可分为下面三种类型 · 页状态此种类型的状态在一页中是有效的例如搜索查询返回的一系列结果的开始索引 · 会话状态此种类型的状态通常在一次会话的整个过程中是有效的例如运行应用程序的末端用户的身份 · 持久状态此种类型的状态的生命周期为端用户会话例如购物报表或开支报告的内容在常见的典型应用程序中大多数应用程序状态都是这种持久状态类型的 一旦您将应用程序的状态划分为上述三种类型您就可以将状态映射到适当的持有器中请您在脑中牢记您的目标之一就是通过一种JEE 机制使在中间层内存器中保存的状态尽可能少 映射页状态处理页状态的最佳方式就是将其存储隐藏形式的元素或URL参数中这些元素或参数嵌套在该页中因为此状态需要在该页面对浏览器可用的整个期间中始终保持因而它并不会产生恢复问题诸如 OracleiAS 的JEE MVC 框架之类的模型查看控制器(Model View Controller)框架使用隐藏形式的元素将页面流信息保存在每一个Web页面中 映射会话状态您可以保存一些会话状态如用户身份和in cookies身份验证系统(如OracleiAS Single SignOn)就使用此种方法然而您需要在中间层内存中保存会话状态的其他一些部分如果cookie 的数目过多或者内容过大就无法进行高效操作在这些情况下您就应该使用之前已提及的一种 JEE状态管理机制把使用这些机制的情形限制到这些场合有助于保持较高的可用性 映射持久状态您应该非常明确地将持久状态保存在后端数据库中您可以在中间层内存中对其进行缓存以便提高效率(OracleiAS 中的特殊JSP 标记库可以在 Web 缓存和 JEE 容器中对页片断进行缓存)然而您可能希望数据库成为真实数据的来源以便中间层失败时避免出现恢复问题请注意强烈建议显式标识状态并且通过正规的数据库访问机制(如实体 beans或 Java Database Connectivity (JDBC))将状态显式存储在数据库中 通过此种方式来映射这三种类型的状态就可以创建状态安全的应用程序状态安全的应用程序可以避免无状态应用程序的局限性而可用性并不差 仔细的层次设计 层次设计是获得可用性的另一领域在JEE中通常有这样一个共识应用程序应该由多种层次组成然而如果您使用过多的层次不仅不会增强可用性反而还可能会阻碍了可用性 使用多种层次的原因是相当明显的首先仔细的多层设计有助于隔离各种故障例如商业组件虽然失败但并不会影响Web前端的可用性这一点可持续至前端需要使用该组件为止而且在一些情况下每一层中运行更少的逻辑可以使每一层变得更健壮 但是使层的数目尽可能保持最低具有非常显着的优势这使应用程序可以更容易地进行管理和监控为那些负责实现高可用性的操作组提供巨大的帮助而且如果一个应用程序具有层数不多通常就更易于设计因而整体上就更加健壮最后设计一个层数不多的应用程序(例如使用Enterprise JavaBeans (EJB) 本地接口)可以获得更优的性能这也同时会大大增强可用性 如果您将目标锁定为高可用性但又无法确定选用的层数应该多一些还是少一些请您相信使用更少的层数出错的可能性就会更低 失败处理策略 与状态管理和层次设计一样我们在失败处理方面过分依赖于常规的方法和高可用性基础结构的实际能力因为现在的应用程序服务器能够自动检测和修复许多组件失败我们就不必投入太多的精力以便我们的应用程序能够处理那些不能自动修复的失败但是我们并没有意识到真正的高可用性则要求应用程序和应用程序服务器之间能够相互协作 双重事务是一种常见的失败类型这种类型的失败很难做到自动修复终端用户两次单击Bill Me 按钮就是该类失败的一个示例由于双重事务的产生因素在于不同层之间的通信失败所以修复就可能会涉及一些位于应用程序服务器内嵌的修复机制范围之外的问题请这样一种简单的情形一个JSP 页面通过JDBC 提交事务但是却收到了网络通信错误那么应用程序服务器如何才能确定在通信失败之前该事务是否已经提交?应用程序服务器是否应该自动再重复先前的操作?这类问题在层次紧密的体系结构中更加难以解决其中JSP页调用在多个分布式容器中运行的EJB通信错误表示bean 调用根本就没有执行完毕在这种情况下再次进行调用就非常合适可是相同的错误也可能是起因于这样一种情况调用本身已取得成功但是 |