gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:54:37 24 4
gpt4 key购买 nike

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

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

  • 接收包含URL的HTTP GET请求以查询
  • 对于单个GET请求,服务提取URL
  • 查询有关URL的本地数据库
  • 如果在数据库中找到了结果,它将返回给客户端,如果没有,它将需要查询一些外部服务(可能需要花费较长的时间来响应)
  • 将URL的结果返回给客户端

  • 我正在使用spring在虚拟机和Tomcat7上运行它。
    我会先道歉,并提到我是Tomcat的新手

    无论如何,我期望对此服务有很多并发的GET请求(数十万个并发请求)
    我基本上想实现的目标是使该服务尽可能地可扩展(如果不可能的话,至少要有一个能够处理成千上万同时请求的服务)

    我一直在阅读有关服务(尤其是Tomcat)中的异步请求处理的大量文章,但是我有一些不清楚的地方:
  • 在tomcat官方网站上,Tomcat似乎包含许多接受线程和一些工作线程。
    如果是这样,为什么我应该使用AsyncContext?释放Tomcat的工作线程并在应用程序中占用不同的线程以执行完全相同的操作有什么好处? (系统中仍然有1个 Activity 线程)
  • 有点类似于第一个问题,但是创建AsyncContext并将其与其他线程一起使用有什么好处吗? (来自在我的应用程序中创建的线程池中的线程)
  • 关于同一问题,我看到here也可以返回Callable或DeferredResult并使用Tomcat的线程之一或我自己的线程之一对其进行处理。与仅处理请求中的AsyncContext相比,返回Callable或使用DeferredResult有什么好处吗?
  • 另外,如果我决定返回一个可调用对象,那么Tomcat从哪个线程池获取该线程来处理我的可调用对象?这里使用的线程与我前面提到的来自Tomcat的工作线程是否相同?如果是这样,发布一个Tomcat工作线程并改用另一个工作线程有什么好处?
  • 从Oracle文档中可以看到,我可以将可以同时处理的Runnable对象传递给AsyncContext,用于执行此Runnable的线程从何而来?我对此有任何控制权吗?另外,与仅将AsyncContext传递给我的线程相比,将AsyncContext传递给Runnable有什么好处?

  • 对于相同的问题我问了这么多问题,我感到很抱歉,但是我和我的同事们为这些问题争论了一个多星期,没有任何具体的答案。

    我还有一个更普遍的问题:
    您认为使我描述的服务可扩展的最佳方法是什么? (目前暂不考虑添加更多计算机),您能针对目标解决方案发布任何示例或引用吗?

    我会发布更多我一直在查看的链接的链接,但是我目前的声誉不允许这样做。
    对于任何可理解的引用文献或具体示例,我将不胜感激,并且很高兴在任何相关问题上进行澄清

    干杯!

    最佳答案

    这个问题很多,但我会尝试解决其中的一些问题。

    异步I/O是一件好事,尤其是在处理大量请求的服务器上-它允许您使用更少的线程来处理更多的请求。对于正在编写的代理,您确实希望HTTP客户端(使对外部URL的请求)也异步,以便处理请求或接收远程响应都不会阻止I/O。

    就是说,与使用诸如Netty这样从头开始是异步的框架的Tomcat或Java EE服务器相比,通常来说,在做事之后,您通常会比较费劲,因为Tomcat或Java EE服务器将异步I/O连接到了它们。作为基于Netty构建框架的作者,我有些偏颇。

    为了演示执行描述所需的代码很少,我编写了一个小型服务器,该服务器执行了3个Java源文件and put it on 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数据库,则最好使用something like this)。

    有关使用Netty进行此类操作的另一个示例,请参见tiny-maven-proxy项目-代码虽然不太漂亮,但它显示了一个HTTP代理示例,该示例将响应主体逐块地馈送到客户端,因为它到达-因此您实际上从未将完整的响应主体拉到内存中,这意味着即使响应很大的请求也不会使代理耗尽内存。 Tiny-maven-proxy也缓存在文件系统上。我没有在the demo中做这些事情,因为它会使代码更复杂。

    关于java - 使用tomcat和spring进行异步http请求处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27923680/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com