Java 中并发请求多个接口怎样才能效率最高呢?

2020-03-26 15:38:34 +08:00
 noble4cc

在 Java 中并发的请求多个接口,把请求来的数据做个聚合然后返回,如果是调用了 api1 然后再调用 api2 再调用 api3,这种方式可能大多数时间都在网络 IO 上了,而且随着接口的变多性能不断下降 如果是在 go 中直接用协成就可以了,请求五个 api 和请求一个 api 耗时可能差不多(前提 api 平均耗时都一样)

java 中该如何编写代码呢?使用线程池的话肯定提高效率有限,因为线程不是协成,数量不会太多,并发量大了都在线程池里排队了

使用 NIO httpclient 可能效果好些,但是都必须写 callback,怎么判断所有的 api 都把结果成功返回了,然后我们要聚合接口,callback 写起来有些难受

java 中这种场景应该很多见,一般会怎么处理呢?

8710 次点击
所在节点    Java
43 条回复
Macolor21
2020-03-27 00:04:27 +08:00
以前做个类似场景,用创建个线程池,然后用 CountdownLatch 。看楼上似乎 8 的特性也支持。建议楼主写多个版本,做下 benchmark
noble4cc
2020-03-27 00:22:00 +08:00
@guyeu 线程池在并发量大的情况下不如协成吧
感觉线程池的原理是使用多线程进行 http 请求,比如 5 个 api,开 5 线程,然后聚合,但是每个线程在执行的时候 io 是阻塞的,大部分的线程时间都浪费在阻塞上了,如果我们这种聚合 api 数据的请求特别多,比如 1000qps,复用五个线程或者多开点 20 个,相当于 1000 个要请求 5000 次后端 api,在线程池里排队处理的话太慢吧
tairan2006
2020-03-27 08:40:57 +08:00
这不是基本功么,开线程等待完成,CountDownLatch 啊
Seawalker
2020-03-27 09:06:37 +08:00
标记一下看看有没有好方案
shaoyijiong
2020-03-27 09:16:14 +08:00
一楼标准答案
yc8332
2020-03-27 09:17:16 +08:00
只是聚合请求,干嘛不搞个现成的 api 网关就好了。。
piglovesx
2020-03-27 09:19:51 +08:00
小白一枚,很好奇协程是从哪个英文单词翻译过来的,是 channel 吗?
guolaopi
2020-03-27 09:31:28 +08:00
C#:Task.WaitAll();
(滑稽
LosLord
2020-03-27 09:46:07 +08:00
CompletableFuture.allOf(List<CompletableFuture>)
noble4cc
2020-03-27 10:20:05 +08:00
@tairan2006 老哥我说过多线程方案性能肯定不行
200 qps 访问 5 个 api 不能开 1000 个线程吧,线程复用一个机器 8core 开 16 个工作线程的话,每次并发的请求后端 api 是 16,每个 api 平均耗时 10ms 的话,第 200 个请求得等到什么时候呢?量少了确实没什么问题,java 类似的工具包确实也多如牛毛
noble4cc
2020-03-27 10:22:48 +08:00
@micean 这个本质上确实是 io 多路复用的原理吧,开起来挺方便的,vert.x 不太熟,netty 到是经常用,我一开始想的是用 netty 封装个 httpclient,但是感觉搞起来太麻烦了,是不是 vert.x 就是用 netty 实现了 http 协议了
lscexpress
2020-03-27 10:34:03 +08:00
@piglovesx Coroutine 翻译为协程,通常来说 java 不用协程。channel 在书中的翻译多为信道或者通道
piglovesx
2020-03-27 11:07:32 +08:00
@lscexpress 谢谢 :)
guyeu
2020-03-27 11:13:24 +08:00
@noble4cc #22 是的,线程池在并发量大的情况下不如协程。所以这种情况下会做一些设计,比如把发消息和收消息分开,一个线程池专门发,一个线程池专门处理收消息,也就是 NIO 的思路。。
hpeng
2020-03-27 11:14:44 +08:00
看一楼的
aguesuka
2020-03-27 12:00:54 +08:00
@noble4cc vertx 底层就是 netty
buliugu
2020-03-27 15:27:09 +08:00
java 大量 API 请求可以用 Quasar,现成的纤程库
elevation
2020-03-30 15:47:12 +08:00
不知道你现在怎么样,我觉得用 diruptor,环形数组线程分发,可以降低消耗,自己写底层实现,工厂,资源调用。比较方便;
xiaoidea
2020-03-31 17:27:30 +08:00
目前用的是线程池+guava ListenableFuture 、Futures 工具类,确实很多线程堵在 IO 上了,线程池要开多大需要压测
看到有其他项目用 Spring webflux 的,对这个不熟
monkeyWie
2020-04-03 18:31:05 +08:00
NIO httpclient + CountDownLatch 不就行了吗
主线程还是得阻塞的啊,阻塞到 api 全部 callback 完

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/656411

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX