`

JAVA EE集成原理

阅读更多
J2EE集群原理
转载:原文地址:http://blog.csdn.net/hbqyk/archive/2009/04/05/4049765.aspx
什么是集群呢?总的来说,集群包括两个概念:“负载均衡”( load balancing)和“失效备援”( failover
图一:负载均衡
多个客户端同时发出请求,位于前端的负载均衡器根据特定算法,将请求分担给比较空闲的机器,从而实现较高性能和较好的扩展性
 
图二:失效备援
当客户端连续向某个服务器发出请求时,该服务器可能处理到一半就宕机了,失效备援系统能够检测出有问题的服务器,将后续的请求转发至其他可用的机器,从而实现容错功能
 
那么,哪些对象可以被集群呢,答案是:“可以被部署在分布式拓扑的组件
因此,负载均衡和失效备援会发生在哪些 J2EE代码中呢?“仅当你调用分布式对象的方法时

 

图四:分布式对象
客户端和目标服务器不在一个 JVM上,他们之间通过标准的网络协议进行通讯,这也就给集群提供了用武之地,实现集群效果的设备可以放在边界上对通讯做一些处理
J2EE的分布式技术包括: JSP,JDBC,EJB,JNDI,WEB SERVICE等等
 
网络层的集群实现
这是最常见最基本的 J2EE集群功能,网络层集群技术包括:网络负载均衡和 HTTP SESSION的失效备援
图五:网络负载均衡
 
负载均衡器可以是一个硬件设备,比如 F5 Load Balancer,也可以是另外一台服务器加一个负载均衡的插件,甚至一个 Linux的嵌入式设备都能胜任。通常,负载均衡包括以下几个特点:
实现负载均衡算法
常用的算法有: Round-Robin, Random Weight Based,算法的最终目标是尽量使每台服务器的负载达到平衡,但以上算法只是根据每台服务器接收的请求来进行均衡,因此都不能完全达到理想化的目标。有些复杂的算法可以在分发请求之前检测机器的性能,从而决定要由哪台机器来处理请求。
健康监测
一旦某台机器宕机了,负载均衡器要能够及时发现情况,并且将请求转交给其他可用的服务器,保证做到“ failover
Session stickiness
即是让一次 session会话的请求都尽量交给一台机器处理,这样省去了服务器之间交换 session数据的开销
 
HTTPSession  Failover
session进行到一半时,如果服务器挂了,我们就要想办法让 session在另外一台机器上继续进行,而不是让用户重新来过。下面图六解释了实现 HTTPSession Failover的原理:每次的 session都会分配一个唯一的 id,这个 id cookies的形式存放在客户端中,负载均衡器通过 id分辨请求是属于哪个 session的。在第四步中,服务器 A以某种定义好的方式,定期将 session数据保存起来,一旦出问题,负载均衡器会自动通知另一台服务器 B,让它取出保存的数据,接 A的班

图六
 
要实现以上基本功能,首先要支持以下特性:
全局session id
每个jvm内部都会为每次session维护一个唯一的id,但多个jvm之间的session id会不会重复就很难说了,所以负载均衡器要能够协调各个jvm,使每个session id都能全局唯一。
如何备份session
这个跟具体厂商有关,后面会讲到
备份的频度和粒度
这个事关负载均衡的性能,因为备份数据的过程直接占用cpu、网络和IO性能
 
 
数据库方式备份

这是最简单的实现方式,数据库还能在整个系统都当掉时依旧保存好 session 数据,可靠性高,几乎所有 J2EE 实现都提供了这种方式,当然,你的 session 数据必须是可序列化的。但是,这种方式一般推荐不要在 session 中存放过大过多的数据,因为数据库的事务过程相当费资源,但这样也大大限制了它的使用范围,毕竟我们有时必须要在 session 中存放一些大对象

 

内存拷贝方式

 

这种方式好处很多,首先它省去了数据库连接和事务的开销,其次由于备份的数据已经放在内存中了,也就省去了从数据库恢复的过程
 
“JavaGroup”是当前tomcat和jboss集群方案的通讯层协议,本质上是一个可靠的组间通讯和管 理的toolkit,它的核心功能在于“ Group membership protocols” 和“message multicast”,用在集群上非常适合,关于JavaGroup的更多内容,请参考 http://www.jgroups.org/javagroupsnew/docs/index.html
 
Tomcat的实现:多服务器之间互相拷贝内存

虽然实现起来容易,但这种方法的弊端也显而易见,当节点增加时,拷贝量就要成倍增长,性能有时还不如不集群

 

Weblogic, Jboss WebSphere 的实现:双服务器拷贝

 

 

 

虽然这种方法的性能和扩展性都很好,但也有不少弊端

l  负载均衡器的复杂度加大,因为要记住每个服务器的备份者是谁

l  除了处理请求外,每个服务器还得自己维护备份开销

l  平时大量的内存都被用于备份数据,会增加 jvm 的垃圾收集频率,间接影响性能

l  一旦某个服务器长时间挂掉,那么另一台服务器的负荷就会翻倍,可能也被一起拖垮

 

为了克服以上缺点,各个厂商都有自己的不同解决方案

 

 

IBM 的方案:中央服务器

 

 

很像是之前的数据库方式吧,只是把数据库换成了一台专门备份的服务器,综合了数据库和内存方式的优点。

l  将备份和请求处理分开,增强了系统的鲁棒性

l  所有的备份数据都在专门的服务器上,节省了其他服务器的内存

l  所有服务器都能存取备份机器上的数据,任何服务器宕机了,负载都能平滑的分配到剩余所有服务器上,而不至于加重某台机器的负担

l  比起数据库连接,备份服务器使用的 socket 连接更加轻量级

 

比起直接的双服务器互拷内存,这种方式效率还是比较低的,因为还要有个恢复的过程,而且在管理上也增加了系统的复杂度。此外,备份服务器本身也很有可能成为瓶颈。

 

Sun 的实现:专用数据库

 

 

表面上就是数据库的方式,但实际上, Sun JES 应用服务器使用的称为“ HADB ”的数据库是专门为 session 的备份做了优化的,其大部分数据都是直接存放在内存中


Session 备份的性能考虑

集群中每台服务器都有多个 web 应用,每个应用又同时有数以千记的用户 session ,这些 session 的备份和恢复都会耗费大量资源。更恐怖的是, session 一直在变,比如失效了,比如增加或修改某个属性了,等等。所以如何备份 session 是考验系统架构水平的

 

何时备份?

不管是用数据库还是内存方式,下面两点都是比较常见的考虑

l  web 请求,即每次请求都进行备份更新,这样可以保证备份的数据是最新的

l  固定时间备份,虽然不能保证备份的 session 是最新的,但却可以提高性能

 

备份粒度

l  全部备份,最保险也是最慢的方法

l  备份修改过的 session 。通常的做法是检测 ”HTTPSession.setAttribute()” “HTTPSession.removeAttribute()” 的调用,当然你要保证 session 的状态只能由这两个方法更改,尽管这不是 J2EE 规范的要求。

l  备份修改过的 session 的属性,最节省性能的做法。但是有一点很重要:防止交叉引用。如下图, session 中包含 school 对象,指向一个 student 对象。当 school 对象某个属性改变后,被备份到 AS2 中,它此时引用的是旧的 student 对象。接着 student 对象被单独改变了,也进行了备份,但是 school 中仍然引用旧的 student 。因此这种方法对 web 容器的设计要求很高,尽管它的性能是最好的。

 

图十三: session 复制中的交叉引用

 

其他 失效备援的实现

以上不论是数据库还是内存复制,归根结底都要使用 Java 的序列化机制,这给 web 容器的性能造成了不小的影响,因此有些应用服务器使用别的方式进行 session 备份

 

JRun with Jini

JRun 4 使用 jini 实现集群, jini 的详细介绍请参考 http://java.sun.com/products/jini/2_0index.html

 

Tangosol with Distributed Cache

Tangosol Coherence™ 提供了一个分布式数据管理平台,可以嵌入到大部分 J2EE 系统中,此外还提供一个分布式缓存系统,能够在多台 jvm 上有效的共享缓存,详情请参考  http://www.tangosol.com/

 

JNDI 集群

Jndi 集群对于 EJB 也是非常重要的,因为几乎所有的 EJB 都是从 JNDI 调用开始的

 

共享全局 JNDI

Weblogic JBOSS 都使用一个全局的、共享的、分布在整个集群系统的 JNDI 树,对象被绑定到全局上下文,使用 ip 多播方式拷贝 JNDI 数据

 

图十四:全局共享 JNDI

 

集群中的每个节点都有自己的命名服务器,并且自动保存其他所有节点的 JNDI 数据,因此这种结构具有高度可靠性

实际中,集群 JNDI 树主要有两个用途:一是用于部署,你只需要将某个 EJB 部署到一台服务器上,系统会自动将其拷贝到其他节点。二是在运行中你可以用 JNDI 存取自己的对象,这些自定义对象同样会被自动拷贝到其他节点。

 

独立的 JNDI

Sun JES, IBM Websphere 和其他厂商使用的是独立的 JNDI 树,各个节点拥有自己独立的 JNDI ,而不会关心其他节点的 JNDI 。但这并不意味着它们不能实现集群,关键是每台服务器上的配置要相同,应用也要相同,这样的话通过代理 agent 就能实现高性能的集群了

Sun JES IBM Websphere 都在每个节点处安装了一个 agent ,由 console 负责协调各个 agent

但这种方式不支持动态绑定运行时生成的对象,设计者的理由是: JNDI 本身就是作为管理外部资源的中间层,运行时对象绑定不在 JNDI 的职责范围内,如果真的有这种需要,可以使用 LDAP 或者具有 HA 功能的数据库。 Sun IBM 都有自己的 LDAP 实现

 

中央型 JNDI

少数厂商采用中央型的 JNDI ,所有节点都去一个某个指定的 JNDI 服务器上获取资源,当然这对于客户端来说是透明的。不过这种方式会大大增加安装和管理的复杂性,因此被大部分厂商放弃

 

怎样开始连接 JNDI

使用 JNDI ,你必须知道提供 JNDI 服务的域名或 IP 以及端口,在全局和独立型 JNDI 树中,都存在着多个 JNDI 服务器,客户端要连接哪一个呢,负载均衡和失效备援又是如何实现的呢?

技术上来说,可以在客户端和 JNDI 服务器之间放一个硬件或软件实现的负载均衡器,来实现上述要求,不过大部分厂商都有更加简单的方法:

l  SUN JES JBOSS 能够令“ java.naming.provider.url ”这一 JNDI 属性支持用逗号分隔多个地址,例如,“ java.naming.provider.url=server1:1100,server2:1100,server3:1100,server4:1100 ”,客户端会逐个搜索,直到找到一个可用的为止

l  JBOSS 还支持自动找寻功能,即令“ java.naming.provider.url ”属性为空,客户端会自动以网络多播的方式寻找一个 JNDI 服务器作为查询的起始点

 

 

EJB 集群原理

EJB 衍生自分布式计算技术,服务器组件或富客户端都能够以标准协议( RMI/IIOP )调用远程的 EJB ,并且 RMI/IIOP 技术能够屏蔽底层网络,使得 EJB 的调用对客户透明化

图: EJB 调用原理

如图,客户端不是直接和 EJB 打交道,而是通过 stub 来代理。 Stub 负责利用 RMI 找到远程的 EJB 并进行调用。 EJB 的调用过程分为下面三步( EJB2.0

l  JNDI 中查找 EJBHOME stub

l  利用 home stub 创建一个 EJB Object stub

l  利用 EJB Object stub 调用 EJB 的方法

 

JNDI 查找时,可以利用上文说到的方法进行负载均衡;各厂商也会有自己专门的技术对 stub 的使用进行负载均衡,一般有以下三种方式:

 

Smart stub

我们知道, stub 可以通过 JNDI 来获得和创建,甚至可以直接下载相应的 class 文件来在运行时动态生成,而无须在客户端本地的 classpath 中声明

 

图十七: smart stub

 

如图十七, Weblogic JBOSS 通过在 stub 的代码中嵌入特殊的代码来实现集群,这个 stub 的确相当 smart ,它包含了所有能够访问的集群服务器节点、内置了专门的集群算法来决定把请求发给何处,甚至当集群的拓扑有变时(比如增加了节点),能动态改变自身来适应新的结构,无须手工干预

 

Smart stub 有以下几个好处:

l  节省大量服务器资源

l  由于负载均衡是由客户端处理,因此可以防止在服务器端放置负载均衡器而可能导致的单点失败

l  Stub 可以动态下载安装,意味着无须手工维护

 

IIOP Runtime Library

Sun JES 采用另一种方法,它直接修改客户端的 IIOP 运行时库

 

图十八: IIOP Runtime

 

如图十八, sun 直接把负载均衡逻辑转移到了 IIOP 库中,从而使 stub 能够保持“小而轻”,同时由于 IIOP 是底层库,能够更加有效地获取和使用 JVM 提供的资源。但正是由于底层库有所不同,使得 JES 与其他 J2EE 服务器打交道时可能会出现一些问题

 

 

Interceptor Proxy

IBM Websphere 使用 Location Service Daemon (LSD) 作为一个拦截器代理来实现 EJB 集群

 

 

 

Figure 19: Interceptor Proxy

 

使用这种机制, stub 中包含至 LSD 的路由信息,而不是直接去找服务器节点,这样 LSD 就能获得所有请求并进行负载均衡了,不过这样会大大增加管理和维护的成本

 

 

EJB 的集群支持

调用 EJB 方法的过程中我们要和两个 stub 打交道,一个是 home stub ,另一个是 object stub ,因此可以在两个层面上实现负载均衡和失效备援

 

EJBHOME STUB 的集群实现

由于 EJBHOME STUB 本身不包括任何客户端信息,无论从哪个服务器上获得的 EJBHOME STUB 都是一样的,因此当客户端调用 EJBHOME STUB create 等方法时,就能利用一些负载均衡的算法选择合适的服务器节点

 

EJBOBJECT STUB 的集群实现

EJBOBJECT STUB 包含业务接口,而且其本身也能够含有集群节点的信息,但也不是所有的方法调用都能够进行负载均衡式的路由,得看 EJB 的类型是什么

 

l  无状态会话 bean 最容易实现负载均衡了,因为它本身不包含特定的客户信息

l  有状态会话 bean 略有不同,因为它本身包含客户端的会话信息,因此有状态 bean 的集群实现本质上和 HTTP session 无异,一般情况下客户端的 stub 都是一直与某个节点上的 EJB 组件打交道的,除非中途出问题了才会将请求转发到备用的节点上

l  实体 bean 本质上也是无状态的。表面上看可以采用和无状态会话 bean 一样的方式集群,但实际上很少厂商会对实体 bean 做集群。因为实体 bean 一般都是被其他会话 bean 调用的,因此通常都使用本地接口通讯,实在没有集群的必要

 

 

JMS 和数据库连接的集群

目前一些数据库产品已经可以集群了,你可以部署成多份,每个节点之间可以同步。但是 JDBC 本质上是有状态连接,和底层的 socket 紧密绑定。当某个 JDBC 连接突然中断了,与之相关的对象也就费了,因此很难对 JDBC 集群。 Weblogic 使用一种 JDBC multipool ,可以在 JDBC 断开情况下,方便地进行重新连接

 

JMS 的负载均衡和失效备援只在 JMS broker 上有实现,很少有厂商在 JMS destination 的消息上实现了负载均衡

 

 

J2EE 集群的困惑

失效备援能够防止所有错误吗?——错!

JBOSS 的文档花了整整一章的内容来提醒你:“你真的需要 HTTP SESSION 复制吗”,有时候不用失效备援也能以经济的方式获得高可靠性。更何况,失效备援并没有你想象中的那么可靠

 

你也许认为失效备援能够在节点宕机时保护你的 session 数据,但你得清楚,这种保障是有条件的

 

回想一下作者在定义“失效备援”时,前提条件是“在两个方法调用之间”!也就是说只有在第一个方法成功返回之后、第二个方法调用开始之前,失效备援才能起作用

 

假设某个方法处理到一半时服务器不幸挂掉了,客户端一般只能收到错误消息。除非你这个方法恰好是“ idempotent ”的(即多次调用的结果都能保持一致,不会对环境造成任何改变,比如 getter 方法),那么有些聪明的负载均衡器会尝试找其他节点去调用这个方法

 

所以说“ idempotent ”这个概念非常重要,因为客户端压根不知道是在什么地方失败的,而如果这个方法不是 idempotent ,那么系统就可能处于一种不一致的状态,很危险

 

你也许认为事务性的方法就是 idempotent 的,毕竟事务可以回滚。但其实事务远远不能涵盖整个远程调用的范围,比如服务器成功执行某事务性方法后,返回结果的过程中网络崩溃了呢?

 

在比较严格的系统设计中,你根本不能令所有方法都 idempotent ,你能做的就是利用 failover ,尽可能减少错误而不是彻底杜绝错误。以某个网上商城为例:每台服务器都同时处理 100 个用户请求,当某台服务器崩溃时,如果没有失效备援,那么你会得罪一百个用户;而如果有失效备援,可能只有不到 20 个用户会发飙。你自己要权衡:

l  是得罪一百个客户还是得罪 20 个客户?

l  有没有失效备援的服务器的价格差别

 

 

独立的应用程序可以无缝地迁移到分布式平台上?——错!

这只是某些厂商的广告而已,不可轻信。如果是大型系统,那么设计之初就应该全盘考虑集群可能造成的影响

HTTP   SESSION

正如前文所述, HTTP SESSION 的集群会受到你使用的服务器的诸多限制。首先是可序列化的要求,在很多 MVC 架构中, session 被用来存储一些不可序列化的对象(比如 servlet context );其次,序列化、特别是数据库方式的序列化非常耗费资源,因此要集群就尽量不要用 session 存储大对象。如果是内存拷贝的方式,那么就要考虑内存的限制和交叉引用的问题(交叉引用请参考前文);最后,你在集群环境下改变 session 的属性时,必须使用“ setAttribute ”方法,而在单机环境下却没这个限制。这么做的主要原因是让你的应用服务器能够检测到属性改变,及时地备份已修改的属性

 

缓存

大部分流行的应用服务器都会使用缓存来提升性能,但缓存一般都是为单机环境设计的。集群环境下如果使用缓存,那么缓存之间的拷贝花费的性能将比缓存带来的好处还多,适得其反

 

静态变量

有一种很流行的 J2EE 设计模式“ singleton (单体)”,是使用静态变量的,这在单机环境下适用,但到了集群就不行了,道理很简单,每个 JVM 都有自己的静态对象,“单体”也就失去意义了。比如要统计在线用户数时,经常用一个静态变量来存储,但是在集群环境下这种方法显然失去作用。要使用静态对象,最好把它放到一个数据库中,才能实现全局的“单体”

 

外部资源

尽管 J2EE 规范并不推荐,但外部 IO 操作还是有用的,比如用来存放用户上传的文件。在集群中,服务器是不能通过另一台服务器把本地文件直接存放到别的机器上的,那么还是要依靠数据库来统一存放文件,或者你可以使用 SAN 这种集中式文件仓库

 

专有服务

有些专有服务是只限于单机环境的,比如定时器服务( timer );再比如某些事件触发类型的服务,如初始化服务,邮件提醒服务也属于此列。这些服务一般针对一个特定条件只发生一次,拿去集群没什么意义。 JBOSS 的“ clustered singleton facility ”就是用来保证所有服务器运行且只运行一次某种服务

 

 

分布式系统比并列式系统更灵活?——未必

尽管 EJB 生来就是为了分布式、解耦合,但很多框架认为把 EJB 层和 web 层放在一起也未尝不是好事,或许更好

 

 

20 :分布式架构

 

如图 20 ,负载均衡器先将请求分发到适当服务器的 web 层, web 层进一步判断调用何处的 EJB ,这等于是做了两次的负载均衡和失效备援。很多人认为这种设计并不好:

l  首先,第二次的转发根本没有必要,每个服务器都有自己的 web ejb 层,比起只调用内部的 ejb web 层调用其他 ejb 层没有任何的好处

l  第二次的失效备援也是没有必要的,大部分厂商都把 web 容器和 ejb 容器实现为在同一个 jvm 上跑,那样一旦 web 容器挂了, ejb 容器很难独善其身

l  损失性能,这个不必解释了,大量的服务器之间的调用对性能肯定有影响。

 

实际上,大部分厂商都让 web 容器优先选择同一个服务器上的 ejb 容器,这种方式称作“并

分享到:
评论

相关推荐

    javaee-nosql:通过 CDI 等将 NoSQL 数据库集成到 Java EE 中

    NoSQL 数据库的 Java EE 7 / CDI 集成 该项目旨在简化 Java EE 项目中某些 NoSQL 数据库的使用。 通过 CDI,它有助于让本地 API 对象与这些数据库进行交互。 目前仅提供 MongoDB 集成。 我们计划在未来添加新的...

    JAVA程序开发大全---上半部分

    第15章 Java EE中EJB的开发 256 15.1 EJB概述 256 15.2 WebLogic服务器的安装与配置 257 15.2.1 WebLogic服务器的安装 257 15.2.2 WebLogic服务器的配置 258 15.2.3 MyEclipse中集成WebLogic服务器 260 15.3 使用...

    JavaEE开发的颠覆者+Spring+Boot实战++完整版

    涵盖使用Spring Boot 进行Java EE 开发的绝大数应用场景,包含:Web 开发、数据访问、安全控制、批处理、异步消息、系统集成、开发与部署、应用监控、分布式系统开发等。, 当你学完《JavaEE开发的颠覆者: Spring ...

    struts2.0_Ajax

    <br>实现原理 基于不重新发明轮子的原则,Struts 2并没有开发新的AJAX框架,而是使用时下Java EE平台中比较流行的AJAX框架——Dojo和DWR。 <br>最近在Musachy Barroso等同志的无私奉献下,开发了Struts 2...

    JavaEE开发的颠覆者SpringBoot实战[完整版].part2

    涵盖使用Spring Boot 进行Java EE 开发的绝大数应用场景,包含:Web 开发、数据访问、安全控制、批处理、异步消息、系统集成、开发与部署、应用监控、分布式系统开发等。 第一部分 点睛Spring 4.x 第1 章 Spring ...

    JavaEE开发的颠覆者SpringBoot实战[完整版].part3

    涵盖使用Spring Boot 进行Java EE 开发的绝大数应用场景,包含:Web 开发、数据访问、安全控制、批处理、异步消息、系统集成、开发与部署、应用监控、分布式系统开发等。 第一部分 点睛Spring 4.x 第1 章 Spring ...

    JBoss Seam 工作原理、seam和hibernate的范例、RESTFul的seam、seam-gen起步、seam组件、配置组件、jsf,jboss、标签、PDF、注解等等

    Java EE 框架..................................................................................................................................................................................1 ...

    JavaEE开发的颠覆者SpringBoot实战[完整版].part1

    涵盖使用Spring Boot 进行Java EE 开发的绝大数应用场景,包含:Web 开发、数据访问、安全控制、批处理、异步消息、系统集成、开发与部署、应用监控、分布式系统开发等。 第一部分 点睛Spring 4.x 第1 章 Spring ...

    网络架构师148讲视频课程

    java架构师148讲视频教程 │ ├─1-148视频教程 │ 第01节:整体课程概览.flv │ 第02节:分模块、分工程管理.avi │ 第03节:多模块多Web应用合并War包.avi │ 第04节:Git基本原理和安装配置使用.avi │ 第05节...

    spring security 参考手册中文版

    28.2.2 Java EE容器认证 220 29. LDAP认证 220 29.1概述 220 29.2在Spring Security中使用LDAP 221 29.3配置LDAP服务器 221 29.3.1使用嵌入式测试服务器 222 29.3.2使用绑定认证 222 29.3.3加载权限 223 29.4实现类 ...

    spring boot 项目代码,直接启动本人编写的,里面包含PPT下载地址

    VIII ∣ Java EE 开发的颠覆者:Spring Boot 实战 3.7 测试 .... .... ............. 66 第二部分 点睛Spring MVC 4.x 第4 章 Spring MVC 基础 .... .......................... 72 第三部分 实战Spring Boot 第5 章...

    JavaEE开发的颠覆者 Spring Boot实战,多个地址免费下载,

    VIII ∣ Java EE 开发的颠覆者:Spring Boot 实战 3.7 测试 .... .... ............. 66 第二部分 点睛Spring MVC 4.x 第4 章 Spring MVC 基础 .... .......................... 72 第三部分 实战Spring Boot 第5 章...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    我们掌握了数据库及其应用技术、数据库原理、计算机网络技术等课程,对数据库的设计、应用、维护及局域网的组成有了深刻的认识与一定的动手实践能力,考取了信息处理、程序设计、数据库技术等国家IT认证。...

Global site tag (gtag.js) - Google Analytics