ter*_*xus 6 java tomcat asynchronous jax-rs jersey
我有一个异步JAX-RS API,用于在Jersey Container Servlet 2.22中放置并在Tomcat 7上托管的长轮询客户端.
它看起来类似于下面显示的代码段.它在生产中运作良好.
平均有150个长轮询请求同时执行.它导致几乎相同数量的实时Tomcat HTTP连接(根据JMX指标).对于这种低流量情况,使用普通的HTTP-BIO连接器没有问题.如果您仅使用托管线程,则无法检测到运行时连接泄漏:)
@Path("/v1/events")
public class LiveEventsResource {
private static final long longPollTimeoutMs = 30000;
private ExternalResource externalResource = ExternalResourceProvider.provide();
private AsyncResponse asyncResponse;
@POST
@Path("/liveEvents")
@ManagedAsync
public void getResult(@Suspended final AsyncResponse asyncResponse, RequestPayload payload) {
this.asyncResponse = asyncResponse;
asyncResponse.setTimeout(longPollTimeoutMs, TimeUnit.MILLISECONDS);
asyncResponse.setTimeoutHandler(new TimeoutHandler() {
@Override
public void handleTimeout(AsyncResponse asyncResponseArg) {
try {
asyncResponseArg.cancel();
} finally {
cleanupResources();
}
}
});
startListeningForExternalEventsAndReturn(payload);
}
private void startListeningForExternalEventsAndReturn(RequestPayload payload) {
externalResource.register(new Listener() {
@Override
public void onEvent(Event event) {
respond(event);
}
});
}
private void respond(Event event) {
try {
asyncResponse.resume(event);
} catch (RuntimeException exception) {
asyncResponse.resume(exception);
} finally {
cleanupResources();
}
}
protected void cleanupResources() {
externalResource.cleanup();
}
}
Run Code Online (Sandbox Code Playgroud)
我面临的问题是,在成功的Tomcat重新部署过程之后,实时连接的数量显然将增加到大约300,然后增加到450,并且在进行一些进一步的重新部署之后,它将达到maxConnection为容器配置的限制.
API的客户端通过等待客户端超时(当然大于servlet端设置的超时)来处理重新部署,并再次开始轮询API.但他们保证只能同时发送一个请求.
连接计数监控图的形状给出了提示.取消部署后连接计数保持不变(连接不会释放回池中TimeOutHandler)并且随着客户端再次开始长轮询而开始增加(分配新连接).实际上,在JVM终止之前,在前一个上下文中启动的正在进行的(暂停的)异步请求永远不会被释放!
经过一些挖掘后不难发现,通过分析在少量重新部署之后进行的堆转储,未发布的暂停AsyncResponse(AsyncResponder)实例保留在以前的Web应用程序上下文的内存中(可以通过Classloader实例分组的JQL查询轻松过滤).同样数量的过时org.apache.coyote.Request实例在以前的上下文中存在于内存中也是非常可疑的.
我开始环顾的取消部署相关的源代码新泽西集装箱希望一些正常关机过程与在执行一些清理行动异步请求的实现@PreDestroy-时间或close()或dispose()方法Provider秒.
我乐观地猜测,通过TimeOutHandler在取消部署之前运行每个预定的s来解决问题.但是将默认的@BackgroundSchedulerprovider(DefaultBackgroundSchedulerProvider)替换为自定义实现并收集所有排队TimeoutHandler的Executor并最终调用它们AsyncResponse.resume()或AsyncResponse.cancel()对它们没有帮助.此阶段对于此清理可能为时已晚,因为请求范围已经关闭.
有关我的异步设置缺失的内容或者如何配置Jersey以释放仍在重新部署时暂停的Servlet容器连接的任何想法?
| 归档时间: |
|
| 查看次数: |
565 次 |
| 最近记录: |