使用tomcat和spring进行异步http请求处理

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

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

  • 接收包含要查询的URL的HTTP GET请求
  • 对于单个GET请求,服务将提取URL
  • 查询关于URL的本地数据库
  • 如果在数据库中找到结果,它会将其返回给客户端,如果不是,则需要查询一些外部服务(可能需要相对较长的时间来响应)
  • 将URL的结果返回给客户端
  • 我正在虚拟机上运行此操作,并在Spring中运行Tomcat7。 我会提前道歉,并提到我对Tomcat很新

    无论如何,我期待着很多并发GET请求到这个服务(成百上千的同时请求)我基本上试图实现的是使这个服务尽可能地扩展(如果这是不可能的,那么至少是一个服务可以处理数以十万计的同时请求)

    我一直在阅读关于服务中异步请求处理(特别是在Tomcat中)的一篇文章,但是我还有一些东西仍然不清楚:

  • 从官方的tomcat网站看来,Tomcat似乎包含一些接受者线程和工作线程的数量。 如果是这样,为什么我应该使用AsyncContext? 释放一个Tomcat的工作线程并在我的应用程序中占用不同线程以执行完全相同的操作有什么好处? (系统中仍有1个活动线程)
  • 有点类似于第一个问题,但创建AsyncContext并使用它与不同的线程有什么好处吗? (来自我的应用程序中创建的线程池的线程)
  • 关于同样的问题,我在这里看到我也可以返回一个Callable或一个DeferredResult,并使用Tomcat的线程或我自己的线程处理它。 返回Callable或使用DeferredResult仅仅处理来自请求的AsyncContext是否有任何好处?
  • 另外,如果我决定返回一个可调用对象,那么Tomcat从哪个线程池获取线程来处理我的可调用对象? 这里使用的线程是否与我之前提到的Tomcat具有相同的工作线程? 如果是这样,那么从发布一个Tomcat工作线程并使用不同的线程可以获得什么好处?
  • 我从Oracle的文档中看到,我可以将AsyncContext传递给一个可同时处理的Runnable对象,从哪里执行此Runnable的线程来自哪里? 我有任何控制权吗? 另外,将AsyncContext传递给Runnable只是将AsyncContext传递给我的线程有什么好处?
  • 我很抱歉对同样的问题提出了很多问题,但我和我的同事们在这些问题上争论了一个多星期,却没有任何具体的答案。

    我还有一个常见问题:您认为如何让我描述的服务可扩展? (暂时增加更多的机器),你可以发布任何示例或参考用于目标解决方案吗?

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

    干杯!


    这里有很多问题,但我会尽力解决其中的一些问题。

    异步I / O是一件好事,特别是在处理大量请求的服务器上 - 它允许使用更少的线程来处理更多的请求。 在你写代理的情况下,你真的希望你的HTTP客户端(也就是对外部URL的请求)也是异步的,这样既不处理请求也不接收远程响应就包含阻塞I / O。

    也就是说,用一般的Tomcat或Java EE服务器来处理这些事情可能会比较困难,这些服务器有异步的I / O作为事后的想法,而不是像从头开始异步的Netty这样的框架。 作为构建在Netty之上的框架的作者,我有点偏颇。

    为了演示你所需要的代码有多少,我写了一个小型服务器,它在3个Java源文件中描述了这些内容,并将它放在github上 - 它构建了一个独立的JAR,可以使用java -jar运行尝试一下,我试图清楚地评论它。

    结果是,网络应用程序花费大部分时间等待I / O发生。 特别是在使用传统的线程I / O的情况下,您将得到一个请求,并且接收请求的线程将负责同步回答 - 也就是说,如果它必须发出网络请求另一台服务器,该线程被阻塞,等待来自远程服务器的答案。 这意味着线程不能用于其他任何事情。 所以,如果你有10个线程,并且所有的线程都在等待响应,你的服务器就不能回答更多的请求,直到其中一个线程完成并释放一个线程。 使用异步I / O时,当某些I / O完成时会得到回调。 换句话说,在操作系统将数据刷入套接字并将网卡刷出之前,您的代码只需在需要做的事情(如来自您的代理请求的响应)时轻松获得肩膀。 在您的代码正在等待该HTTP请求完成时,发送代理请求的线程可以自由用于处理另一个请求。这意味着一个线程可以在一个请求上做一些工作,在另一个请求上做一些工作,另一个线程可以在另一个请求上做一些工作,并最终完成第一个请求。 由于线程是您的操作系统提供的有限资源,因此您可以使用更少的硬件来完成更多任务。

    至于CallableDeferredResult ,使用Callable只会在工作周围发生时移动( Callable稍后会在某个线程或其他线程中执行,但仍然期望同步返回结果); DeferredResult听起来更像你所需要的,因为它允许你的代码关闭并完成它想要的任何工作,然后在需要设置的时候设置结果(触发完成响应)。

    老实说,我认为如果你想真正有效地实现这一点,你最好避开Java EE堆栈 - 它的大部分内容都假设I / O是同步的,尝试使用异步的东西是向上游游泳(例如,JDBC的同步I / O已烧入其骨骼 - 如果您真的希望这样做可以扩展,并且您想使用SQL数据库,那么最好使用类似这样的东西)。

    有关使用Netty进行此类操作的另一个示例,请参阅tiny-maven-proxy项目 - 代码不太漂亮,但它显示了执行HTTP代理的一个示例,其中响应主体逐个馈送到客户端,大块,因为它到达 - 所以你永远不会真正将完整的响应主体拉到内存中,这意味着即使具有巨大响应的请求也不会运行代理内存不足。 微小Maven代理也缓存在文件系统上。 我没有在演示中做这些事情,因为它会使代码更复杂。

    链接地址: http://www.djcxy.com/p/24303.html

    上一篇: asynchronous http request handling with tomcat and spring

    下一篇: Where has nuget support in Resharper 9 gone?