我目前正在努力应对 Wildfly 25 或 26 的 EJB 远程调用。 相同的客户端应用程序可以与 Widfly 10、13、16、20 配合使用,在某种程度上也可以与 Wildfly 25 或 26 配合使用。 当 EJB 调用的返回对象大小超过某个限制时,问题就开始出现,而该限制似乎有时会发生变化。示例:我创建了一个测试 EJB 方法,该方法返回与我作为参数提供的相同的字符串。大多数情况下,如果字符串的长度超过约 65.000 个字符,Wildfly EJB 客户端将在读取结果时挂起。不管怎样,有时我也遇到过客户端在超过该限制时冻结的情况。在我的客户端中,我注册了一个 EJB 调用拦截器,并且我发现调用 EJB-context.getResult() 时调用会冻结。在服务器端,也基于服务器端拦截器,我看到调用已完成,但显然在通过 EJB 客户端接收返回值时出现了问题。 这是挂起线程的堆栈跟踪:
"main@1" prio=5 tid=0x1 nid=NA waiting
java.lang.Thread.State: WAITING
at java.lang.Object.wait(Object.java:-1)
at java.lang.Object.wait(Object.java:502)
at org.wildfly.httpclient.common.WildflyClientInputStream.read(WildflyClientInputStream.java:147)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at org.jboss.marshalling.SimpleDataInput.read(SimpleDataInput.java:111)
at org.jboss.marshalling.UTFUtils.readUTFBytes(UTFUtils.java:151)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:314)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:231)
at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:41)
at org.wildfly.httpclient.ejb.HttpEJBReceiver$2.getResult(HttpEJBReceiver.java:207)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:620)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:551)
at org.jboss.ejb.protocol.remote.RemotingEJBClientInterceptor.handleInvocationResult(RemotingEJBClientInterceptor.java:57)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:622)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:551)
at org.jboss.ejb.client.TransactionPostDiscoveryInterceptor.handleInvocationResult(TransactionPostDiscoveryInterceptor.java:148)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:622)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:551)
at org.jboss.ejb.client.DiscoveryEJBClientInterceptor.handleInvocationResult(DiscoveryEJBClientInterceptor.java:130)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:622)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:551)
at org.jboss.ejb.client.NamingEJBClientInterceptor.handleInvocationResult(NamingEJBClientInterceptor.java:87)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:622)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:551)
at org.jboss.ejb.client.AuthenticationContextEJBClientInterceptor$$Lambda$94.871790326.get(Unknown Source:-1)
at org.jboss.ejb.client.AuthenticationContextEJBClientInterceptor.call(AuthenticationContextEJBClientInterceptor.java:59)
at org.jboss.ejb.client.AuthenticationContextEJBClientInterceptor.handleInvocationResult(AuthenticationContextEJBClientInterceptor.java:52)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:622)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:551)
at com.ge.hac.ca.common.util.CommonClientInvocationInterceptor.handleInvocationResult(CommonClientInvocationInterceptor.java:196)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:622)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:551)
at org.jboss.ejb.client.TransactionInterceptor.handleInvocationResult(TransactionInterceptor.java:212)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:622)
at org.jboss.ejb.client.EJBClientInvocationContext.getResult(EJBClientInvocationContext.java:551)
at org.jboss.ejb.client.EJBClientInvocationContext.awaitResponse(EJBClientInvocationContext.java:1003)
at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:182)
at org.jboss.ejb.client.EJBInvocationHandler.invoke(EJBInvocationHandler.java:116)
at com.sun.proxy.$Proxy4.loopback(Unknown Source:-1)
at com.ge.hac.ca.perf.connection.TestConnectionToWildfly.checkEJBInvocation_LoggerService(TestConnectionToWildfly.java:225)
at com.ge.hac.ca.perf.connection.TestConnectionToWildfly.executeEJBIterations(TestConnectionToWildfly.java:191)
at com.ge.hac.ca.perf.connection.TestConnectionToWildfly.main(TestConnectionToWildfly.java:401)
我正在使用 Amazon Corretto jdk1.8.0_292。
有没有人遇到过类似的问题,如果有,如何解决?
带有巨大结果对象(即字符串 >= 64 KB)的 EJB 调用不适用于 Wildfly 25 或 26,因为我现在必须使用 HTTP 协议,而不是“远程处理”我以前使用过的协议。 具体来说,HTTP/2 实现不起作用,但 HTTP/1 似乎可以工作。
说明: 我已经检查/调试了 Wildfly 客户端代码,在我看来,HTTP/2 协议实现的服务器和客户端代码中都存在几个错误。
第一个错误:服务器在数据流中间突然发送(主要是在较大的对象上)FRAME_TYPE_RST_STREAM(请参阅 io.undertow.protocols.http2.Http2FrameHeaderParser:191 --> type = header[3] & 0xff;), 它将流标记为已损坏(请参阅 io.undertow.server.protocol.framed.AbstractFramedStreamSourceChannel:684 --> state |= STATE_STREAM_BROKEN;) 然后在客户端内部的所有流读取上导致“ClosedChannelExceptions”(请参阅 org.wildfly.httpclient.common.WildflyClientInputStream:58 --> int res = streamSourceChannel.read(pooled.getBuffer());) 我没有调试服务器端代码,所以我无法判断为什么服务器突然在一些巨大的对象上发送“重置流”。有时,同一个巨大的对象会毫无问题地传输到客户端。使用 HTTP/1 时,这种情况永远不会发生,因此这不可能是网络问题。
第二个错误(由上述重置流发起):客户端无法正确处理由接收到的重置流发起的“ClosedChannelExceptions”,因为它冻结了整个通信。 客户端不断从通道读取数据,每次读取后都会对其锁对象调用 wait(0)(请参阅 org.wildfly.httpclient.common.WildflyClientInputStream:147 --> lock.wait();) 通常,此 wait(0) 会通过调用同一锁对象的 notifyAll() 来继续(在 ClosedChannelExceptions 的情况下,它是 org.wildfly.httpclient.common.WildflyClientInputStream:94 --> lock.notifyAll(); 不幸的是,在最后一次读取并因此最后调用 wait(0) 之后,不再调用 notificationAll(),因此 EJB 客户端调用永远冻结。我认为在任何情况下都不应该发生这种情况。
我找到的解决方案是在服务器上禁用 HTTP/2 协议并使用 HTTP/1 来代替,但我对此并不满意。
standalone-full.xml -->
现在通过 HTTP/1 协议进行 EJB 调用也适用于大型对象。
提到的带行号的类均取自Wildlfy 26.0.0客户端jar:
我希望一些 Wildfly 专家会读到这篇文章并做出反应。
感谢您与我们分享的所有内容,我也有同样的问题(或多或少)。 您是否得到了 Wildfly 专家或其他人的回复?