我们有几个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重新协商它的初始连接?
答案 0 :(得分:4)
也许。 JNDI是一种对象缓存。因此,如果您在同一个VM中多次询问相同的名称,则总会得到相同的结果。这是正确的行为,但你不喜欢它。
解决方案是在JNDI中注册工厂而不是实例本身。这样,工厂可以从JNDI获取用于创建连接的信息,但每次调用它时返回一个新实例(或从内部池返回一个实例)。
JDBC使用相同的方法。不是将JDBC连接添加到JNDI缓存,而是添加DataSource
- 这是JDBC java.sql.Connection
实例的工厂。
答案 1 :(得分:1)
您忘了告诉我们硬件负载均衡器实际上是在“平衡”。
由于我无法想象硬件负载均衡器知道专有的JBoss远程处理协议,因此在您的情况下,很可能只是对JNDI查找进行负载均衡。这意味着您从同一个InitialContext获取的所有客户端存根最终将转到同一个物理服务器。
如果硬件负载均衡器应该循环每个请求,则必须通过负载均衡器支持的协议进行远程调用,例如: HTTP。如果你正确配置它,JBoss应该支持这个。
你当然可以设置一个“真正的”JBoss集群,让JBoss代码处理负载平衡和故障转移,但是JBoss集群代码是如此错误和脆弱,你很可能会破坏其他东西这种方法。