java - 使用少量线程并发发送大量 HTTP 请求

标签 java http asynchronous load-testing completable-future

我们需要在我们的 Java 代码中同时向服务器端点发送大量 HTTP 请求(每秒数百个请求)持续一段时间。服务器需要大约 4-5 秒来响应每个请求。

底层代码使用 Apache HttpClient(经典)发出这些请求。由于此客户端处于阻塞状态,我不得不使用大量线程(在 ExecutorService.newFixedThreadPool() 中)并发发送请求以实现以下目标:启动这些线程,其中每个线程基本上做这样的事情:

while (time_elapsed < 3600 seconds) {
    sendHttpRequest(); // this takes ~4-5 seconds, during which the current thread is blocked due to the nature of Apache 
}

有两个问题:

  • 由于服务器在 4-5 秒内响应每个 HTTP 调用,理论上我们将需要 400-500 个线程才能发送约 100 个请求/秒,但如此大量的线程会消耗大量资源,并且会导致很多上下文切换以及其他问题,所以实际上他们不会真正发送多达 100 个请求/秒
  • 由于每个线程都必须等到当前请求完成(4-5 秒)后才能发送下一个请求,因此我们无法控制每秒发送的请求的精确数量。

如果我们可以灵活地切换到像 Apache HttpAsyncClient 这样的异步 http 客户端,这会很容易。或 async-http-client , 但不幸的是,由于代码库的限制,我们不能。

我的问题是,是否有另一种方法可以实现每秒数百个并发请求,使用少量线程并且不使用异步 HTTP 客户端? CompletableFuture 是一个选项吗?

最佳答案

虚拟线程

Virtual threads ( fibers ) 是一个新的 preview feature建议Java 19 .这是 Project Loom 的一部分, 带有实验版本 available now .

在传统的 Java 并发中,Java 中的线程与主机操作系统线程直接一对一映射。问题是当线程中运行的代码阻塞时,线程也会阻塞。该线程暂停,直到执行代码被解除阻塞。在等待对存储 I/O、网络 I/O、数据库访问等的调用返回时,线程可能会闲置很多时间。

相比之下,许多建议的虚拟线程都映射到主机操作系统提供的每个“真实”线程。当虚拟线程正在执行的代码阻塞时,虚拟线程被“停放”,搁置一旁,而另一个虚拟线程将在主机操作系统线程上占据一席之地。当先前的虚拟线程的任务不再被阻塞时,它会再次分配给主机操作系统线程以继续执行。

这种 parking 和 parking 非常高效。这意味着您可以同时拥有数千甚至数百万个线程。

因此您可以将数百个 HTTP 请求设置为单独的 Runnable/Callable任务,然后将它们全部提交给适当的执行器服务以立即执行。


顺便说一下,Java 现在包含一个 new HTTP client图书馆。

关于java - 使用少量线程并发发送大量 HTTP 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72066501/

相关文章:

javascript - Node JS - 文件写入/Http 请求真正异步

java - 安卓 3.1 : Unit Testing a Class that Request User Permissions

java - 在单个项目 netbeans 中有两个同名的 jar 文件

C - 套接字,分离数据和http header ?

ruby - 缓存获取的网页有哪些选项?

c# - 为什么 Multiple await 需要像 Task.WhenAll() 一样的时间

java - 如何在java中输出格式化的html

java - Leptonica findSkew 返回 0.0

http - 使用 MUX 包将查询参数传递给 Go HTTP 请求处理程序

javascript - 如何使用嵌套promise调用函数并获取值