Tomcat 9中基于异步事件驱动Servlet实现长轮询的最佳实践
Tomcat 9 实现HTTPS长轮询的最佳实践
核心方案:异步事件驱动Servlet(Async Servlet)
Tomcat 9完全支持异步Servlet,这正是解决同步I/O线程占用问题的最优方案——它能通过固定线程池处理大量长连接,无需为每个连接分配独立线程,完美适配你的需求。
实现步骤
编写支持异步的Servlet
通过注解开启异步支持,同时维护异步上下文队列用于消息推送,搭配固定线程池处理后台逻辑:@WebServlet(urlPatterns = "/long-poll", asyncSupported = true) public class LongPollServlet extends HttpServlet { // 线程安全队列,保存待推送的异步连接上下文 private final Queue<AsyncContext> asyncContexts = new ConcurrentLinkedQueue<>(); // 固定大小线程池,处理消息推送任务 private final ExecutorService pushExecutor = Executors.newFixedThreadPool(8); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { // 配置HTTPS长连接响应头 resp.setContentType("text/plain;charset=UTF-8"); resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); resp.setHeader("Pragma", "no-cache"); resp.setHeader("Connection", "keep-alive"); // 启动异步上下文 AsyncContext asyncContext = req.startAsync(); // 设置超时时间,避免连接长期挂起 asyncContext.setTimeout(30000); // 添加异步监听器,处理超时、完成等事件 asyncContext.addListener(new AsyncListener() { @Override public void onTimeout(AsyncEvent event) throws IOException { asyncContexts.remove(asyncContext); AsyncContext ac = event.getAsyncContext(); ac.getResponse().getWriter().write("timeout"); ac.complete(); } @Override public void onComplete(AsyncEvent event) { asyncContexts.remove(asyncContext); } @Override public void onStartAsync(AsyncEvent event) {} @Override public void onError(AsyncEvent event) {} }); // 将上下文加入队列,等待消息触发 asyncContexts.add(asyncContext); } // 消息推送方法,实际场景可从MQ、业务逻辑中触发 public void broadcastMessage(String message) { pushExecutor.submit(() -> { Iterator<AsyncContext> iterator = asyncContexts.iterator(); while (iterator.hasNext()) { AsyncContext ac = iterator.next(); try { ac.getResponse().getWriter().write(message); ac.complete(); // 完成响应,释放资源 iterator.remove(); } catch (IOException e) { iterator.remove(); e.printStackTrace(); } } }); } }Tomcat NIO连接器优化
在server.xml中配置HTTPS的NIO连接器,适配异步场景:<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="200" minSpareThreads="30" asyncTimeout="30000" SSLEnabled="true" scheme="https" secure="true" keystoreFile="/your/keystore/path" keystorePass="your-password" sslProtocol="TLSv1.2"/>maxThreads:设置核心工作线程数,异步模式下无需过大,因为连接等待不占用线程asyncTimeout:全局异步超时时间,与Servlet内的配置配合生效
核心优势
- 低资源占用:长连接等待状态不消耗Tomcat工作线程,仅在推送消息时使用固定线程池
- 完全兼容HTTPS:基于标准HTTP/HTTPS协议,使用443端口,满足端口限制要求
- 替代废弃的Comet API:Async Servlet是Servlet 3.0+标准特性,Tomcat 9原生支持,无兼容性风险
额外优化建议
- 连接复用:确保客户端和服务器开启HTTP Keep-Alive,减少TCP握手开销
- 批量推送:针对大量客户端,可批量处理异步上下文,避免线程池过载
- 客户端重连:客户端收到超时或响应后,自动重新发起长轮询,保持连接活性
- 内存清理:通过异步监听器及时移除失效上下文,防止内存泄漏
内容的提问来源于stack exchange,提问作者vmayorow
相关产品推荐
相关产品推荐

