在做电商系统的时候,首页、活动页、商品详情页等流量入口承载了整个网站的大部分流量网站,这些系统的主要职责包括聚合数据组装模板、热点统计、缓存、下游功能降级开关、后台数据等,其中聚合数据需要调用其他多个系统服务获取数据、组装数据/模板,然后返回到前端。聚合数据的来源主要取决于系统/服务、缓存、数据库等;而系统之间的调用可以通过http接口调用(如HttpClient)、SOA服务调用(如dubbo、thrift)等。在Java中,如果使用Tomcat,一个请求会分配一个线程来处理请求。该线程负责获取数据,组装数据或模板返回给前端;整个线程总是被占用和阻塞。如果有大量这样的请求,每个请求占用一个线程,但是线程一直处于阻塞状态,降低了系统的吞吐量,进而会导致应用程序的吞吐量下降;我们希望被依赖的服务响应比较慢,这时候应该释放线程和CPU去处理下一个请求,当被依赖的服务返回时,再分配相应的线程继续处理。对此应该有更好的解决方案:异步/协程。Java不支持协程(虽然有的Java框架说支持,但仍然是对高层API的封装),所以在Java中我们也可以使用异步来提高吞吐量。目前主要支持java的一些开源框架(HttpClient\HttpAsyncClient、dubbo、thrift等)。多个调用方法的同步阻塞调用为串行调用,响应时间为所有服务响应时间之和;半异步(asynchronousFuture)线程池,异步Future,使用场景:并发请求多个服务,总耗时为最长响应时间;提高总响应时间,但阻塞主请求线程。并发高的时候,还是会造成线程过多,CPU上下文切换;所有异步(Callback)回调方法调用,使用场景:不考虑回调时间,只能做简单的结果处理,如果依赖的服务是两个或多个服务,则不能合并两个服务的处理结果;主请求线程不阻塞,但使用场景有限。异步回调链编排异步回调链编排(JDK8CompletableFuture),使用场景:其实不是异步调用方式,只是将依赖多个服务的Callback调用结果进行整理,弥补Callback的不足,从而实现完全异步的链式传输。接下来我们看看如何使用全异步Callback调用和异步回调链编排处理结果来设计一个全异步系统设计。同步阻塞调用publicclassTest{publicstaticvoidmain(String[]args)throwsException{RpcServicerpcService=newRpcService();HttpServicehttpService=newHttpService();//耗时10msMapresult1=rpcService.getRpcResult();//耗时20msIntegerresult2=httpService.getHttpResult();//总共耗时30ms}staticclassRpcService{MapgetRpcResult()throwsException{//调用远程方法(远程方法耗时10ms左右,可以用Thread.sleep模拟)}}staticclassHttpService{IntegergetHttpResult()throwsException{//调用远程方法(远程方法耗时20ms左右,可以用Thread.sleep模拟)Thread.sleep(20);return0;}}}半异步(asynchronousFuture)publicclassTest{finalstaticExecutorServiceexecutor=Executors.newFixedThreadPool(2);publicstaticvoidmain(String[]args){RpcServicerpcService=newRpcService();HttpServicehttpService=newHttpService();Future