0

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

我想正在发生的事情是远程客户端创建其初始上下文,进行查找,并在一段时间(大约 15 秒)内保持与 JNDI 服务器的连接,以节省重新创建连接的开销。这意味着第 2 个和第 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 重新协商它的初始连接?

4

2 回答 2

4

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

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

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

于 2012-05-08T16:34:20.937 回答
1

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

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

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

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

于 2012-05-08T16:32:21.547 回答