servlet异步_如何使用异步Servlet来提高性能

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异步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346239.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql锁机制 php_MySQL锁机制和PHP锁机制

模拟准备--如何模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本例如:cmd: apache安装路径/bin/ab.exe -c 10 -n 10 http://web.test.com/test.php【切入正题】MYSQ…

怎么安装红旗Linux5,如何用硬盘安装红旗LINUX5_0.doc

如何用硬盘安装红旗LINUX5_0如何用硬盘安装红旗LINUX5_0本文由xinbing9贡献红旗linux5.0安装教程相信大家都和我一样,在一开始知道linux的系统时充满了神秘感.习惯了windows的我们对另一种操作系统非常好奇.正是这种好奇心,我决定装linux.看看到底有什么东东.第一次装时,大略的…

企业应用程序开发框架的分类

如果您使用的是“最佳Java框架”,那么您很可能会迷失本文 ,它对Java Enterprise世界中的情况进行了很好的概述。 但是,从我的角度来看,它缺少一件非常重要的事情–对上述框架进行分类。 让我们看看这个生态系统的另一个角度&…

投资最重要的事读后感_《投资最重要的事》读书笔记分享

1、学习第二层次思维。在投资的零和世界中参与竞争之前,你必须先问问自己是否具有处于上半部分的充分理由。要想取得超过一般投资者的成绩,你必须有比群体共识更加深入的思考。你具备这样的能力吗?是什么让你认为自己具有这样的能力&#xff…

Linux下社交平台,Linux 启动

> 1. 如启动失败请 查看[坑点概述](https://doc.fastadmin.net/wanlshop/299.html)## Linux运行IM即时通讯#### 1\. 远程连接Linux可以通过远程连接软件、VNC远程连接、Workbench或宝塔面板 > 软件商店 > 宝塔SSH终端进入SSH 终端cd命令 进入cd www/wwwroot/你的网站/…

vscode 取消拉去变基_GIT快速回忆

关于GIT和github:请搜索git下载安装,安装了git才能去github或码云(国内)观察自己上传的代码,github有个桌面版只是基于git的的图形工具,还是需要下载git。概念:1.提交、版本、commit,ID,差不多都…

java对象序列化去掉字段_使用序列化查找对象中的脏字段

java对象序列化去掉字段假设您正在开发一个将对象自动保存到数据库中的框架。 您需要检测两次保存之间所做的更改,以便仅保存已修改的字段。 如何检测脏场。 最简单的方法是遍历原始数据和当前数据,并分别比较每个字段。 代码如下: public s…

c语言中怎么定义的字符串,C语言中定义字符串的几种方式

1,什么是字符串?所谓字符串本质上就是以\0作为结尾的特殊字符数组;2,定义字符串的过程中有哪些注意点由于字符串本质上其实就是以\0作为结尾的特殊字符数组,所以定义字符串时,必须保证字符串存储的最后一个…

ios 不被遮挡 阴影_解决ios10导航栏底部阴影线条隐藏失效问题

2016.11.13 21:47* 字数 887 阅读 791评论 0喜欢 16一、置空阴影图片基于iOS9,在iOS10上不好使.[self.navigationController.navigationBar setShadowImage:[UIImage new]];二、剪裁navigationBar首先看看UIView的clipsToubounds属性在SDK中的描述:property(nonatom…

Java的未来项目:巴拿马,织布机,琥珀和瓦尔哈拉

新闻稿“ Oracle Code One Java主题演讲概述了Java的未来 ”在Oracle Code“突出未来项目” Valvala 项目,巴拿马 项目,Amber 项目和Loom 项目中描述了Java主旨。 这篇文章为不熟悉上述项目的人提供了每个项目的简要摘要以及与每个项目相关的一些最新工作…

c语言选择题答案在哪查,C语言选择题及答案

C语言选择题及答案成绩的取得离不开我们平时的努力,以下是百分网小编为大家整理的C语言选择题及答案,希望对大家的学习起到帮助!选择题1.在深度为5的满二叉树叶中,叶子结点的个数为( )。A.32B.31C.16D.152.软件生命周期中,花费最多…

vs2019中如何创建qt项目_在VS2015中创建Qt项目【VS+Qt项目开发系列】(二)

在VS2015中创建Qt项目【VSQt项目开发系列】(二)发布时间:2018-04-20 22:44,浏览次数:1269, 标签:VSQt在上一篇【VSQt项目开发】(一)在VS2015中安装Qt环境中,我们完成了开发环境的安装,现在我们正式创建我们的项目。项目…

c语言ok未定义标识符,C语言中宏的相关知识 - osc_y7ckpzr9的个人空间 - OSCHINA - 中文开源技术交流社区...

2019/04/27 16:02 1.宏的定义:宏定义就是预处理命令的一种,它允许用一个标识符来表示一个字符串。格式如下:#define name(宏名) stuff(字符串)本质就是使用宏名去替代字符串的内容,注意是原封不动的替换,不要自己潜意识…

pythoni屏幕连点_【Flutter组件】仿抖音双击点赞弹出爱心效果(可连点)

效果简介仿抖音点赞手势,单击暂停,双击点赞,可连续点击添加多个爱心,特点如下全部效果为代码绘制(爱心图标来自Material Icon的图标)套上在目标Widget外即可使用提供单击与点赞的回调建议复制代码使用,动画可按需修改没…

java8 linq4j_Java 8仍然需要LINQ吗? 还是比LINQ更好?

java8 linq4j长期以来, LINQ是.NET软件工程生态系统中发生的最好的事情之一。 通过在Visual Studio 2008中引入lambda表达式和monad ,它使C#语言跃居Java之前,Java在当时是版本6,但仍在讨论泛型类型擦除的优缺点。 这项…

printf sizeof c语言,你可能对 sizeof(i++) 有点误解。。。

原标题:你可能对 sizeof(i) 有点误解。。。各位,今天还是按照惯例给大家分享一个C语言容易出现的小错误,这也是跟sizeof有关的,问题虽小,却可管中窥豹,话不多说,代码先行:# includei…

mongodb上一篇下一篇_如何使用Microsoft office word—上一篇

从这一期开始,将会逐一介绍Microsoft office的几个常用的软件,例如word ppt excel等,每一个软件将分为几期介绍,这几期介绍word。注意:介绍软件版本是Microsoft office365。如何插入图片首先打开word,点击插…

Java:使用Mockito模拟ResultSet

这篇文章展示了如何使用Mockito模拟java.sql.ResultSet 。 它可用于帮助单元测试代码对ResultSet (例如ResultSetExtractor )执行操作,而无需依赖外部数据源。 您可以通过提供列名列表和2D数据数组来创建MockResultSet 。 例如: …

c语言如何随机获取1kb,基于VS2010+C语言实现播放器的顺序播放、随机播放

1.[文件] music.h ~ 920B 下载(38)/** File: music.h* Time: 2014/10/11*/#ifndef __MUSIC_H__#define __MUSIC_H__typedef enum { UNPLAYED, PLAYED } BOOL; // 自定义一个bool类型typedef enum { ORDER, RANDOM } PLAY_MODEL; // 自定义一个播放类型typedef char *MUSIC_…

rmi远程代码执行漏洞_fastjson远程代码执行漏洞复现

漏洞原理fastjson提供了autotype功能,在请求过程中,我们可以在请求包中通过修改type的值,来反序列化为指定的类型,而fastjson在反序列化过程中会设置和获取类中的属性,如果类中存在恶意方法,就会导致代码执…