分享到
云计算环境下的JVM虚拟化特性初探
 

作者:李三红,发布于2011-11-11

 

简介: 云计算的概念是 Google 提出的。从用户的角度理解,云计算强调的是 IT 服务的交付和使用模式。在云计算环境下,这些 IT 服务通过网络 ( 通常是 internet) 以按需 (On Demand)、易扩展 (Extensibility) 的方式获得。按照云计算平台提供的服务种类,划分出了云计算平台的三层架构,即:Infrastructure as a Service(IaaS),Platform as a Service (PaaS), 以及 Software as a Service (SaaS)。 IaaS 的代表如亚马逊的 Amazon Web services(AWS), PaaS 的代表如 Google App Engine(GAE), 以及 SaaS 的代表如 IBM Lotus Live。本文将在介绍这些典型的云计算环境基础上,围绕着云计算的两个重要的主题:多租户和资源管理,展开我们的讨论,讨论的重点涉及将来的 Java 平台会为云计算提供什么样的基础支持。

目前对于到底什么是云计算,什么样的平台属于云计算平台,等等围绕云计算相关的问题,不同的软硬件厂商对此都有自己不同的理解,有着自己不同的定义。他们所提供的云计算平台也是千差万别。谈到云计算,大家总会联想到这些方面的东西:比如说高伸缩性 (High Scalability) ,成本节约 (Cost Saving), 按需使用 (Use On Demand), 等等。我们姑且不论云计算带来的这些纷繁多样的种种概念,如果仅仅从技术角度来讲,云计算本身并不是一个什么新奇的概念,可以理解为一种新型的 IT 服务交付使用方式,而传统的技术比如虚拟化、集群、网格等等都可以用来作为云计算平台的支撑技术。更详尽的有关云计算概念的介绍,请参考 Wikipedia 描述。

云计算平台架构

一般来讲,云计算平台被解释为如下的架构,图 1 所示。

图 1. 云计算平台架构 .

最下的一层是 IaaS,提供 CPU,网络,存储等基础硬件的云服务。在 IaaS 这一层,著名的云计算产品有 Amazon 的 S3(Simple Storage Service), 提供给用户云存储服务。

再上一层是 PaaS,提供类似于操作系统层次的服务与管理 ,比如 Google GAE,你可以把自己写 Java 应用 ( 或者是 Python) 丢在 Google 的 GAE 里运行,GAE 就像一个”云”操作系统,对你而言,不用关心你的程序在那台机器上运行。

最后一层是 SaaS,就是我们所熟悉的软件即服务。事实上 SaaS 的概念的出现要早于云计算,只不过云计算的出现让原来的 SaaS 找到了自己更加合理的位置。本质上,SaaS 的理念是:有别的传统的许可证付费方式 ( 比如购买 Windows Office),SaaS 强调按需使用付费。SaaS 著名的产品很多,比如 IBM 的 LotusLive,Salesforce.com 等。

多租户 (Multi-Tenant)

多租户的概念是伴随云计算而出现的,在这里有必要介绍一下,我们后面的讨论很大量涉及这个概念。

多租户是一个软件架构方面的概念,指的是一个软件实例 (Application Instance) 可以供多个组织 (Organization 或者称为 Tenant) 使用。这里可以理解为应用程序的虚拟化,也即:多个租户共同使用同一个软件实例,但是每一个租户在数据集,配置等方面有自己的虚拟划分。实际上,在某种程度上,基于 B/S 架构的应用程序比如 J2EE 应用本身就是多租户性质的,因为大家都是使用浏览器来访问同一份部署在 Application Server 上的软件实例。这里之所以说是”某种程度”,是因为对于我们谈到的数据集按租户虚拟划分,现实的 J2EE 应用并没有支持。这个东西本文在后面会详细谈到。

接下来的章节,将以 S3 和 GAE 为例子,围绕本文讨论的主题:多租户和资源管理, 简单介绍一下在这些典型的云计算平台上,多租户是怎么样进行部署的,以及在这些平台上的资源是如何被管理的。

多租户及资源管理在 S3 的支持

