我正在使用Java。另一位软件开发人员向我提供了执行同步HTTP调用的代码,并负责维护它-他正在使用com.google.api.client.http
。无法更新他的代码以使用带有回调的异步HTTP客户端,并且我无法联系开发人员对其进行更改。但是我仍然想要将回调附加到HTTP请求的高效异步行为。
(我正在Spring Boot中工作,并且如果有效果,我的系统将使用RabbitMQ AMQP构建。)
简单的HTTP GET(实际上是一个API调用)的执行方式如下:
HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());
我正在通过HTTP与之通信的该服务器需要一些时间来回复...例如3-4秒。因此,我的执行线程在此期间一直处于阻塞状态,等待答复。这样的扩展性很差,我的单线程没有执行,只是在等待回复到达-这很繁重。
当然,如果我想同时发送更多HTTP请求,则可以添加执行此调用的线程数,即我可以通过这种方式进行扩展,但这听起来效率不高或不正确。如果可能的话,在这种情况下,我真的想获得比1个线程等待1个HTTP请求更好的比率。
换句话说,我想发送带有2-3个可用线程的数千个HTTP请求,并在响应到达时对其进行处理;我不想在执行每个请求之间造成任何重大延迟。
我想知道:如何实现更具扩展性的解决方案?每个线程如何处理数千个HTTP调用?我应该看什么,或者我只是没有选择,而我要求不可能?
编辑:我想这是表达我的问题的另一种方法。假设我现在有1000个请求要发送,每个请求将持续3-4秒,但是只有4-5个可用的执行线程可以在上面发送它们。我想同时发送所有邮件,但这是不可能的。如果我设法在0.5秒或更短的时间内将它们全部发送出去,并通过某种回调或类似方式处理它们的请求,那么我认为这是一个很好的解决方案。但是我不能切换到异步HTTP客户端库。
答案 0 :(得分:4)
使用异步HTTP客户端不是可用选项-我无法更改HTTP客户端库。
在这种情况下,我认为您在客户端上陷入了不可扩展的同步行为。
我唯一能想到的解决方法是将请求作为任务在具有有限线程池的ExecutorService
中运行。这将限制使用的线程数量...,但也将限制正在进行的同时HTTP请求的数量。这将一个扩展问题替换为另一个扩展问题:您正在有效地限制HTTP请求的速率。
但是另一面是,同时发起太多HTTP请求可能会使目标服务和/或客户端或服务器端网络链接不堪重负。从这个角度来看,客户端限速可能是一件好事。
假设我现在有1000个请求要发送,每个请求将持续3-4秒,但是只有4-5个可用的执行线程可以在上面发送它们。我想同时发送所有邮件,但这是不可能的。如果我设法在0.5秒或更短的时间内将它们全部发送出去,并通过某种回调或类似方式处理它们的请求,那么我认为这是一个很好的解决方案。但是我不能切换到异步HTTP客户端。
使用N个线程同时运行
和“ ...回调或类似的内容...” 。这是您只能通过异步客户端获得的功能。 (或更准确地说,如果内部有真正的异步客户端库,则只能通过回调获得真正的异步行为。)
因此解决方案类似于以一种交错的方式发送HTTP请求,即一个请求与另一个请求之间存在一些延迟,其中每个延迟都受可用线程数的限制?如果每个请求之间的延迟不大,我可以找到可接受的延迟,但我假设每个线程执行之间的延迟会相当大,因为每个线程必须互相等待才能完成(3-4s) ?在那种情况下,这不是我想要的。
使用我建议的解决方法,很难量化任何两个请求之间的延迟。但是,如果您尝试同时提交大量请求并等待所有响应,则各个请求之间的延迟无关紧要。对于这种情况,相关的度量标准是完成所有请求的时间。假设没有其他东西提交给执行者,则完成请求所花费的时间大约为:
nos_requests * average_request_time / nos_worker_threads
要注意的另一件事是,如果您确实设法同时提交了大量请求,则每个请求3-4s的服务器延迟很可能会增加。服务器仅具有每秒处理一定数量请求的能力。如果超出该容量,则请求将被延迟或丢弃。
但是如果没有其他选择。
我想,您可以考虑更改服务器API,以便可以在单个HTTP请求中提交多个“请求”。
我认为真正的问题是服务器API设计要支持的功能与您要使用的功能之间不匹配。
肯定有问题:
另一位软件开发人员向我提供了执行同步HTTP调用的代码,并负责维护该代码-他正在使用com.google.api.client.http。无法更新他的代码以使用带有回调的异步HTTP客户端,并且我无法联系开发人员对其进行更改。
也许您需要“咬住子弹”并停止使用他的代码。弄清楚它在做什么,并用您自己的实现替换它。
没有神奇的尘埃尘埃会从同步HTTP客户端提供可扩展的性能。期间。