servlet异步

这篇文章将描述一种性能优化技术,该技术适用于与现代Web应用程序相关的常见问题。 如今的应用程序不再只是被动地等待浏览器发起请求,而是希望自己开始通信。 一个典型的示例可能涉及聊天应用程序,拍卖行等–共同点是这样一个事实,即大多数时候与浏览器的连接处于空闲状态并等待某个事件被触发。

这类应用程序已经开发出自己的问题类别,尤其是在面对重负载时。 症状包括线程不足,用户交互受苦,陈旧性问题等。

根据最近在加载此类应用程序方面的经验,我认为现在是演示简单解决方案的好时机。 在Servlet API 3.0实现成为主流之后,该解决方案就变得真正简单,标准化和优雅。

但是在进入演示解决方案之前,我们应该更详细地了解问题。 对于我们的读者–在某些源代码的帮助下,比解释问题更容易的是:

@WebServlet(urlPatterns = "/BlockingServlet")
public class BlockingServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {try {long start = System.currentTimeMillis();Thread.sleep(2000);String name = Thread.currentThread().getName();long duration = System.currentTimeMillis() - start;response.getWriter().printf("Thread %s completed the task in %d ms.", name, duration);} catch (Exception e) {throw new RuntimeException(e.getMessage(), e);}}

上面的servlet是上面描述的应用程序的外观示例:

  • 请求到达,宣布有兴趣监视某些事件
  • 线程被阻塞,直到事件到达
  • 收到事件后,响应将被编译并发送回客户端

为了简单起见,我们将等待部分替换为对Thread.sleep()的调用。

现在,您可能会认为这是一个完全正常的servlet。 在许多情况下,您是完全正确的–在应用程序面临大量负载之前,代码没有错。

为了模拟此负载,我在JMeter的帮助下创建了一个相当简单的测试,在该测试中,我启动了2,000个线程,每个线程运行10次迭代,以对/ BlockedServlet的请求轰炸应用程序。 在现成的Tomcat 7.0.42上使用已部署的servlet运行测试,我得到以下结果:

  • 平均响应时间:19,324毫秒
  • 最小响应时间:2,000毫秒
  • 最大响应时间:21,869 ms
  • 吞吐量:97个请求/秒

Tomcat的默认配置有200个工作线程,再加上将模拟工作替换为2,000ms睡眠周期这一事实很好地说明了最小和最大响应时间– 200秒中的每个线程应该能够完成100个睡眠周期,每个2秒。 最重要的是,加上上下文切换成本,达到的97个请求/秒的吞吐量非常接近我们的预期。

对于99.9%的应用程序而言,吞吐量本身看起来不会太差。 但是,从最大响应时间(尤其是平均响应时间)来看,问题开始变得更加严重。 在20秒(而不是预期的2秒)内获得响应是确定惹恼用户的肯定方法。

现在让我们看一下利用Servlet API 3.0异步支持的替代实现:

@WebServlet(asyncSupported = true, value = "/AsyncServlet")
public class AsyncServlet extends HttpServlet {private static final long serialVersionUID = 1L;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Work.add(request.startAsync());}
}
public class Work implements ServletContextListener {private static final BlockingQueue queue = new LinkedBlockingQueue();private volatile Thread thread;public static void add(AsyncContext c) {queue.add(c);}@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {thread = new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(2000);AsyncContext context;while ((context = queue.poll()) != null) {try {ServletResponse response = context.getResponse();response.setContentType("text/plain");PrintWriter out = response.getWriter();out.printf("Thread %s completed the task", Thread.currentThread().getName());out.flush();} catch (Exception e) {throw new RuntimeException(e.getMessage(), e);} finally {context.complete();}}} catch (InterruptedException e) {return;}}}});thread.start();}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {thread.interrupt();}
}

这部分代码稍微复杂一点,所以也许在我们开始深入研究解决方案细节之前,我可以概述一下该解决方案在延迟方面的性能提高约75倍,在吞吐量方面的性能提高了约20倍 。 掌握了此类结果的知识后,您应该更加有动力去理解第二个示例中的实际情况。

servlet本身看起来确实很简单。 但是,有两个事实值得概述,第一个事实声明了该Servlet支持异步方法调用:

@WebServlet(asyncSupported = true, value = "/AsyncServlet")

第二个重要方面隐藏在以下行中

Work.add(request.startAsync());

其中整个请求处理都委托给Work类。 使用AsyncContext实例存储请求的上下文,该实例保存由容器提供的请求和响应。

现在,第二个也是更复杂的类–以ServletContextListener实现的Work开始看起来更简单。 传入的请求只是在实现中排队等待通知-这可能是对受监控拍卖的更新出价,或者是群聊中所有请求都在等待的下一条消息。

通知到达时-再次简化为仅在Thread.sleep()中等待2,000ms,队列中所有被阻止的任务都由一个负责编译和发送响应的工作线程处理。 我们没有阻塞数百个线程来等待外部通知,而是以一种更简单,更简洁的方式实现了这一点-将兴趣组批处理在一起,并在单个线程中处理请求。

结果不言而喻–在具有默认配置的相同Tomcat 7.0.24上进行的相同测试得出以下结果:

  • 平均响应时间:265毫秒
  • 最小响应时间:6毫秒
  • 最长响应时间:2,058毫秒
  • 吞吐量:1,965请求/秒

此处的具体情况很小且综合,但在实际应用中可以实现类似的改进。