Amazon S3 向用户提供的在线的 (基于 Internet) 云存储服务。用户可以在 S3 上存储任何数据,这些数据可以是私有的亦或是可以被公共访问的。Amazon S3 支持 Web 浏览器或者 BitTorrent 来访问这些数据。一般来讲,用户使用 S3:

作为 Backup server:存储你的私有数据到 S3 上去,这样你就不需要自己购买维护自己的备份磁盘,你只是付费从 Amazon 租赁磁盘空间。

作为 Data host: 存储数据到 S3 上,并且其他人有访问这些数据的权限。这里,你付费的对象不是传统意义上的 ISP,而是 Amazon。

S3 存储涉及两个核心的概念:S3 bucket 和 S3 object。S3 object 是对存在于 Amazon S3 上内容的抽象,其包括两方面的内容:数据和元数据,数据指的是你存储的真正的内容,比如一份 PDF 文档,一个 HTML 文件等。而元数据是对该数据的描述,比如可以用于指定当前存放的内容的 Content-Type 是 text/html。每一个 S3 object 有一个唯一的 Key 来标志。S3 bucket 是存放 S3 object 的容器。如果用个类比的话,S3 bucket 相当于于磁盘上的文件系统,而 S3 Object 则是这个文件系统中的一个文件。

我们用一个简单的例子来看,在 S3 上多租户是怎么做出来的?

假如想利用 S3 存储 example.com web 站点,首先需要创建名为”example.com”的 bucket,然后在这个 bucket 里创建诸如:键值为 “”( 空串 ),”catalog”, “catalog/929339”的 objects,这些 objects 对应的 URL 分别为 : “http://example.com/”,“http://example.com/catalog/”,“http://example.com/catalog/929339”,而 object 的值就是相应的 HTML 页面,元数据 Content-Type 被设置为 text/html(相应于标准的 http 定义)。

如果多租户的角度来看,我们可以把 S3 看作是在线的存储服务器,各个租户可以把自己的信息存储在 S3 上,比如 : 甲租户可以把 http://tenantA.com 网站放在 S3 上,乙租户可以存储的是 http://tenantB.com 网站,各个租户共享 S3 的使用。

除了多租户支持,S3 还有资源的使用管理,计费等功能,如图 2 所示:

图 2. S3 存储价格表

多租户及资源管理在 GAE 上的支持

较之于 IaaS,Google App Engine 提供了更多的系统抽象能力。如果做一个比喻的话,IaaS 相当于你有了一台拥有存储,网络,CPU 等计算资源的计算机,而 PaaS 的 Google App Engine 则是装在这台计算机上的操作系统。设想一下,如果你开发一个传统意义上的 J2EE 应用,你要关心的事情除了应用程序本身之外,还有:要部署在什么样的应用服务器上,使用什么样的数据库,应用的可伸缩性 (Scalability) 等等。而有了 GAE,这些东西你都不需要关心了,你只需要根据 GAE 规范开发 J2EE 应用,然后把它部署在 GAE 云里,GAE 会帮助你管理除了你的应用程序本身的所有事情。

GAE 本身就是多租户的架构,即:来自不同租户的、任何一个符合 GAE 规范 J2EE 都可以部署在 GAE 上。

而且,部署在 GAE 上的应用实例,如果你想把它作为一个 SaaS 应用的话,本身也可以实现多租户,也就是说:当你的一个部署在 GAE 上的 J2EE 应用需要被不同的租户使用时,可以使用 Google 提供的 Namespace API 将其虚拟化为多个应用实例。比如:该 SaaS 应用的不同的租户使用了不同的子域名 (subdomain),tenantA 的子域名是 tenantA.example.com,tenantB 的子域名是 tenantB.example.com,等等,你可以使用下面的代码把不同的租户划归在不同的命名空间里,它们可以在共享同一个 Datastore 实例的基础上按照不同的租户实现相互的隔离。

清单 1. GAE App Multitenancy

// Filter to set the namespace by different subdomain.

public class NamespaceFilter implements javax.servlet.Filter {

     @Override

     public void doFilter(ServletRequest req, ServletResponse      res, FilterChain chain)

     throws IOException, ServletException {

          //Make sure set() is only called if the current namespace           is not already set.

          if (NamespaceManager.get() == null) {

               NamespaceManager.set(req.getServerName());

          }

          //Chain into the next request.

          chain.doFilter(req, res);

     }

