国庆的时候闲来无事,就随手写了一点之前说的比赛的代码,目标就是保住前 100 混个大赛的文化衫就行了。
现在还混在前 50 的队伍里面,稳的一比。
其实我觉得大家做柔性负载均衡那题的思路其实都不会差太多,就看谁能把关键的信息收集起来并利用上了。
由于是基于 Dubbo 去做的嘛,调试的过程中,写着写着我看到了这个地方:
org.apache.dubbo.rpc.protocol.AbstractInvoker#waitForResultIfSync
先看我框起来的这一行代码,aysncResult 的里面有有个 CompletableFuture ,它调用的是带超时时间的 get() 方法,超时时间是 Integer.MAX_VALUE,理论上来说效果也就等同于 get() 方法了。
从我直观上来说,这里用 get() 方法也应该是没有任何毛病的,甚至更好理解一点。
但是,为什么没有用 get() 方法呢?
其实方法上的注释已经写到原因了,就怕我这样的人产生了这样的疑问:
抓住我眼球的是这这几个单词:
have serious performance drop。
性能严重下降。
大概就是说我们必须要调用 java.util.concurrent.CompletableFuture#get(long, java.util.concurrent.TimeUnit)
而不是 get() 方法,因为 get 方法被证明会导致性能严重的下降。
对于 Dubbo 来说, waitForResultIfSync 方法,是主链路上的方法。我个人觉得保守一点说,可以说 90% 以上的请求都会走到这个方法来,阻塞等待结果。所以如果该方法如果有问题,则会影响到 Dubbo 的性能。
Dubbo 作为中间件,有可能会运行在各种不同的 JDK 版本中,对于特定的 JDK 版本来说,这个优化确实是对于性能的提升有很大的帮助。
就算不说 Dubbo ,我们用到 CompletableFuture 的时候,get() 方法也算是我们常常会用到的一个方法。
另外,这个方法的调用链路我可太熟悉了。
因为我两年前写的第一篇公众号文章就是探讨 Dubbo 的异步化改造的,《Dubbo 2.7新特性之异步化改造》
当年,这部分代码肯定不是这样的,至少没有这个提示。
因为如果有这个提示的话,我肯定第一次写的时候就注意到了。
果然,我去翻了一下,虽然图片已经很模糊了,但是还是能隐约看到,之前确实是调用的 get() 方法:
我还称之为最“骚”的一行代码。
因为这一行的代码就是 Dubbo 异步转同步的关键代码。
前面只是一个引子,本文不会去写 Dubbo 相关的知识点。
主要写写 CompletableFuture 的 get() 到底有啥问题。
放心,这个点面试肯定不考。只是你知道这个点后,恰好你的 JDK 版本是没有修复之前的,写代码的时候可以稍微注意一下。
学 Dubbo 在方法调用的地方加上一样的 NOTICE,直接把逼格拉满。等着别人问起来的时候,你再娓娓道来。
或者不经意间看到别人这样写的时候,轻飘飘的说一句:这里有可能会有性能问题,可以去了解一下。
啥性能问题?
根据 Dubbo 注释里面的这点信息,我也不知道啥问题,但是我知道去哪里找问题。
这种问题肯定在 openJDK 的 bug 列表里面记录有案,所以第一站就是来这里搜索一下关键字:
https://bugs.openjdk.java.net/projects/JDK/issues/
一般来说,都是一些陈年老 BUG,需要搜索半天才能找到自己想要的信息。
但是,这次运气好到爆棚,弹出来的第一个就是我要找的东西,简直是搞的我都有点不习惯了,这难道是传说中的国庆献礼吗,不敢想不敢想。