问题背景
我们有一个微服务架构的项目是基于 Spring Cloud 的,因为拆分出来的服务比较多,如何能够保证服务的 Consumer 和 Provider 始终消费的是同一份契约呢?
于是乎,我们引入了 Spring Cloud Contract 测试,但是其中有一个服务A会依赖于服务 B,服务 C 和服务 D,由于服务B,C,D 的启动需要时间较长,导致这个测试代码的执行耗时比较长。为了避免在跑契约测试的时候需要把所有服务 A,B,C,D 都启动起来,我们决定使用 Stub 的方式,因为这样测试的执行速度要快很多,开发人员能够更快的得到测试的反馈。
具体的操作大致是这样的:如果服务 A 作为 Consumer,服务 B,C,D 作为 Provider,那么在运行服务 A 的契约测试之前,先将服务 B,C,D 定义好的契约发布到自己的 maven 仓库中。然后运行测试的过程中,会通过 Stub Runner 将服务 B,C,D 的契约 serve 起来,这样就可以顺利的进行契约对比了,而且执行的速度还相当快。
直到某一天,一位开发同学跳出来说,“这个测试跑的太慢了,每次在本地跑一边都要20分钟”,而另一为同学却说,“没有啊,我一直三分钟就跑完了啊……”
诊断过程
出于开发的本能,第一时间还以版本问题,结果 Gradle 版本一致,JDK 版本一致,各种依赖库的版本也一致。然后怀疑 Gradle 的参数设置,因为大家本地的默认配置略有区别,结果改成一致后,并无好转。再怀疑 JVM 的 GC 问题,IO 问题,通过 visualvm
看到并无太大区别。无奈之下,放出大杀器,重启电脑,还是不行。
好吧,这种鸟枪法的扫射并没有那么幸运,一下子就命中目标。只能老老实实的坐下来冷静地分析日志了,在命令行里敲下 ./gradlew clean build --debug
之后,等上煎熬的20分钟,拿到了30MB 的日志。
通过对比正常的3分钟的日志和慢的20分钟的日志,发现其中总有一段似乎和网络请求相关的日志(因为契约测试需要在本地起 Stub Server)重复了好多遍,每一遍差不多耗时10s,粗略估算一下总共怎么也得多出十几分钟来吧。感觉离成功就差最后一步了,但是这究竟是由于什么原因引起的呢?
对比来对比去,也就只有 MacOS 的系统有些差异,有的同学紧跟时代的步伐,始终会把系统升到最新(MacOS Sierra 10.12.6),有的同学则始终会落后几个小版本。仿佛已经看到了黎明的曙光了,然后就是大家在 Stack Overflow 上一通乱翻,大家搜索的关键词也风格迥异。最后,做好事从不留名只写日记的 Summer 姐姐拔得头筹,终于药到病除(🙏🙏🙏)。
解决方案
在命令行中执行
hostname
命令得到本机的 hostname。比如我的机器运行结果是:Max-Peng.local
修改 hosts 文件,在
127.0.0.1
和::1
两行中加上 hostname:
127.0.0.1 localhost Max-Peng.local
::1 localhost Max-Peng.local
对于比较懒的人,也可以这样:
sudo sed -i bak "s^127\.0\.0\.1.*^127.0.0.1 localhost $(hostname)^g" /etc/hosts
sudo sed -i bak "s^::1.*^::1 localhost $(hostname)^g" /etc/hosts
然后再次执行 ./gradlew clean build
,时间马上就从20分钟降到3分钟了,亲测有效!(👏👏👏🎉🎉🎉)至于 Mac 系统升级到 Sierra 后,发生了什么改动,目前还并不是很清楚。
以上部分故事情节纯属虚构,如有雷同,纯属巧合
相关链接
https://thoeni.io/post/macos-sierra-java/
https://macpaw.com/how-to/fix-macos-sierra-problems
https://github.com/spring-projects/spring-boot/issues/7087
https://stackoverflow.com/questions/33289695/inetaddress-getlocalhost-slow-to-run-30-seconds
https://stackoverflow.com/questions/34842698/inetaddress-getcanonicalhostname-returns-ip-instead-of-hostname
https://stackoverflow.com/questions/39636792/jvm-takes-a-long-time-to-resolve-ip-address-for-localhost
https://stackoverflow.com/questions/39636792/jvm-takes-a-long-time-to-resolve-ip-address-for-localhost