这是我的第一个问题,所以请耐心对待我:)
我正在尝试创建一种服务:
我是在虚拟机和Tomcat7上运行这个spring的。我会事先道歉,并说我对Tomcat很陌生
不管怎么说,我期望这个服务会有很多并发的GET请求(几十万个同时请求),我基本上想要实现的是使这个服务尽可能地具有可伸缩性(如果这是不可能的,那么至少有一个能够处理数十万次同时请求的服务)
我已经阅读了很多关于服务中异步请求处理的文章,特别是在Tomcat中,但是我仍然不清楚一些事情:
我很抱歉就同样的问题问了这么多问题,但我和我的同事们就这些问题争论了一个多星期,没有得到任何具体的答复。
我还有一个一般性的问题:您认为使我描述的服务可伸缩的最佳方法是什么?(暂时撇开增加更多的机器相比),你能为这个有目的的解决方案提供任何例子或参考吗?
我会张贴更多的链接,我一直在看,但我目前的声誉不允许它。我将感谢任何可以理解的参考或者具体的例子,我很乐意澄清任何相关的问题。
干杯!
发布于 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请求完成时,发送代理请求的线程可以自由地处理另一个请求,这意味着一个线程可以对一个请求做一些工作,对另一个请求做一些工作,并最终完成第一个请求。因为线程是操作系统提供的有限资源,这允许您用更少的硬件做更多的事情。
至于Callable和DeferredResult,使用Callable只是在工作发生时移动( Callable稍后在某个线程或其他线程上执行,但仍然希望同步返回结果);DeferredResult听起来更像是您需要的东西,因为这允许您的代码运行它想做的任何工作,然后设置结果(触发响应的完成)。
老实说,我认为如果您想要高效地实现这个功能,最好远离Java堆栈--其中很多都是在假设I/O是同步的情况下做出的,以至于试图与其同步完成异步操作是在上游进行的(例如,JDBC有同步I/O进入其核心--如果您真的希望扩展它,并且希望使用SQL数据库,那么使用像这样的东西就更好了)。
关于将奈蒂用于这类事情的另一个例子,请参阅微型maven代理项目--代码不那么漂亮,但它展示了一个示例,在该代理中,响应体在到达时被逐块地馈送给客户端--因此您永远不会将完整的响应体实际拉到内存中,这意味着即使具有巨大响应的请求也不会从内存中运行代理。微型maven代理也缓存在文件系统上。我没有在演示中做这些事情,因为这样会使代码更加复杂。
https://stackoverflow.com/questions/27923680
复制相似问题