JNDI查找是否保持连接打开 - 这就是为什么我的负载平衡被打破了?

时间:2012-05-08 16:09:52

标签: java jboss jndi

我们有几个JBoss服务器使用循环策略坐在硬件负载均衡器后面。我们所有的(JBoss)客户端都习惯于偶尔连接,这些客户端将被正确地进行负载平衡。但是,新客户端每分钟发送约100个查询,这些查询都将被定向到同一服务器。

我认为发生的事情是远程客户端创建其初始上下文,执行查找,并维护与JNDI服务器的连接一段时间(大约15秒),以节省重新创建连接的开销。这意味着第二个和第N个请求转到同一个服务器。我们使用以下代码证明了这一点(使用JBoss库的Jython):

def __call__(self):
    p = Properties()
    p[Context.PROVIDER_URL] = "jnp://my.load.balancer:1099"
    p[Context.INITIAL_CONTEXT_FACTORY] = JndiLoginInitialContextFactory.name
    p[Context.SECURITY_PRINCIPAL] = <redacted>
    p[Context.SECURITY_CREDENTIALS] = <redacted>

    ctx = InitialContext(p)
    home = ctx.lookup("ejb/ServerNameService")

    ejbQuery = home.create()


    print "Server name: %s", (ejbQuery.getServerName())

    ctx.close()

现在,如果我在同一个JVM(多个线程)中调用100次,那么我总是得到相同的服务器。如果我用新的JVM调用100次,那我就得到了混合物。

有没有办法在不使用群集技术的情况下强制JNDI重新协商它的初始连接?

2 个答案:

答案 0 :(得分:4)

也许。 JNDI是一种对象缓存。因此,如果您在同一个VM中多次询问相同的名称,则总会得到相同的结果。这是正确的行为,但你不喜欢它。

解决方案是在JNDI中注册工厂而不是实例本身。这样,工厂可以从JNDI获取用于创建连接的信息,但每次调用它时返回一个新实例(或从内部池返回一个实例)。

JDBC使用相同的方法。不是将JDBC连接添加到JNDI缓存,而是添加DataSource - 这是JDBC java.sql.Connection实例的工厂。

答案 1 :(得分:1)

您忘了告诉我们硬件负载均衡器实际上是在“平衡”。

由于我无法想象硬件负载均衡器知道专有的JBoss远程处理协议,因此在您的情况下,很可能只是对JNDI查找进行负载均衡。这意味着您从同一个InitialContext获取的所有客户端存根最终将转到同一个物理服务器。

如果硬件负载均衡器应该循环每个请求,则必须通过负载均衡器支持的协议进行远程调用,例如: HTTP。如果你正确配置它,JBoss应该支持这个。

你当然可以设置一个“真正的”JBoss集群,让JBoss代码处理负载平衡和故障转移,但是JBoss集群代码是如此错误和脆弱,你很可能会破坏其他东西这种方法。