     // … remaining Filter methods init() and destroy()

}

值得注意的是,GAE Namespace 使用了 Thread-local storage 的技术。也就是说,你在 Filter 设置的 Namespace Manager,其生存期 ( 或者叫做有效范围 ) 是存在于单个 HTTP Request 生命周期内 ( 即:当前线程服务该请求的期间内 ),而不是租户登录后的整个 Session 周期。

类似于 Amazon S3,GAE 也提供了资源的管理计费功能,如图 3 所示。

图 3. GAE 资源管理

写到这里,总结一下:我们看到,无论是 S3 还是 GAE,都对多租户以及资源管理做了支持。 事实上,不只是 S3 和 GAE,多租户以及资源管理是任何一个云计算平台都必须具备的一个核心特质。

如何我们简单的把 S3 和 GAE 看作是运行在 Java 平台的上的应用程序 ( 底层运行的是 JRE ! ),那么我们可以说:S3 和 GAE 都在Java Application这个层次上对这两个需求做了它们自己的实现。进一步设想,如果我们要求底层的 JRE 本身就能对多租户和资源管理提供支持,那么有理由相信,这些部署在 JRE 上的 Java 应用,利用底层 JRE 的这些支持,应该能更高效、简洁、方便地来做这方面的工作。这也是本文接下来要谈的 Java 平台的两个重要的 JSR:JSR284 和 JSR121 的原因。一个是 Java 平台的资源管理支持,一个是 Java 平台的多租户支持。

早在云计算兴起之前,Sun Lab 就已经开始关注于 Java 平台的资源的共享与管理。比如:如果不借助操作系统的本地支持,我们没办法让一个普通的 Java 应用程序受限于 CPU 的使用,受限于 Disk IO 或者网络带宽的使用等等。当我们在同一台机器上运行多个 JVM 实例时,它们都是独立的用户进程,每个 JVM 的启动都需要实例化自己一份独立的 JDK 类库,其结果是:JVM 启动时间 (Startup),内容 (Memory footprint) 等都消耗在重复的 JVM 初始化上。我们要问的问题是:多个 JVM 可以最大化地共享 JDK 运行时吗 ? 在共享的同时它们能够互不影响吗?这就是 Sun 发起 Barcelona 研究项目,Multi-Tasking Virtual Machine( 即 MVM) 的主要原因。

在云计算大行其道的今天,我们回过头再来审视一下 Barcelona 项目,MVM 所有解决的两个目标:资源的共享与管理,在云计算的环境下显得愈加的重要。正如我们前面所讲的那样,作为云计算环境两个必备的两个特性,多租户和资源管理,前者要求最大化的共享软件实例,后者要求我们在共享的基础上如何对资源的使用进行隔离与控制。这也正和 MVM 的目标不谋而合。由 MVM 源生出了下面的两个 JSR:121 和 284,这也应该是 Java 平台走向虚拟化的所必需的步骤。

JSR284

JSR284 规范 Resource Consumption Management API(RCM) 定义了 Java 平台的资源管理框架。

到目前为止,Java 平台本身对于资源的管理与控制是非常有限的,在很多情况下,需要额外借助操作系统的资源管理能力对 JVM 进程进行管理,这样的管理是非常粗粒度的。尤其是放在云计算的大环境下,这种能力就更显得特别有限。可以设想一下,如果多租户的多个 J2EE 应用同时运行在同一个 JVM 上,资源的控制与管理就变得尤为重要。比如:我们需要防止 DoS 攻击,需要对租户进行 QoS 控制等等,这些目前 Java 平台本身是没法解决的,这也是 JSR284 诞生的重要原因。

通过 JSR284,你可以做什么 ?

可以对资源在 JVM 进程内做更细粒度的,基于线程级别的控制,比如对它们做 QoS 限制;可以对 JVM 内资源的使用消费进行细粒度的 , 基于线程级别的隔离,防止 DoS 攻击等;可以通过 JMX 接口监视资源 ( 比如 CPU 使用率 ) 其使用情况。

