首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用tomcat和spring异步处理http请求

用tomcat和spring异步处理http请求
EN

Stack Overflow用户
提问于 2015-01-13 13:50:15
回答 1查看 2.2K关注 0票数 9

这是我的第一个问题,所以请耐心对待我:)

我正在尝试创建一种服务:

  1. 接收包含要查询的URL的HTTP请求
  2. 对于单个GET请求,服务提取URL
  3. 查询本地数据库有关URL的信息
  4. 如果在DB中找到结果,它将返回给客户端,如果不是,则需要查询一些外部服务(这可能需要相对较长的时间来响应)。
  5. 将URL的结果返回给客户机

我是在虚拟机和Tomcat7上运行这个spring的。我会事先道歉,并说我对Tomcat很陌生

不管怎么说,我期望这个服务会有很多并发的GET请求(几十万个同时请求),我基本上想要实现的是使这个服务尽可能地具有可伸缩性(如果这是不可能的,那么至少有一个能够处理数十万次同时请求的服务)

我已经阅读了很多关于服务中异步请求处理的文章,特别是在Tomcat中,但是我仍然不清楚一些事情:

  1. 从官方的tomcat网站上看,Tomcat似乎包含了接收线程的数量和工作线程的数量。如果是这样,我为什么要使用AsyncContext?在我的应用程序中释放Tomcat的工作线程并占用不同的线程来执行完全相同的操作有什么好处?(系统中仍有一个活动线程)
  2. 有点类似于第一个问题,但是创建AsyncContext并将它与其他线程一起使用有什么好处呢?(在我的应用程序中创建的线程池中的线程)
  3. 关于同样的问题,我看到了这里,我也可以返回一个可调用的或一个DeferredResult,并使用Tomcat的一个线程或我自己的一个线程来处理它。返回可调用的或使用DeferredResult是否比处理来自请求的AsyncContext更有好处?
  4. 另外,如果我决定返回一个可调用的线程,Tomcat从哪个线程池中获取线程来处理我的可调用的线程?这里使用的线程是否与前面提到的Tomcat中的工作线程相同?如果是这样,那么发布一个Tomcat工作线程并使用另一个线程会带来什么好处呢?
  5. 我从Oracle的文档中看到,我可以传递给AsyncContext一个将被并发处理的可运行对象,用于执行这个可运行对象的线程从哪里来?我能控制它吗?另外,将运行的AsyncContext传递给我的线程之一AsyncContext有什么好处呢?

我很抱歉就同样的问题问了这么多问题,但我和我的同事们就这些问题争论了一个多星期,没有得到任何具体的答复。

我还有一个一般性的问题:您认为使我描述的服务可伸缩的最佳方法是什么?(暂时撇开增加更多的机器相比),你能为这个有目的的解决方案提供任何例子或参考吗?

我会张贴更多的链接,我一直在看,但我目前的声誉不允许它。我将感谢任何可以理解的参考或者具体的例子,我很乐意澄清任何相关的问题。

干杯!

EN

回答 1

Stack Overflow用户

发布于 2015-02-07 05:01:43

这里面有很多问题,但我会设法解决其中的一些问题。

异步I/O是一件好事,特别是在服务大量请求的服务器上--它允许您使用更少的线程来处理更多的请求。在您正在编写的代理的情况下,您确实希望您的HTTP客户机(发出对外部URL的请求)也是异步的,这样处理请求或接收远程响应都不涉及阻塞I/O。

尽管如此,在Tomcat或Java服务器上使用异步I/O作为事后考虑可能会比使用像奈蒂这样的框架更加困难,因为这些服务器通常是异步的。作为一个建立在Netty之上的框架的作者,我有一点偏见。

为了演示您所需的代码有多少,我编写了一台小型服务器,它完成了您在3个Java源文件把它放在github上中描述的内容--它构建了一个独立的JAR,您可以使用java -jar进行测试,我试图对其进行清楚的注释。

归根结底,网络应用程序大部分时间都在等待I/O的发生。特别是在代理的情况下,对于传统的线程I/O,您将得到一个请求,接收请求的线程将负责同步地回答它--这意味着,如果它必须向另一个服务器发出网络请求,该线程将被阻塞,等待来自远程服务器的答案。这意味着线程不能用于其他任何事情。因此,如果您有10个线程,并且所有线程都在等待响应,那么在其中一个线程完成并释放线程之前,您的服务器无法响应任何请求。使用异步I/O时,当某些I/O完成时,您将得到一个回调。换句话说,在操作系统将您的数据刷新到套接字并输出网卡之前,您的代码不是一动不动,而是在有事情可做时,您的代码只会得到友好的点击(比如来自代理请求的响应)。当您的代码等待HTTP请求完成时,发送代理请求的线程可以自由地处理另一个请求,这意味着一个线程可以对一个请求做一些工作,对另一个请求做一些工作,并最终完成第一个请求。因为线程是操作系统提供的有限资源,这允许您用更少的硬件做更多的事情。

至于CallableDeferredResult,使用Callable只是在工作发生时移动( Callable稍后在某个线程或其他线程上执行,但仍然希望同步返回结果);DeferredResult听起来更像是您需要的东西,因为这允许您的代码运行它想做的任何工作,然后设置结果(触发响应的完成)。

老实说,我认为如果您想要高效地实现这个功能,最好远离Java堆栈--其中很多都是在假设I/O是同步的情况下做出的,以至于试图与其同步完成异步操作是在上游进行的(例如,JDBC有同步I/O进入其核心--如果您真的希望扩展它,并且希望使用SQL数据库,那么使用像这样的东西就更好了)。

关于将奈蒂用于这类事情的另一个例子,请参阅微型maven代理项目--代码不那么漂亮,但它展示了一个示例,在该代理中,响应体在到达时被逐块地馈送给客户端--因此您永远不会将完整的响应体实际拉到内存中,这意味着即使具有巨大响应的请求也不会从内存中运行代理。微型maven代理也缓存在文件系统上。我没有在演示中做这些事情,因为这样会使代码更加复杂。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27923680

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档