同事在本地启动dubbo服务时,发现自己的注册到zk上的dubbo 地址为:
dubbo://192.168.20.100:20880/com.xxx.xxx...
而其实际的ip 地址是192.168.10.60,他换了好几次不同的版本号启动应用,发现始终不是正常的ip地址,于是,开始了这次排插过程~~,看解决方案可以直接到三。
1.首先,我们看下同事自身配置的dubbo.xml,里面的 dubbo:provider和dubbo.protocol均无强制指定的URL,排除是自身dubbo配置文件的问题
2.我们开始看dubbo 里面是怎么初始化提供者的url,由于dubbo 中存在ServiceBean实现了InitializingBean接口,因此在Spring示例化这个bean后会调用里面的 afterPropertiesSet 方法:
public void afterPropertiesSet() throws Exception {
//前面省略部分代码,这些代码是在判断配置项缺失时的处理
......
// 处理完后暴露provider
if (!isDelay()) {
export();
}
}
3.接着我们到export方法里面看,它做了什么,它在 ServiceConfig 中:
public synchronized void export() {
// 这个代码段很好理解,就是 赋值 export和delay
if (provider != null) {
if (export == null) {
export = provider.getExport();
}
if (delay == null) {
delay = provider.getDelay();
}
}
//如果不需要暴露接口,则不进行后续处理
if (export != null && ! export.booleanValue()) {
return;
}
//是否有 延时暴露?有的话 就sleep下再暴露
if (delay != null && delay > 0) {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(delay);
} catch (Throwable e) {
}
//重点的暴露的方法
doExport();
}
});
thread.setDaemon(true);
thread.setName("DelayExportServiceThread");
thread.start();
} else {
//重点的暴露的方法
doExport();
}
}
4.我们着重看下doExport方法:
protected synchronized void doExport() {
//由于代码过长,省略判断和检查部分代码,有兴趣可以到参考文档里面进行查看
......
//检查每个配置,进去看了下,没有初始化host地址
checkApplication();
checkRegistry();
checkProtocol();
//关联 到provider
appendProperties(this);
checkStubAndMock(interfaceClass);
if (path == null || path.length() == 0) {
path = interfaceName;
}
//重点的 暴露urls
doExportUrls();
}
5.doExportUrls:
private void doExportUrls() {
List registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols){
//我们直接看这一行
doExportUrlsFor1Protocol(protocolConfig,registryURLs);
}
}
6.doExportUrlsFor1Protocol
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List registryURLs) {
//省略不关键的代码
......
// 从protocol的配置项和provider中获得host,我们没有配置,自然获得不到
String host = protocolConfig.getHost();
if (provider != null && (host == null || host.length() == 0)) {
host = provider.getHost();
}
boolean anyhost = false;
......
//当host 为null或非法或localost等符合dubbo NetUtil限制的时候
try{
// 第一步、这是获取host 的重点
host = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
logger.warn(e.getMessage(), e);
}
......
//若第一步获取的host 还是不符合规则的,则对registryURLs进行操作处理,这个本次不讲
......
}
7.InetAddress这个里面在搞什么的呢?
public static InetAddress getLocalHost() throws UnknownHostException {
......
//省略其他非重点,我们看这一行,根据name获得address
try {
localAddrs = InetAddress.getAddressesFromNameService(local, null);
}
......
}
我们接着进去看
private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr) throws UnknownHostException{
......
//此处获得 addresses
addresses = nameService.lookupAllHostAddr(host);
......
}
8.一般来说,我们都会马上到这个实现类里面去,可怎么看都发现断点进不来,什么原因呢?在这个方法之前,createNSProvider 已经被执行了,里面对nameService 的方法进行了重写
private static NameService createNSProvider(String provider) {
......
//此处new
nameService = new NameService() {
public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException{
return impl.lookupAllHostAddr(host);
}
public String getHostByAddr(byte[] addr) throws UnknownHostException {
return impl.getHostByAddr(addr);
}
};
......
}
lookupAllHostAddr 被Inet6AddressImpl和Inet4AddressImpl 实现,因此返回是ipv4和ipv6的地址。
分析:
- 而其ipv4返回的是错误的ip,且传入的host 名字很大众(”admins-MacBook-pro”),我们怀疑是否是DNS 解析的问题,相同的host 名称在同个局域网,解析到别的机子上的ip。
解决方案:
我们修改了 /etc/resolv.conf DNS 的配置,改成了
//重要
nameserver 8.8.8.8
即正常使用了
在/etc/hosts中加入机器名 公网IP,比如:
admins-MacBook-pro 192.168.10.60
或者 在dubbo.xml中加入主机地址的配置
"192.168.10.60"/>
或者在每个provider中绑定host
"192.168.10.60"/>
或者在JVM中指定host
-Ddubbo.properties.file=xxx.properties
然后 此properties中写入 host
http://dubbo.io/User+Guide-zh.htm
http://blog.csdn.net/flashflight/article/details/44473617
http://blog.csdn.net/lele2426/article/details/39530409#4483369
http://www.cnblogs.com/leo-li-3046/p/5702479.html