用于扩展 JEE 容器/应用程序的并行性、灵活性、多租户和安全性的策略和模式
在本文中,作者概述了云应用程序和 Java? 企业版应用程序的基本特征,比较了他们的相同点和不同点,然后定义了一组策略并提供了一些模式来扩展
Java EE 容器和应用程序,增加一些云的特征,如并行性、灵活性、多租户和安全性。
Java 企业版(JEE)架构是基于组件的,拥有可以高效管理应用程序事务和有状态性、多线程和资源池的特性。即使是复杂的需求,JEE
应用程序也很容易实现,因为业务逻辑是以可重用的组件组织的,并且服务器为各种组件(以容器 的形式)提供了底层服务。
我们认为,可以通过增加一些云计算的强大概念 — 即并行性、灵活性、多租户和安全性
— 给 JEE 的容器服务概念增加更多的功能,这是一种全新的概念。本文将介绍给 JEE 容器和应用程序扩展一些云计算特性的策略和模式。
其中包括:
1.概括介绍我们整合的每一种云特征。
2.JEE 应用程序的现有特征的布局。
3.介绍我们用于将 JEE 容器扩展到云上的方法。
4.提出关于这种类型迁移的一种设计策略,它包含并行、同步、存储、灵活、多租赁和安全等概念。
云计算的特征
图 1 说明了云是什么,以及各种不同的云部署模型。
图 1. 云服务模型及其组件的俯视图
云协议的最基础部分是 Infrastructure as a Service(IaaS)。这些基础架构已经转移到云环境中了,并且云环境现在能够支持包括业务应用程序在内的软件部署。然而,IaaS
并没有一个应用程序开发环境或者测试服务。如图所示,抽象的顶部是灵活性、自动部署和实用计算。
Platform as a Service (PaaS) 层提供了应用程序软件创建、部署和维护的环境。PaaS
提供者必须提供基本的生命周期服务,如编译、部署、测试和构建块服务,如状态管理、事务和安全性,以及运行时的资源管理服务。
Software as a Service (SaaS) 层为最终用户提供了访问和使用应用程序的环境。
应用程序需要支持的基本云特征有灵活性和多租户。其他特征,如分配和自动化,是通过应用程序服务器的部署特性支持的,并且对代码没有太大的影响。并行性、分布式存储需求和安全性增强是作为一些实现灵活性和多租户的辅助特征。
现在让我们详细了解每一种特征。
灵活性
灵活性 是指根据需要自动向上和向下扩展基础架构。在负载峰值期间,集群会增加更多的实例,而当负载下降时,实例的数量也会下降。这是以动态方式实现的。这个功能是由支持动态集群技术的应用程序服务器的特性实现的。
灵活性并不只是应用程序服务器的解决方案;应用程序本身也应该支持灵活性。这意味着应用程序的设计需要能够处理那些用于支持并发性的资源。设计或定制一个应用程序来支持灵活性,意味着您还需要在应用程序中实现并行性、无状态性和事务支持。
设计策略部分描述了如何实现所有资源都支持运行时无状态性的灵活性和并行性。
多租户
多租户 表示您的应用程序以一个应用程序实例来支持多个客户;这意味着如果有
5 位客户同时使用内容管理服务,那么所有 5 个客户都可以使用同一个应用程序实例,数据和执行参数适当分离。为了支持多租赁,您的应用程序需要实现分布式存储、并行性、安全性和松耦合性。
支持多租赁的方法有两种:
1.为所有用户提供一种物理存储方式。
2.为多个用户提供多种物理存储资源。
并行性和事务支持
在本文的内容中,并行性 指的是能够并行执行多个请求或者将大数据量任务划分成多个并行执行的子任务。这有利于提高资源使用效率。引入并行性会对吞吐量和性能产生积极影响。事务支持
是通过保证任何资源的状态变化都是同步的,从而保证可靠性。这两个概念属于两个对立面 —— 如果您在一方面做得更好,那么另一方面就会受到影响。
适当混合并行性和事务支持对于平衡这些相对立的特征是非常重要的。本文的策略部分将介绍四种策略,两种针对于并行性,另外两种针对于事务支持:
1.并行性的同步和异步支持。
2.用于事务支持的一种线程完成(thread-completion)和数据到达(data-arrival)同步方法。
所提出的移植策略采用了非功能性方法来实现并行性,但是其中一些需要进行功能修改。如
Google 框架 MapReduce;MR 描述了一种使用 Map功能实现并行性的方法,它将大型数据分割成多个键-值对。(见
参考资料 中关于 MapReduce 和云的文章。)
松耦合性与无状态性
松耦合性 保证服务的每一个调用都是通过一个标准接口发起的;这使得被调用的组件和调用组件能够独立修改,彼此互不影响。松耦合是通过一个发起调用的代理引入的。无状态性
是松耦合的一种特性,其中服务的每一个调用都不依赖前一个调用。这是通过在一个持久化存储中管理状态变化而实现的。
这两种策略是使系统调用与依赖条件更加独立的辅助特征。
分布式存储
分布式存储 是一种存储数据的方法,这样数据的位置就会变得不重要。它也意味着同一块数据可能会存储在不同的位置。这个特征能够提高灵活性和无状态性,但是会对事务支持产生负面影响,所以它们需要进行一些平衡考虑。
分布式存储包括 4 种策略:
1.复制节点:数据存在于不同的节点上,能够快速地复制到其他节点。
2.随需复制:定义了触发器来触发数据的手动复制或自动复制。
3.单向故障恢复复制:从主节点到子节点的复制计划;当主节点出现故障时,复制任务会交由一个特定子节点完成。
4.文件系统共享:当复制开销像其他文件系统资源一样时使用。
安全性
云应用程序安全性会对特定的特征产生重大影响:多租户、并行性和松耦合性都会增加安全性需求。而且,如果您的应用程序以混合模式部署(例如,云组件与本地系统组件),那么您需要实现一种跨域的单点登录功能,而这会对安全性造成额外的影响。
分布式存储、并行性和传输也有一些安全性问题。
现在您已经熟悉了云应用程序的特征,现在让我们了解一下 Java EE 的容器结构。
Java EE 容器应用程序特征
传统 JEE 应用程序依赖于容器服务,并且使用:
1.严格的会话来管理连接状态
2.直接通过 SQL 或间接使用 ORM 的存储过程来实现 RDBMS
3.JMS 对象
它们也使用消息驱动的 Bean 和 Session Bean,以及使用容器提供的框架来实现
Web Service。新创建的应用程序可能会使用异步处理,以及缓存服务或 JavaMail 服务。
让我们详细了解 JEE 应用程序的一些属性和功能。
数据与操作
每一部分的编程逻辑都会抽象到一个 与数据(或内存)相关的部分 和 与操作(或执行)相关的部分,它们相互之间会发生交互,这样操作用来处理数据,而数据被操作使用。整个
JEE 包,包括容器和应用程序,都可以采用相同的方式进行抽象。
容器
数据方面的质量是通过保证数据访问可靠性、数据访问可用性和支持数据存储的并发性与安全性等功能进行判断的。操作方面的质量是通过保证监听器监听数据到达、发起远程调用以及访问控制和传输安全性等功能判断的。
表 1. 提供 JEE 应用程序的数据和操作方面的质量
容器的作用是双重的:
1.使用一种机制保证维持数据和操作的质量特征。
2.控制系统资源的使用,如内存泄漏、运行的线程数等。
这会导致出现两种您需要关注的完全不同的模式,托管资源模式和托管任务模式。
托管资源模式
托管资源模式提供了与数据相关的服务,它实现了会话管理、事务、持久化和安全性。调用者使用使用命名目录来定位资源管理器。资源管理器会使用容器提供的对象池来管理系统资源。典型的管理资源采用如图
2 所示的模式。
图 2. 托管资源模式
容器或应用程序可以通过 JNDI 获得资源管理器的控制。资源管理器实现了对象池,它能够获得实现持久化、安全性状态管理和事务的托管资源模式。
托管任务模式
托管任务提供了与操作相关的服务,它们实现了远程调用、监听器和安全性,同时它使用了容器提供的线程池和命名目录服务。此外,一个托管任务很可能封装了一个或多个它所处理的托管资源。
托管监听器是由容器基于数据到达触发的,数据可以是时间、消息或请求的形式。它也可能被应用程序触发。
图 3. 托管任务模式
容器提供的每一个服务都可以分解为其中一种模式,或者两种模式组合。例如,Java
Message Service (JMS) 具有一种 JMS Destinations 的托管资源模式和一种
JMS MessageListener 托管任务模式。类似地,JDBC Connection 是一种托管资源模式。
现在,我们已经介绍了 JEE 容器的应用程序的工作方式,接下来让我们了解如何将一个容器应用程序扩展到云上。
扩展容器:基本方法
将容器向云特征扩展的方法是为了:
1.将云特征分解到实现特征中,
2.使用与实现特征相关的修改来强化托管资源模式和托管任务模式。
策略部分介绍了托管资源模式是如何扩展到云资源模式的,以及托管任务模式是如何扩展到云任务的。
托管资源模式使用以下扩展来创建云资源模式(见 图 4):
1.CloudResource
2.Isolator
3.Replicator
4.LockManager
5.LockDataResource
6.StateDataResource
类似地,托管任务模式是通过扩展 Proxy 和 StateManager
来创建云任务模式的(见 图 5)。
让我们开始讨论其中一些组件。
云资源模式
云资源模式包括刚刚提到的一组扩展。下面对每一个组件及其之间的交互进行介绍。
1.CloudResource
CloudResource 扩展了托管资源,在需要时支持分布式事务和状态持久化逻辑。
2.StateDataResource
StateDataResource 是 CloudResource 的一种实例,表示指定云资源的一个状态变化。状态持久化本身是以有状态方式执行的。
3.Isolator
Isolator 在输入中指定一个控制域来确定使用客户,并应用相关的安全性和分区逻辑将它存储到正确的位置。Isolator
能够保证应用程序代码不会受到多租赁存储策略的影响,并且保证应用正确的多租赁策略。Isolator 本身是一个
CloudResources 集合。
4.Replicator
Replicator 只有在使用了复制节点和随需存储复制的策略时才会被使用。Replicator
保证数据会作为一个分布式事务持久化到所有复制节点中。Isolator 和 Replicator 之间的区别是
Isolator 保证数据能够到达正确的用户存储,而 Replicator 则保证数据能够到达为某个用户复制的多个存储位置。
5.LockManager 和 LockDataResource
LockManager 的功能是在所有 Replicator 上为进程的某个线程锁定一个特定数据。LockManager
保证在所有复制节点上具有相同的状态视图。这意味着如果将服务器 1 的一个服务器进程的某个线程的数据锁定,那么服务器
2 的过程看到数据的状态是锁定的,即使它所看到的只是存储副本。这个特性仅在复制节点和在随需存储策略的复制中支持。
模式的总体修改可以总结为(图 4):
1.资源管理器现在提供了 Isolator,它能够直接提供一个 CloudResource
或者通过存储策略提供一个 Replicator。
2.云资源现在支持分布式事务,而状态管理则负责处理状态持久化。
图 4. 云资源模式现在支持分布式事务
云任务模式
云任务模式给管理任务模式增加了 Proxy 和 StateManager
扩展。Proxy 决定了并行策略,并指示 StateManager 来控制执行状态的持久化。
1.Proxy
Proxy 是带有预处理和后处理逻辑的管理任务的包装器。预处理逻辑包括消息安全性,以及基于协议对输入进行格式化和执行任务。在任务执行之后,后处理逻辑决定了输出的处理方式。
2.StateManager
任务的无状态执行是为了保证任务的输入是初始状态,而所有与最终状态相关的信息都会存储在输出中。因此,StateManager
负责管理输入和输出,并将它们作为 一个 CloudResource 进行移动。
图 5. 云任务模式的 StateManager
将 I/O 作为一个 CloudResource 进行移动
表 2 详细列出了每个云特征及其相应的设计策略是如何影响 JEE 实现特征的,以及所引用的模式。
表 2. 云特征及其对设计和实现策略的影响
扩展容器:通用容器服务方法
修改现有的容器服务以匹配云资源和云任务模式,并尽可能以非侵入方式将它们附加到应用程序上。总而言之,我们将所有服务转换为云资源模式;当应用程序与云资源模式交互时,
它会将这个模式转换为云任务模式,从而支持在云中使用。下面的清单列出了我们所使用的服务、原始方法和方法。
1.服务:JDBC Database Connections
遗留方法: 管理资源。 方法: 使用支持分布式事务(分成两个阶段的提交)的更高版本,支持线程池和无状态调用的可共享连接。基于已有的更高版本,其余功能可以使用云资源模式提供。
2.服务:JMS 对象
遗留方法: JMS Senders 和 Receivers 是任务,而
JMS 消息和目标是对象。
方法: 与 JDBC Database Connections 采用相同的方法。这个配置可以进行修改,以保证
JMS Server 也出现在所有节点上,其中使用 JMS 客户端来提高灵活性。
3.服务:缓存对象
遗留方法: 当前支持内存或分布式缓存服务。
方法: 所有缓存都需要转换为一个分布式缓存,以实现高效的共享。缓存服务可以选择用一个云资源服务适配器进行包装。
4.服务:Session
遗留方法: 大多数应用程序使用严格的会话。
方法: 代码可以用一种非侵入方式进行修改,其中使用过滤器过滤所有请求,并由这个过滤器来创建一个自定义的
HttpServletRequestWrapper,它可以重写 getSession(),将它转换为一个云资源。从而不需要严格的会话。
5.服务:持久化策略
遗留方法: 基于 ORM 的容器管理技术化是有益的。
方法: 基于对象关系映射的容器管理持久化使应用程序代码不会与存储的关系性质混合在一起。这能够简化将持久层修改为非关系数据库的过程。Hibernate
Shards 也支持分布式存储,并且采用与云资源模式的 Replicator 相同的工作方式。如果应用程序使用
DAO(数据访问对象)来产生动态 SQL 和存储过程,那么传递给 DAO 的值对象就可以使用注释声明为一种云资源。
6.服务:变量
遗留方法: 变量处理方式。
方法: 所有公开变量和静态变量、所有文件输入/输出和所有日志写入都必须修改为使用云资源。
7.服务:方法调用
遗留方法: 方法调用处理方式。
方法: 所有相关的方法调用都转换为一个云任务。
对设计策略的影响
最后,让我们了解一下在您的应用程序中启用云特征会如何影响设计策略。我们将介绍以下方面:
同步和异步并行性。
数据到达和线程完成同步。
复制节点、随需复制、支持故障恢复的单向复制和存储端的文件系统共享。
松耦合和无状态性。
灵活性。
单个存储或分离存储的多租户。
安全性。
并行性
正如之前提到的,并行性指的是任务的并行处理能力,其中任务会分成不同的子任务,它们最后会合并为一个。并行性支持两种策略:同步和异步。
同步
在这种策略下,调用者要等待执行完成之后才能继续后续的任务。每一个任务都使用一个服务调用触发。任务会等待调用者返回。并行性是通过运行主线程为每一个任务调度执行的子线程而实现的,这样任务就会并发执行,而每一个线程是同步执行任务的。
同步策略最适合于数据聚合。当应用程序需要使用不同来源的信息时,来自每个源的数据可以同步获得,而每个源可以同时提取。
异步
在这种策略下,调用者会使用消息以异步方式执行一个任务。当任务完成时,任务的输出会保存在一个持久化存储区中,供下一个任务使用。
这种策略更适合用来处理复杂任务。每一个复杂任务都是异步执行的,它们都会使用同步策略来调用数据聚集任务。
同步策略
同步策略会保证事务支持,从而保证任务的可靠性。它保证相关的任务和数据在下一个任务处理之前就准备好。同步策略有两种:基于数据到达和基于线程完成的同步。
基于数据到达的同步
基于数据到达的同步指的是,任务的执行是基于特定位置的特定数据到达而触发的。当使用了异步调用,而调用的任务需要查找所调用任务在特定位置生成的输出才能够继续后续操作时,这种方法是特别重要的。
一个线程会检查数据区,检查数据的到达。当数据到达时,它会马上发送一条消息给需要触发的任务。MessageListener
是数据到达同步的一种实现。
基于线程完成
在线程完成同步中,资源监控器会检查并发的线程,然后同步这些任务的执行,同时访问该资源。通过组合数据到达策略和线程完成策略,相同的策略可以应用到一个必须在多个实例之间共享的资源上。
这个策略通常会应用到一个 JVM 中的线程上。对于外部资源,这个方法是数据到达同步机制的扩展,其中监控器状态是数据,监听器会把数据传递给当前
JVM 中执行的线程。
存储
存储的类型有很多种;数据库、文件系统、内存数据和诸如原生目录等持久化设备都是存储。存储策略的一个重要需求是要保证
JEE 应用程序能够创建一个真正的网络对象,这个对象的状态变化会反映到集群中所有的 JVM 上,并且能够在动态
RDBMS SQL 失效时移植到一个分布式数据源上。此外,存储策略是并行性和多租户的一个重要组成部分。
复制节点
复制节点策略指的是,相同的数据存在于不同的节点上,并且能够快速地复制其他节点。数据库支持暖复制和热复制策略。其他存储区则需要使用分两个阶段提交的策略。
这个策略的执行至少需要两个线程的支持。其中一个线程会同步调用保存/更新操作。它会通过套接字连接将数据发送给其他节点,然后接收响应,它会发出提交命令,这个命令实际上会更新这些节点。监听器线程会监听其他节点的变化,并对它们作出响应。套接字连接可以替换成基于消息或
http 的服务。
复制是最适合用于较少更新的只读数据。复制的开销很大。所有缓存和内存数据都可以重新设计为基于存储的复制节点。
随需复制
这是复制策略的一种变化,其中常规提交是针对当前节点的,而这个节点可以逻辑点触发复制。这个复制也可以是采用同步策略的随需触发器。
对于每个节点处理不同部分数据并在逻辑步骤中整合这些数据的情况,随需复制是很有帮助的。MapReduce
风格的编程模型也可以使用这种策略。
支持故障恢复的单向复制
复制还有另一个变化就是分配一个主节点,然后将所有数据从主节点复制到子节点。在故障恢复过程中,其中一个子节点会成为主节点,而所有复制将从该节点开始。这种复制总是从主节点开始。这种策略可以与文件系统共享策略一起实现高可用性。
文件系统共享
这通常用在复制开销非常大的基于文件系统的资源存储。在这里,文件系统本身会在不同节点之间切换,以实现负载均衡。这不会提供一种简单的可用性方法,但是已经很接近了。关系数据库文件系统可以按这种方法进行处理。
松耦合性和无状态性
无状态性是通过保证调用所需数据的可用性实现的,而且这不依赖于处理请求的主机。松耦合保证了一个调用是可替换的。基于
HTTP 的 REST 或 Web Service 都能够保证这一点。
灵活性
灵活性是通过保证并行性支持和事务支持的正确混合实现的,而且更重要的是,其执行过程是无状态性,因此是可以重复的。每一个执行的状态都是单独持久化的。对象的同一个实例在执行中会有多个线程;每一个线程保存该对象的一个方面。这能够减少池中多个对象的需要。有一些数据库提供商已经实现了一种可共享连接来处理这个特性。这意味着平均
2 到 3 个连接就足够处理 20 至 30 个并发共享读取事务。
事务持续时间越短,它就具有更高的灵活性。将一个长期运行的任务分割成多个可重复的无状态任务能够显著地减少事务大小。
多租户
多租户指的是,通过足够的数据分离,应用程序的一个实例实际上能够服务多个客户。多租户有一些不同的设计问题,但是其中不需要进行代码重构就能够解决的一个重要问题是使用一个还是多个存储来保存不同用户的数据。
用一个存储支持多个用户
这意味着所有客户都共享一个存储资源。这种配置更容易维护,也更容易扩展,因为其中只有一个逻辑分离,因此每一个数据元素都可以使用不同的密钥进行加密。这种模式和分区能够实现数据的逻辑分离,而名称空间则能够实现
XML 数据的逻辑分离。
每一个用户使用独立的存储
每一个客户都有自己的存储。这种策略采用的是物理数据分离方法。这种模型适合那些包含敏感数据的应用程序。这种分隔的存储应该使用一种路由服务来访问,以便将复杂性从编程逻辑剥离。
安全性
分布式存储和多租户会带来额外的安全性需求。这种安全性策略需要解决存储、消息和传输等方面的安全性。此外,混合云或虚拟私有云实现都要求使用跨域的单点登录方法,因此联合机制也会在这里发挥重要作用。
额外的安全性需求是与应用程序相关的云特征的一种分支,因此它可以在不影响其余功能和代码的前提下实现。
结束语
本文概括的提出了一些设计策略和模式,它们可以帮助您在容器服务中实现云特征,以及帮助您将应用程序移植到云上。云资源模式和云任务模式的设计是为了实现重用,所以我们并不要求您选择这种策略。
我们还介绍了云应用程序的特征,以及 Java EE 容器和应用程序的相应特征。我们将托管资源和托管任务模式转变成云资源和云任务模式,以便向您介绍如何将容器服务扩展为云应用程序使用的服务。
此外,我们还介绍了将 JEE 容器整合到云应用程序中对云应用程序设计策略的影响。
最后,我们想要指出的是,JEE Connector Architecture
(JCA) 是一种实现托管资源和托管任务模式扩展的方法之一。JEE Connector Architecture
提供了定义资源工作、生命周期、连接和事务管理的框架,以及改进安全性架构、入站通信和消息流入的框架。
|