现在,在您将所有servlet重写为异步servlet之前-稍等片刻。 该解决方案可以完美地用在部分用例上,例如群聊通知和拍卖行价格警报。 对于请求在唯一数据库查询完成后等待的情况,您很可能不会从中受益。 因此,与往常一样,我必须重申我最喜欢的与性能相关的建议–衡量所有事情。 什么都不要猜。

但是在问题确实适合解决方案形状的情况下,我只能称赞它。 除了对吞吐量和延迟的明显改进之外,我们还优雅地避免了在高负载下可能出现的线程不足问题。

另一个重要方面–异步请求处理方法最终实现了标准化。 独立于您最喜欢的Servlet API 3.0 –兼容应用程序服务器(例如Tomcat 7 , JBoss 6或Jetty 8),您可以确定该方法有效。 不再为不同的Comet实现或与平台相关的解决方案(例如Weblogic FutureResponseServlet)而费力

参考: Plumbr Blog博客上的JCG合作伙伴 Nikita Salnikov Tarnovski 如何使用异步Servlet来提高性能 。

翻译自: https://www.javacodegeeks.com/2013/10/how-to-use-asynchronous-servlets-to-improve-performance.html

servlet异步

servlet异步_如何使用异步Servlet来提高性能相关推荐

  1. java servlet类_[Java教程]与Servlet相关的类

    [Java教程]与Servlet相关的类 0 2017-08-31 17:00:15 有4个有关的类,通过servlet可以获得其中的三个,然后通过ServletConfig间接获取ServletCo ...

  2. ztree java 异步_使用 zTree 异步加载

    使用 zTree 异步加载 使用场景 可能需要展示类别很多,如果采用直接加载的方式,需要展示的数据量过大,交互十分不友好.所以采用 zTree 异步加载数据. demo 环境 SpringBoot 1 ...

  3. pthread异步_探索 Flutter 异步消息的实现

    本文作者:赵旭阳 字节跳动资深工程师 一.简介 我们在进行 Android 开发的时候,会通过创建一个 Handler 并调用其 sendMessage  或 Post 方法来进行异步消息调用,其背后 ...

  4. java event 异步_[转]java异步编程

    很多时候我们都希望能够最大的利用资源,比如在进行IO操作的时候尽可能的避免同步阻塞的等待,因为这会浪费CPU的资源.如果在有可读的数据的时候能够通知程序执行读操作甚至由操作系统内核帮助我们完成数据的拷 ...

  5. 微服务架构 性能提升_如何通过无服务器架构提高性能

    微服务架构 性能提升 by Domenico Angilletta 通过多梅尼科·安吉列塔(Domenico Angilletta) 如何通过无服务器架构提高性能 (How to boost your ...

  6. servlet3异步_Servlet 3的异步Servlet功能

    servlet3异步 在深入了解什么是异步Servlet之前,让我们尝试了解为什么需要它. 假设我们有一个Servlet,处理时间很长,如下所示. LongRunningServlet.java pa ...

  7. 如何使用异步Servlet来提高性能

    这篇文章将描述一种性能优化技术,适用于与现代Web应用程序相关的常见问题. 如今的应用程序不再只是被动地等待浏览器发起请求,而是希望自己开始通信. 一个典型的示例可能涉及聊天应用程序,拍卖行等–共同点 ...

  8. python mongodb 异步_【转】Python操作MongoDB数据库

    前言 MongoDB GUI 工具 PyMongo(同步) Motor(异步) 后记 前言 最近这几天准备介绍一下 Python 与三大数据库的使用,这是第一篇,首先来介绍 MongoDB 吧,,走起 ...

  9. servlet怎么接受请求_谁再问Servlet的问题,我就亲自上门来教学了

    1. 概述 在这篇简短的文章中,我们将从概念上理解什么是servlet 和 servlet 容器以及它们是如何工作的. 同时,还能在请求.响应.会话对象.共享变量和多线程的上下文中看到它们的身影. 2 ...

最新文章

  1. java 对象被回收的例子_Java对象的后事处理——垃圾回收(二)
  2. 机器学习特征工程之特征缩放+无量纲化:最大绝对值缩放(MaxAbsScaler)
  3. python 投资组合_重新设计投资组合的好处
  4. 细数改善WPF应用程序性能的10大方法
  5. python僵尸进程和孤儿进程_进程3.0——进程状态与僵尸进程、孤儿进程
  6. Hibernate笔记2
  7. Java---读取.properties配置文件空指针异常
  8. blob协议的加密视频地址下载,多个ts文件合并方法,亲测有效
  9. android 编译太慢,如何解决android studio运行编译速度慢
  10. NoteExpress使用教程及添加参考文献自动跳转超链接
  11. 百度地图定位经纬度返回4.9E-324有关问题
  12. 粒子滤波跟踪算法及实现
  13. 值得一看的电脑教程下载
  14. Springboot应用中过滤器chain.doFilter后设置header无效
  15. 滚动截屏苹果_30个小技巧,带你玩转苹果三大系统
  16. 随机抽人名小程序_分析并实现一个简单的抽人程序
  17. 分布式实时计算课程学习(2.2)——Source API
  18. ESP32( IDF平台)+MAX30102 配合Pyqt上位机实现PPG波形显示与心率计算
  19. 手把手教你用视频做闪屏页
  20. 微信小程序setdata方法

热门文章

  1. 【贪心】Sunscreen(poj 3614/luogu 2887)
  2. 组合数学与数论函数专题
  3. java 中 image 和 byte[] 相互转换
  4. JAVA面试常考系列九
  5. JAVA面试常考系列五
  6. jstack命令:教你如何排查多线程问题
  7. layui结合springboot上传图片
  8. Photoshop基本操作
  9. 人脸检测源码facedetection
  10. 用命令行执行java代码