dubbo注册异常记录

昨天一个同事说按下面链接,最新demo无法启动

Dubbo,Spring,Zookeeper,Maven试水简单Demo:测试

我试了一下,的确是错误,感觉端口占用了,要么注册地址有误

com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method sayHello in the service com.alibaba.dubbo.demo.DemoService. Tried 3 times of the providers [0.0.7.226:20880] (1/1) from the registry 127.0.0.1:2181 on the consumer 0.0.7.226 using the dubbo version . Last error is: Failed to invoke remote method: sayHello, provider: dubbo://0.0.7.226:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=42712&qos.port=33333&register.ip=0.0.7.226&remote.timestamp=1554056704529&side=consumer&timestamp=1554056712432, cause: message can not send, because channel is closed . url:dubbo://0.0.7.226:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&codec=dubbo&dubbo=2.0.2&generic=false&heartbeat=60000&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=42712&qos.port=33333&register.ip=0.0.7.226&remote.timestamp=1554056704529&side=consumer&timestamp=1554056712432
	at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:109)
	at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:234)
	at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:75)
	at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)
	at com.alibaba.dubbo.common.bytecode.proxy0.sayHello(proxy0.java)
	at com.alibaba.dubbo.demo.consumer.Consumer.main(Consumer.java:35)
Caused by: com.alibaba.dubbo.remoting.RemotingException: message can not send, because channel is closed . url:dubbo://0.0.7.226:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&codec=dubbo&dubbo=2.0.2&generic=false&heartbeat=60000&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=42712&qos.port=33333&register.ip=0.0.7.226&remote.timestamp=1554056704529&side=consumer&timestamp=1554056712432
	at com.alibaba.dubbo.remoting.transport.AbstractClient.send(AbstractClient.java:263)
	at com.alibaba.dubbo.remoting.transport.AbstractPeer.send(AbstractPeer.java:53)
	at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.request(HeaderExchangeChannel.java:116)
	at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeClient.request(HeaderExchangeClient.java:90)
	at com.alibaba.dubbo.rpc.protocol.dubbo.ReferenceCountExchangeClient.request(ReferenceCountExchangeClient.java:83)
	at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:95)
	at com.alibaba.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:154)
	at com.alibaba.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:77)
	at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
	at com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:54)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
	at com.alibaba.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:49)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)
	at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56)
	at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:78)
	... 5 more

将zookeeper的地址都设置为本地

   <!-- use multicast registry center to export service -->
   <!-- dubbo:registry address="multicast://224.5.6.7:1234"/ -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>

   <!-- use dubbo protocol to export service on port 20880 -->
   <dubbo:protocol name="dubbo" port="20880"/>

先启动provider

lihui@2018  ~  lsof -i:20880
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
java    41918 lihui   61u  IPv6 0xfdabfa92d1715e4d      0t0  TCP *:20880 (LISTEN)

看看zk注册情况

✘ lihui@2018  ~  zkCli
Connecting to localhost:2181
Welcome to ZooKeeper!
JLine support is enabled

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] ls
[zk: localhost:2181(CONNECTED) 1] ls /
[dubbo, zookeeper]
[zk: localhost:2181(CONNECTED) 2] ls /zookeeper
[quota]
[zk: localhost:2181(CONNECTED) 3] ls /zookeeper/quota
[]
[zk: localhost:2181(CONNECTED) 4] ls /zookeeper
[quota]
[zk: localhost:2181(CONNECTED) 5] ls /dubbo
[com.maoxiaomeng.service.HelloService, com.alibaba.dubbo.demo.DemoService]

这就奇怪了,再次看看provider的执行结果

