坑爹的InetAddress getLocalHost函数
今天在跑dubbo 的 DemoService 2.5.4-SNAPSHOT版本的时候,遇到到一个奇怪的问题。consumer怎么都连接不上provider的服务。最后才发现是由于dubbo自 己实现的检测本地IP地址代码不够强壮造成的。你这里的provider实际上是运行在A地址上,但是dubbo检测到本地的IP地址是B,然后他在 zookeeper上注册自己的服务地址的时候,用的是这个B这个IP地址,那么当consumer连接到zookeeper上的时候,查询到 DemoService是在B上的,显然这个IP地址上并没有这样的dubbo服务,那么这个consumer就肯定不能成功。
为什么dubbo检测本地IP地址的结果是错的,因为dubbo检测本地IP地址的策略是先调用InetAddress.getLocalHost,如果
该方法返回一个合法的地址,则直接认为是本地的IP地址,否则会枚举本地所有网卡,并返回第一个合法的IP地址作为本地地址。
坑爹的就是InetAddress.getLocalHost返回了一个错误的IP地址。为什么这个函数会返回一个错误的地址,因为这个函数的原理是通过
获取本机的hostname,然后对此hostname做解析,从而获取IP地址的。那么问题来了,如果在本机的/etc/hosts文件里对这个主机名
指向了一个错误的IP地址,那么InetAddress.getLocalHost就会返回这个错误的IP地址。当然如果你的hostname是到DNS
去解析的,碰巧DNS上的信息也是错的,也同样是悲惨结局。
遇到同样问题的人,可以先检查下hosts文件的设置里面A地址指向哪里了,然后看一下DNS解析出的地址。当然如果dubbo的代码检查一下,这个返回
的地址,是不是真的是本机的IP地址,也不会出现这个问题了,归根结底还是dubbo的卡发人员太相信InetAddress.getLocalHost
了,这货自己应该确保不会出现这样的乌龙事件的。你返回一个不是本机的IP地址作为本机的IP地址,这个在语义上就错误了。不管你用了多么愚蠢的算法,结
果就是不应该返回一个不是本地的IP地址作为本地的地址,不是吗?否则还叫什么狗屁get local host!!!
我为什么说InetAddress.getLocalHost的算法是愚蠢的,是因为这个尽管可能会被hosts文件和DNS误导,但是显然这两个地方都
不是本机IP地址的权威获取处,权威获取处是网卡本身的配置信息。即便你要使用一个不靠谱来源的信息,你至少跟本机的网卡地址做一下校验嘛!如果你实在是
不知道怎么获取,抛出个异常说明一下你的无能为力,大家也是可以接受的嘛!犯不着给个错误的信息,让这么多人掉坑里,浪费时间,对不对?
最后,dubbo检测本地地址的代码位于:
dubbo-common/src/main/java/com/alibaba/dubbo/common/utils/NetUtils.java里的getLocalAddress函数,可以看一下。