JNDI 集群的实现

Java EE 规范要求 Java EE 容易需要提供对 JNDI 规范的实现。在 Java EE 应用中, JNDI 的主要角色就是提供了一个中间层,资源可通过较为透明的方式获得。这使 Java EE 组件提高了重用度。

具有完整功能的集群 JNDI 是 Java EE 集群的重要内容,因为几乎每个 EJB 组件都从查找 (lookup) 其 JNDI 树的 home 接口开始。各个厂商实现 JNDI 集群的方法不同,主要是根据其集群的结构而定。


 


全局共享 JNDI

WebLogic 和 JBoss 都使用集群范围全局共享的 JNDI 上下文以便客户端能查找并绑定对象。绑定到全局 JNDI 上下文的内容将被基于 IP 的多播技术复制到整个集群中,这样当一个服务器实例宕机时,还能保证绑定对象可获得。


如上图所示,全局共享的 JNDI 树实际上包含了每个节点上所有本地的 JNDI 的集合。集群中的每个节点都有其自己的 JNDI 命名服务器,它将所有的信息复制到集群中其它所有的命名服务器中。这样,每个命名服务器的树中都有其他命名服务器的对象拷贝。这样的冗余结构使全局 JNDI 树实现了高可用。


实际上,集群的 JNDI 树有两个用途。管理员可以用它来进行部署任务。在一台服务器上部署了 EJB 模块或配置了 JDBC/JMS 服务后,所有的 JNDI 树都会被复制到其它服务器实例。在应用运行期间,程序用 JNDI 的 API 访问 JNDI 树来存储和检索对象,所以自定义的对象也被全局复制。


 


独立 JNDI

虽然 JBoss 和 WebLogic 采用了全局共享 JNDI ,但 SUN JES 、 IBM WebsPhere 和其他一些服务器采用了独立 JNDI 树技术。在独立 JNDI 树集群环境下的成员服务器不知道或者并不关心集群中的其他服务器。那这样岂不是意味着不对 JNDI 进行集群?因为几乎每个 EJB 访问都从 JNDI 树中查找其 home 接口开始,所以如果不对 JNDI 树进行集群就会丧失集群的功能。

实际上,独立 JNDI 树依然能实现高可用,只要 Java EE 的应用都是同构的。我们将其称为同构集群,因为所有的实例配置相同,部署了同样的应用。在这样的条件下,一个叫 “ 代理 ” 的特殊管理工具可用来实现高可用,如下图:


SUN JES 和 IBM WebSphere 都将代理安装在集群的每个实例上。当部署 EJB 模块并绑定其他 JNDI 服务时,管理终端通过对所有代理发送命令来达到与全局共享 JNDI 树同样的效果。


但是独立 JNDI 解决方案将不支持复制由运行的应用绑定和检索的判定对象。原因如下:在 Java EE 应用中, JNDI 扮演的角色是对管理外部资源提供中间层,而不是运行时数据的存储。如果有需要的话,各自的 LDAP 服务器或有 HA 功能的数据库能够实现。 Sun 和 IBM 都有它们的 LDAP 服务器产品,而且都已经随着集群特性分发。


 


 


集中式 JNDI

一些 Java EE 产品使用集中式的 JNDI 树,命名服务器驻留在一台服务器上,所有服务器实例将 EJB 组件和其他管理对象注册至命名服务器中。 

命名服务器本身实现了高可用,对客户端透明。所有客户端通过单独的命名服务器查找 EJB 组件。这种结构加大了安装和管理的复杂度,所以不为大多数厂商采用。


 


JNDI 服务器的初始访问

当客户端访问 JNDI 服务器时,需要知道 hostname/IP 地址和远程 JNDI 服务器端口号。在全局共享与独立 JNDI 树解决方案中,均有多个 JNDI 服务器。那么客户端会先连接哪台 JNDI 服务器呢?如何实现负载均衡和失败转移呢?

通常,软件或硬件负载均衡器可在远程客户端和所有的 JNDI 服务器之间执行负载均衡和失败转移的任务。但是几乎没有厂商采用这样的办法,而使用一些简单的解决方案。


  • Sun JES和JBoss通过“java.naming.provider.url”让JNDI设置接收由逗号分离的URL列表来实现集群。例如,java.naming.provider.url=server1:1100,server2:1100,server3:1100,server4:1100

客户端将尝试逐个与列表中的每台服务器,一旦连接上之后就停止尝试。


  • JBoss也实现了自动恢复的功能。当属性字符串“java.naming.providing.url”为空时,客户端将尝试通过网络多播调用恢复引导JNDI服务器。