JSR284 最早在 2006 年起草,有兴趣的读者,更多的细节可以阅读 JSR284 规范。

另外,JSR284 的引用实现 (RI) 已经作为 JSR 孵化项目在 2011 年一月份开始,读者可以访问 jsr284-ri-tck了解更多的细节。

JSR121

在通常的情况下,我们运行的 Java 程序和 Java 运行时 ( 即所谓的 JRE) 是一一对应的,即:我们运行一个 Java 应用,就会对应起一个 Java 运行时,这包括 JVM,以及 Java 的类库。如图 4 所示,每一个 Java 应用都

如图 4,在 OS 上,每一个 Java 应用都作为一个独立的 OS 进程运行,像一般的 OS 进程一样,它们拥有自己独立的地址空间,互相之间是相互隔离的,一个 Java 应用的运行错误不会影响到另一个的运行。而且每个 Java 应用都可以相互独立的启动与停止。

图 4. 多个 Java 应用使用不同的 JRE

说了这么多的好处,我们再来看看这样传统的 Java 运行模式的缺点,特别是在云计算的环境下:

首先是关于效率的问题。如果我们运行 N 个 Java 程序,那么同时需要 N 个 JRE,在同一个 OS 上,这不但涉及的资源的浪费问题,比如多使用了内存,而且就 Java 程序的启动而言,也是没有效率的。Java 程序本身启动就慢,这个过程需要初始化 JVM,装载所需要的核心类等等,而这些动作实际上对于其它 N-1 个 Java 程序而言都是多余的,如果 N 个 Java 程序能共享同一个 JRE,那么启动速度也会提升。

其次是关于多个 JVM 进程间的通讯问题。一般情况下,如果多个 JVM 之间如果需要共享数据 ( 比如共享某些类等 ),相互协作,是比较困难的,JDK 本身没有对这种计算模式提供更多的支持。

一个 JRE 可以同时运行多个 Java 程序,这个 JSR121 提出的初衷,如图 5 所示:

图 5. 多个 Java 应用共享同一个 JRE.

在 JSR121 中,每个运行的 Java 程序被称作为一个 Isolate,所有的 Isolates 共享同一个 JRE。

Isolate 之间是相互隔离的,它们各自都有自己的生命周期。类似于在操作系统上的 进程有自己的独立地址空间,JVM 上的 Isolate也可以看作有自己独立地址空间,它们彼此不受影响。

尤其在云计算的环境下,Java Isolate 的计算模型更为合适。设想一下,我们可以在同一个应用服务器上部署不同的 Isolates,每一个 Isolate 对应一个租户,这些 Isolates 共享 JRE 而又互相隔离。也许读者会奇怪:在目前的情况下,一个应用服务器也是可以部署多个 J2EE 应用的,这些独立的 J2EE 应用与我们这里讨论的 Isolate 有什么不同?

不同在于:Isolates 在物理上共享同一个 JRE,但运行时逻辑上是相互隔离,彼此不会影响的。一个 Isolate 的错误不会影响整个 JVM 运行。而且,Isolate 虽然共享基本的 JDK 类,但是你不可能直接通过这些基本的系统类在 Isolates 之间共享数据。这个就非常适合在云的环境下应用。

很多时候,不同的租户来自不同的组织,不同的租户的的代码运行在同一个 JVM 进程里,保证它们之间的相互隔离是非常必要的。

小结

本文首先对云计算以及云计算平台 IaaS,PaaS 和 SaaS 做了扼要的介绍,并且以 Aamzon S3 和 Google GAE 为例子,重点介绍了这两个平台在多租户以及资源管理方面的做法,基于这些的应用背景,围绕云环境下的资源管理以及多租户支持这两个主题,对 Java 平台的 JSR284 和 JSR121 做了比较详细的阐述,未来的 Java 平台 ( 也许是 Java8?) 将会实现 JSR284 和 JSR121 来解决这两方面的需求。

 
分享到
 
 
     


专家视角看IT与架构
软件架构设计
面向服务体系架构和业务组件的思考
人人网移动开发架构
架构腐化之谜
谈平台即服务PaaS
更多...   

相关培训课程

云计算
Windows Azure 云计算应用开发

 
 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号