Java 服务器端异步和同步HTTP请求,性能比较
我试图找出异步和同步HTTP请求处理的优缺点。我使用Dropwizard和Jersey作为我的框架。 测试是比较异步和同步HTTP请求处理,这是我的代码Java 服务器端异步和同步HTTP请求,性能比较,java,multithreading,http,asynchronous,jmeter,Java,Multithreading,Http,Asynchronous,Jmeter,我试图找出异步和同步HTTP请求处理的优缺点。我使用Dropwizard和Jersey作为我的框架。 测试是比较异步和同步HTTP请求处理,这是我的代码 @Path("/") public class RootResource { ExecutorService executor; public RootResource(int threadPoolSize){ executor = Executors.newFixedThreadPool(threadPoo
@Path("/")
public class RootResource {
ExecutorService executor;
public RootResource(int threadPoolSize){
executor = Executors.newFixedThreadPool(threadPoolSize);
}
@GET
@Path("/sync")
public String sayHello() throws InterruptedException {
TimeUnit.SECONDS.sleep(1L);
return "ok";
}
@GET
@Path("/async")
public void sayHelloAsync(@Suspended final AsyncResponse asyncResponse) throws Exception {
executor.submit(() -> {
try {
doSomeBusiness();
asyncResponse.resume("ok");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
private void doSomeBusiness() throws InterruptedException {
TimeUnit.SECONDS.sleep(1L);
}
}
syncAPI将在Jetty维护的工作线程中运行,asyncAPI将主要在customs线程池中运行。这是我的Jmeter结果
- 测试1500 Jetty工作线程/sync端点
- 测试2500个自定义线程/异步端点 结果表明,两种方法之间没有太大差异
我按照建议以10次延迟运行测试
- sync-500-server-thread
- 异步-500-workerthread
我写这篇文章是根据我个人的经验,为斯里兰卡的前台出租车招呼服务编写了一个使用异步处理程序的促销引擎,该服务甚至与优步并肩竞争 与同步处理程序相比,异步处理程序更具可扩展性、可用性和资源利用率 如果您使用的是同步处理程序,则最大并发请求数由可接受新连接的线程数定义,在此之后,您的服务将无法再接受请求
如果您使用异步处理程序,那么接受线程计数与您不能满足的并发请求数量无关。因此,您的服务可以从100 RPM扩展到100万RPM,并且具有高可用性
如果您关心延迟和吞吐量,那么如果您将非阻塞API与异步处理程序一起使用,则可以得到很好的改进。非阻塞套接字(NIO)、非阻塞存储(Mango DB反应、ReDIS反应)、消息队列(卡夫卡、RabByMQ)等 < P>:考虑下面的场景:
Single Backend system
____________
| System A |
HTTP Request --> | |
| 1. |
| 2. |
HTTP Response <-- | |
|____________|
Multi-Backend System
____________
| System A | __________
HTTP Request --> | | --> | |
| 1. | | System B |
| | <-- |__________|
| | __________
| 2. | --> | |
HTTP Response <-- | | | System C |
|____________| <-- |__________|
单后端系统
____________
|系统A|
HTTP请求-->||
| 1. |
| 2. |
HTTP响应您使用的是仍然等待响应的组合异步
@Suspended将暂停/挂起当前线程,直到它得到响应
如果您想在异步中获得更好的性能,请使用ExecutorService
和Future
编写不同的异步方法
私有执行器服务执行器;
私人未来结果;
@施工后
public void onCreate(){
this.executor=Executors.newSingleThreadExecutor();
}
@职位
公众回应startTask(){
futureResult=executor.submit(new ExpensiveTask());
返回Response.status(status.ACCEPTED.build();
}
@得到
公共响应getResult()引发ExecutionException、InterruptedException{
if(futuresult!=null&&futuresult.isDone()){
返回Response.status(status.OK).entity(futuresult.get()).build();
}否则{
返回Response.status(status.forbidded).entity(“稍后重试”).build();
}
}
以下是我的想法
无论是同步还是异步请求,它与HTTP的性能无关,但与应用程序的性能相关
同步请求将阻塞应用程序,直到它收到响应为止,而在异步请求中,基本上,您将在一个单独的工作线程中分配此工作,该线程将处理其余的事情。所以在异步设计中,主线程仍然可以继续自己的工作
假设由于某些限制(不是服务器的资源限制),您的服务器可以处理有限数量的连接(基本上,每个连接都将在单独的线程中处理,我们使用的服务器不同)。如果您的服务器可以处理比连接更多的线程数,并且您不希望由于创建的异步工作而返回任何数据,那么您可以设计异步逻辑。因为您将创建一个新线程来处理请求的任务
但是,如果您希望在响应中返回操作的结果,则不会有任何不同。其中,就像使用异步处理程序一样,接受线程计数与您不能满足的并发请求数无关。但在本例中,您需要另一个线程池来处理HTTP请求,该线程池也不能无限大。[1]在“/async”摘要报告中,最小值7(毫秒?)看起来低得令人怀疑。如果重复运行,报告是否仍显示类似的最小值较低?(2)您可能想考虑用JMeTM替换一个标签,以吸引更合适的受众。您是否尝试以10秒的延迟复制?@ SkOMISA是因为在运行异步测试时有一些套接字错误,如您所见,错误率为1.08% @ USS729 49。异步方式在最大延迟方面稍差一些,我认为这是因为它有更多的上下文切换。我认为您会混淆服务器端异步/同步HTTP请求处理和异步/同步HTTP客户端。如果我以同步方式处理HTTP请求,我仍然可以使用异步HTTP客户端请求系统B和C,这给了我最大响应时间(B,C),感谢您指出了挂起注释。但是正如代码中所描述的,端点应该作为业务需求返回“Hello”。如果我删除挂起,客户端将获得HTTP 204,而没有响应正文。@JadeTang您可以返回“Hello”,但仍然使用Future
如果我删除挂起,客户端将获得HTTP 204
private ExecutorService executor;
private Future<String> futureResult;
@PostConstruct
public void onCreate() {
this.executor = Executors.newSingleThreadExecutor();
}
@POST
public Response startTask() {
futureResult = executor.submit(new ExpensiveTask());
return Response.status(Status.ACCEPTED).build();
}
@GET
public Response getResult() throws ExecutionException, InterruptedException {
if (futureResult != null && futureResult.isDone()) {
return Response.status(Status.OK).entity(futureResult.get()).build();
} else {
return Response.status(Status.FORBIDDEN).entity("Try later").build();
}
}