CXF JAXRS 客户端不重用 TCP 连接
我使用 CXF 2.2.5 中的 JAX-RS 支持来调用 REST Web 服务。我正在为需要与之通信的每个端点(通常是任何给定部署的一个或两个端点)创建一个 org.apache.cxf.jaxrs.client.WebClient 实例,并为每个 Web 服务调用重新使用此客户端。
我面临的问题是客户端正在为每个请求创建到服务器的新 TCP 连接,尽管使用了保持活动设置。在高流量水平下,这会引起问题。下面是我的客户端代码的摘录。
我正在尝试挖掘 CXF 源代码来找出问题所在,但目前却迷失了方向。任何想法都非常感激。
谢谢, FB
ConcurrentMap<String, WebClient> webclients = new ConcurrentHashMap<String, WebClient>();
public void dispatchRequest(MyRequestClass request, String hostAddress) {
// Fetch or create the web client if we don't already have one for this hostAddress
// NOTE: WebClient is only thread-safe if not changing the URI or headers between calls!
// http://cxf.apache.org/docs/jax-rs-client-api.html#JAX-RSClientAPI-ThreadSafety
WebClient client = webclients.get(hostAddress);
if (client == null) {
String serviceUrl = APP_HTTP_PROTOCOL + "://" + hostAddress + ":" + APP_PORT + "/" + APP_REQUEST_PATH;
WebClient newClient = WebClient.create(serviceUrl).accept(MediaType.TEXT_PLAIN);
client = webclients.putIfAbsent(hostAddress, newClient);
if (client == null) {
client = newClient;
} // Else, another thread must have added the client in the meantime - that's fine if so.
}
XStream marshaller = MyCollection.getMarshaller();
String requestXML = marshaller.toXML(request);
Response response = null;
try {
// Send it!
response = client.post(requestXML);
}
catch (Exception e) {
}
...
}
I'm using the JAX-RS support in CXF 2.2.5 to invoke REST webservices. I'm creating a single org.apache.cxf.jaxrs.client.WebClient instance for each endpoint I need to communicate with (typically one or two endpoints for any given deployment) and re-using this client for each web-service invocation.
The problem I face is that the client is creating new TCP connections to the server for each request, despite using the keep-alive setting. At high traffic levels, this is causing problems. An excerpt from my client code is below.
I'm trying to dig through the CXF source to identify the problem but getting hopelessly lost at present. Any thoughts greatly appreciated.
Thanks,
FB
ConcurrentMap<String, WebClient> webclients = new ConcurrentHashMap<String, WebClient>();
public void dispatchRequest(MyRequestClass request, String hostAddress) {
// Fetch or create the web client if we don't already have one for this hostAddress
// NOTE: WebClient is only thread-safe if not changing the URI or headers between calls!
// http://cxf.apache.org/docs/jax-rs-client-api.html#JAX-RSClientAPI-ThreadSafety
WebClient client = webclients.get(hostAddress);
if (client == null) {
String serviceUrl = APP_HTTP_PROTOCOL + "://" + hostAddress + ":" + APP_PORT + "/" + APP_REQUEST_PATH;
WebClient newClient = WebClient.create(serviceUrl).accept(MediaType.TEXT_PLAIN);
client = webclients.putIfAbsent(hostAddress, newClient);
if (client == null) {
client = newClient;
} // Else, another thread must have added the client in the meantime - that's fine if so.
}
XStream marshaller = MyCollection.getMarshaller();
String requestXML = marshaller.toXML(request);
Response response = null;
try {
// Send it!
response = client.post(requestXML);
}
catch (Exception e) {
}
...
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在示例代码中,您将获得一个 JAX-RS 响应,其中 getEntity() 方法默认返回一个 InputStream。因此,由于 CXF 不负责消耗流,因此这显然是开放的。
如果您不明确关闭它,它将在垃圾收集阶段关闭。
但即便如此,在高流量速率下,这一小延迟仍会阻止底层 HTTP 连接重新插入到 HttpURLConnection(CXF 在后台使用的)所利用的持久连接的内部池中。所以不能按时重复使用。
如果您注意关闭 InputStream,则不应再看到大量 TIME_WAIT 套接字。
In your sample code you get a JAX-RS Response, which getEntity() method will return an InputStream by default. Therefore, being CXF not responsible for consuming the stream, this is obviously left open.
If you don't explicitly close that, it would be closed during a Garbage Collection phase.
But even so, under high traffic rates, this little latency prevents the underlying HTTP connection to be reinserted into the internal pool of persistent connections exploited by HttpURLConnection (that CXF is using under the bonnet). So it cannot be reused on time.
If you take care of closing the InputStream, you should not see a large number of TIME_WAIT sockets anymore.
我肯定会尝试更新到更新且受支持的 CXF 版本。新版本的 CXF 中对 JAX-RS 内容进行了大量更新,这个问题可能已经得到解决。
I would definitely try updating to a newer and supported version of CXF. There have been a LOT of updates to the JAX-RS stuff in the newer versions of CXF and this issue may already be fixed.