[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZooKeeper: Client environment:os.name=Mac OS X
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZooKeeper: Client environment:os.arch=x86_64
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZooKeeper: Client environment:os.version=10.14.4
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZooKeeper: Client environment:user.name=lihui
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZooKeeper: Client environment:user.home=/Users/lihui
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZooKeeper: Client environment:user.dir=/Users/lihui/caocao/dubbo/incubator-dubbo
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZooKeeper: Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=60000 watcher=org.apache.curator.ConnectionState@1ff4931d
[01/04/19 02:11:50:050 CST] main-SendThread(127.0.0.1:2181)  INFO zookeeper.ClientCnxn: Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZookeeperRegistry:  [DUBBO] Register: dubbo://0.0.7.226:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=42519&side=provider&timestamp=1554055910026, dubbo version: , current host: 0.0.7.226
[01/04/19 02:11:50:050 CST] main-SendThread(127.0.0.1:2181)  INFO zookeeper.ClientCnxn: Socket connection established to 127.0.0.1/127.0.0.1:2181, initiating session
[01/04/19 02:11:50:050 CST] main-SendThread(127.0.0.1:2181)  INFO zookeeper.ClientCnxn: Session establishment complete on server 127.0.0.1/127.0.0.1:2181, sessionid = 0x100081863b90013, negotiated timeout = 40000
[01/04/19 02:11:50:050 CST] main-EventThread  INFO state.ConnectionStateManager: State change: CONNECTED
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZookeeperRegistry:  [DUBBO] Subscribe: provider://0.0.7.226:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=42519&side=provider&timestamp=1554055910026, dubbo version: , current host: 0.0.7.226
[01/04/19 02:11:50:050 CST] main  INFO zookeeper.ZookeeperRegistry:  [DUBBO] Notify urls for subscribe url provider://0.0.7.226:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=42519&side=provider&timestamp=1554055910026, urls: [empty://0.0.7.226:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=42519&side=provider&timestamp=1554055910026], dubbo version: , current host: 0.0.7.226

看这个注册的host不对,手动配置provider的host

   <!-- use multicast registry center to export service -->
   <!-- dubbo:registry address="multicast://224.5.6.7:1234"/ -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>

   <!-- use dubbo protocol to export service on port 20880 -->
   <dubbo:protocol host="127.0.0.1" name="dubbo" port="20880"/>

还是不行,直接看下源码,错误信息

首先是current host不对

private String appendContextMessage(String msg) {
    return " [DUBBO] " + msg + ", dubbo version: " + Version.getVersion() + ", current host: " + NetUtils.getLocalHost();
}

直接看调用关系,getLocalHost

public static String getLocalHost() {
    InetAddress address = getLocalAddress();
    return address == null ? LOCALHOST : address.getHostAddress();
}

接着getLocalAddress

/**
 * Find first valid IP from local network card
 *
 * @return first valid local IP
 */
public static InetAddress getLocalAddress() {
    if (LOCAL_ADDRESS != null)
        return LOCAL_ADDRESS;
    InetAddress localAddress = getLocalAddress0();
    LOCAL_ADDRESS = localAddress;
    return localAddress;
}

查看getLocalAddress0

private static InetAddress getLocalAddress0() {
    InetAddress localAddress = null;
    try {
        localAddress = InetAddress.getLocalHost();
        if (isValidAddress(localAddress)) {
            return localAddress;
        }
    } catch (Throwable e) {
        logger.warn("Failed to retrieving ip address, " + e.getMessage(), e);
    }
    try {
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        if (interfaces != null) {
            while (interfaces.hasMoreElements()) {
                try {
                    NetworkInterface network = interfaces.nextElement();
                    Enumeration<InetAddress> addresses = network.getInetAddresses();
                    if (addresses != null) {
                        while (addresses.hasMoreElements()) {
                            try {
                                InetAddress address = addresses.nextElement();
                                if (isValidAddress(address)) {
                                    return address;
                                }
                            } catch (Throwable e) {
                                logger.warn("Failed to retrieving ip address, " + e.getMessage(), e);
                            }
                        }
                    }
                } catch (Throwable e) {
                    logger.warn("Failed to retrieving ip address, " + e.getMessage(), e);
                }
            }
        }
    } catch (Throwable e) {
        logger.warn("Failed to retrieving ip address, " + e.getMessage(), e);
    }
    logger.error("Could not get local host ip address, will use 127.0.0.1 instead.");
    return localAddress;
}

注释挺多,顺便看看

/**
 * Returns the address of the local host. This is achieved by retrieving
 * the name of the host from the system, then resolving that name into
 * an {@code InetAddress}.
 *
 * <P>Note: The resolved address may be cached for a short period of time.
 * </P>
 *
 * <p>If there is a security manager, its
 * {@code checkConnect} method is called
 * with the local host name and {@code -1}
 * as its arguments to see if the operation is allowed.
 * If the operation is not allowed, an InetAddress representing
 * the loopback address is returned.
 *
 * @return     the address of the local host.
 *
 * @exception  UnknownHostException  if the local host name could not
 *             be resolved into an address.
 *
 * @see SecurityManager#checkConnect
 * @see java.net.InetAddress#getByName(java.lang.String)
 */
public static InetAddress getLocalHost() throws UnknownHostException {

    SecurityManager security = System.getSecurityManager();
    try {
        String local = impl.getLocalHostName();

        if (security != null) {
            security.checkConnect(local, -1);
        }

        if (local.equals("localhost")) {
            return impl.loopbackAddress();
        }

        InetAddress ret = null;
        synchronized (cacheLock) {
            long now = System.currentTimeMillis();
            if (cachedLocalHost != null) {
                if ((now - cacheTime) < maxCacheTime) // Less than 5s old?
                    ret = cachedLocalHost;
                else
                    cachedLocalHost = null;
            }

            // we are calling getAddressesFromNameService directly
            // to avoid getting localHost from cache
            if (ret == null) {
                InetAddress[] localAddrs;
                try {
                    localAddrs =
                        InetAddress.getAddressesFromNameService(local, null);
                } catch (UnknownHostException uhe) {
                    // Rethrow with a more informative error message.
                    UnknownHostException uhe2 =
                        new UnknownHostException(local + ": " +
                                                 uhe.getMessage());
                    uhe2.initCause(uhe);
                    throw uhe2;
                }
                cachedLocalHost = localAddrs[0];
                cacheTime = now;
                ret = localAddrs[0];
            }
        }
        return ret;
    } catch (java.lang.SecurityException e) {
        return impl.loopbackAddress();
    }
}

其实从这个方法命名基本知道获取IP地址的流程

private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
    throws UnknownHostException
{
    InetAddress[] addresses = null;
    boolean success = false;
    UnknownHostException ex = null;

    // Check whether the host is in the lookupTable.
    // 1) If the host isn't in the lookupTable when
    //    checkLookupTable() is called, checkLookupTable()
    //    would add the host in the lookupTable and
    //    return null. So we will do the lookup.
    // 2) If the host is in the lookupTable when
    //    checkLookupTable() is called, the current thread
    //    would be blocked until the host is removed
    //    from the lookupTable. Then this thread
    //    should try to look up the addressCache.
    //     i) if it found the addresses in the
    //        addressCache, checkLookupTable()  would
    //        return the addresses.
    //     ii) if it didn't find the addresses in the
    //         addressCache for any reason,
    //         it should add the host in the
    //         lookupTable and return null so the
    //         following code would do  a lookup itself.
    if ((addresses = checkLookupTable(host)) == null) {
        try {
            // This is the first thread which looks up the addresses
            // this host or the cache entry for this host has been
            // expired so this thread should do the lookup.
            for (NameService nameService : nameServices) {
                try {
                    /*
                     * Do not put the call to lookup() inside the
                     * constructor.  if you do you will still be
                     * allocating space when the lookup fails.
                     */

                    addresses = nameService.lookupAllHostAddr(host);
                    success = true;
                    break;
                } catch (UnknownHostException uhe) {
                    if (host.equalsIgnoreCase("localhost")) {
                        InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
                        addresses = local;
                        success = true;
                        break;
                    }
                    else {
                        addresses = unknown_array;
                        success = false;
                        ex = uhe;
                    }
                }
            }

            // More to do?
            if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) {
                // Find it?
                int i = 1;
                for (; i < addresses.length; i++) {
                    if (addresses[i].equals(reqAddr)) {
                        break;
                    }
                }
                // Rotate
                if (i < addresses.length) {
                    InetAddress tmp, tmp2 = reqAddr;
                    for (int j = 0; j < i; j++) {
                        tmp = addresses[j];
                        addresses[j] = tmp2;
                        tmp2 = tmp;
                    }
                    addresses[i] = tmp2;
                }
            }
            // Cache the address.
            cacheAddresses(host, addresses, success);

            if (!success && ex != null)
                throw ex;

        } finally {
            // Delete host from the lookupTable and notify
            // all threads waiting on the lookupTable monitor.
            updateLookupTable(host);
        }
    }

    return addresses;
}

最终是调用了这个接口,但是我本地是没有的

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package sun.net.spi.nameservice;

import java.net.InetAddress;
import java.net.UnknownHostException;

public interface NameService {
    InetAddress[] lookupAllHostAddr(String var1) throws UnknownHostException;

    String getHostByAddr(byte[] var1) throws UnknownHostException;
}

但是根据整个流程,已经是库函数InetAddress.getLocalHost()不兼容我本地的环境,无法正确获取IP地址,不用继续看了,具体的解决方法可以查看下帖子:

Dubbo融合Nacos注册中心

发表评论