Java中,有一个for循环调用网络api很耗时,请问如何减少耗时?
30 个回答
这太正常了,一次网络调用,就算延迟100ms吧,你循环个10次就是1s(这还是完全理想,不考虑插队,网络抖动一类的问题)。
首先先问自己为啥要用for调用N次api,这是N个一样的api还是不一样的api?这个操作对用户来说是“1个操作”还是“N个操作”?下游api能提供某种把N个api合并成批量的api吗?或者下游有某种pipeline机制可以合并这个N次请求到一次网络请求吗?没有,能做一个吗?如果底层数据模型无法支持N个api同时做,是否可以改造底层数据模型呢?
此外,如果要求非常低的延迟,用RPC这种形式本来就是不对的。可以考虑改造了。参考游戏服务器的做法。
此外指出用多线程不一定有效果,多线程是并发了,你能确保他们真的并行吗?真的并行,同时发出去了的请求,你确认真的他们各自排队造成的延迟是差不多的吗?用多线程的各自发不同的请求的结果是,这一次请求的延迟取决于被处理最慢的那个请求。而那个最慢的请求是不是有可能排队很久呢?是不是直接就丢了,于是需要重新发?如何判断丢了?丢了1个,其他N-1个的结果咋办?是不是开始烧脑了?
另外这个效果一定就比循环N次强吗?压测下看看。
最后,这事和Java一点关系都没有。看看网络的书~
1 改api,让api支持batch批处理,这样你可以一次发几十上百个请求。
2 客户端多线程并行发送请求,你可以用线程池,也可以用异步call
3 你把客户端部署到几十台机器上
4 同时使用1,2,3,直到服务器挂了为止。。。。
这其实是一个典型的对性能优化没有入门的提问。
性能优化的前提,是找到性能瓶颈。 能理解这句话,你就已经一只脚踏到棺材板,哦不,踏到性能优化的门槛里了。
在这个回答里,For循环调用Api耗时,这是一个性能瓶颈,问题不大。
那接下来的方案是什么呢?
1 异步:如果你的API只是请求不用返回,异步调用是最简单的方式,如果你的API需要有返回,但只果不是同步的关系,你还是可以用异步。扔给一个线程程去解决就完事了。
2 批量:API的调用很大一部分在于TCP三次握手的链接,所以如果能够批次处理数据,那么性能提升杠杠的,当然,问题也在于是,如果出错了怎么办?
从这两个方案里能看出什么呢?
性能优化不是一个通用的方案,要结合实际业务场景,再给出对应的优化方案 。
通用性的原则是最基础的,你需要的是在基础的性能优化方案之上,结合实际的应用场景,给出最合适的方案。
还有, 性能优化是需要有优化目标的 。这个道理如果能懂,那么你已经一半身子挤进来了。
为什么要有目标?因为目标不同,你的方案也不同啊。
比如说,你要从10秒优化到5秒,和优化到20MS,那方案肯定不一样。
就以这个方案为例,如果你非要20MS解决,那就拉专线嘛。
重新总结一下性能优化的三板斧,弄懂这个,你在性能优化的道路上可以越走越远了,这比掌握一两个技巧更重要。
1 性能优化的前提,是找到性能瓶颈。
2 性能优化不是一个通用的方案,要结合实际业务场景,再给出对应的优化方案 。
3 性能优化是需要有优化目标的 。
嗯,回答内容也会收录到黑塔职业规划小程序里去。
1.单步变批量
2.同步变异步
3.cache是万能药
具体一点来说就是,看能否使用下游服务的批量获取接口,减少io次数;如果请求之间没有依赖,使用线程池异步的发起请求,用Future收集所有结果;如果请求结果是幂等的,可以考虑加个缓存,下次就可以一次获取;
我觉得吧,怎么看待这个事情可以把解法分成两类
- 既然RPC调用很慢,是不是本身就是这个RPC有问题
站在这个角度解决问题的话,更多的是去排查上游的链路
- 首先看网络有没有问题,虽然是很低概率的事情,但是我碰到过合作方的电缆被挖断导致提供给我们的RPC疯狂超时的情况,如果是这样的话提供RPC服务的这个集群其他的RPC服务也大概率会有问题
- 其次再看下上游的RPC本身有没有问题,有没有慢SQL,如果有的话可能要治理一下了
- 是不是有其他的服务有慢SQL拖慢了整个DB的吞吐,可以根据时间看下DB的相应情况
- 看下JVM的垃圾回收,同一时间有没有频繁的Yong GC甚至Full GC,如果有的话得dump内存看下具体的代码了
- 再就是排查下同一时间集群有没有异步离线任务,导致集群load飚高,服务质量下降
等等。。
2. 如果确定上游没有问题,或者上游不属于自己域内
- 那靠谱的解法就是想办法让上游提供批量接口
- 评估下可否改成异步
我看评论区中有同学说可以使用parallelStream去优化,通过自定义ForkJoinPool倒也可以,如果不知道这个点的话那是致命的
首先,ForkJoinPool是面向计算密集型任务设计的,如果在RPC调用慢这种IO密集型场景下使用会 造成外部线程阻塞,引起整个集群线程数增多 ,可能会有意想不到的后果
其次,RPC调用,消息消费都属于多线程场景, 多线程场景下用parallelStream(没有定制ForkJoinPool)是会降低并发度的 ,这个危害非常大,关于此推荐一篇非常好的文章大家可以看下:
欢迎关注作者的公众号: