dubbo分析-netty 实现同步通信

说明

dubbo默认的protocol 是 DubboProtocol,默认的远程通信采用netty(不是netty4),默认的codec2是 hessian2。

这里我们来分析一下 dubbo实现 netty 异步转同步的细节。

# ExchangeChannel

上篇我们说过 dubbo 的上层通信封装在exchangeServer 和 exchangeClient。查看源码发现 发送消息的channel是ExchangeChannel,下面 查看HeaderExchangeChannel 的实现。

 public ResponseFuture request(Object request, int timeout) throws RemotingException {
    if (closed) {
        throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
    }
    // create request.
    Request req = new Request();
    req.setVersion("2.0.0");
    req.setTwoWay(true);
    req.setData(request);
    DefaultFuture future = new DefaultFuture(channel, req, timeout);
    try {
        channel.send(req);
    } catch (RemotingException e) {
        future.cancel();
        throw e;
    }
    return future;
}

通过上面代码 我们发现 其实是生成了一个DefaultFuture结果。直接调用 future.get 可以同步等待结果。

public Object get(int timeout) throws RemotingException {
    if (timeout <= 0) {
        timeout = Constants.DEFAULT_TIMEOUT;
    }
    if (!isDone()) {
        long start = System.currentTimeMillis();
        lock.lock();
        try {
            while (!isDone()) {
                done.await(timeout, TimeUnit.MILLISECONDS);
                if (isDone() || System.currentTimeMillis() - start > timeout) {
                    break;
                }
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
        if (!isDone()) {
            throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
        }
    }
    return returnFromResponse();
}

阻塞 主要利用

private final Lock lock = new ReentrantLock();
private final Condition done = lock.newCondition();

当有消息到来时候调用 done.signal()

具体来说,调用 exchangechannel的request方法 生成 Request 对象req,s这里 每
req有一唯一 的id。然后 DefaultFuture有以下 qin两个静态变量,保存了
reqId 到 DefaultFuture 的映射。

private static final Map<Long, Channel> CHANNELS = new ConcurrentHashMap<Long, Channel>();

private static final Map<Long, DefaultFuture> FUTURES = new ConcurrentHashMap<Long, DefaultFuture>();

当 netty 收到消息,会调用 com.alibaba.dubbo.remoting.exchange.support.DefaultFuture#received 静态方法。

public static void received(Channel channel, Response response) {
    try {
        DefaultFuture future = FUTURES.remove(response.getId());
        if (future != null) {
            future.doReceived(response);
        } else {
            logger.warn("The timeout response finally returned at "
                    + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
                    + ", response " + response
                    + (channel == null ? "" : ", channel: " + channel.getLocalAddress()
                    + " -> " + channel.getRemoteAddress()));
        }
    } finally {
        CHANNELS.remove(response.getId());
    }
}

因为 req和response 都有唯一 id对应起来,所以 很容易转成 同步。

调试 dubbo源码 demo使用multicast注册中心时,遇到provider端启动失败 报错如下:

java.net.ConnectException: 网络不可达 (connect failed)
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at com.alibaba.dubbo.config.ServiceConfig.findConfigedHosts(ServiceConfig.java:577)
    at com.alibaba.dubbo.config.ServiceConfig.doExportUrlsFor1Protocol(ServiceConfig.java:469)
    at com.alibaba.dubbo.config.ServiceConfig.doExportUrls(ServiceConfig.java:357)
    at com.alibaba.dubbo.config.ServiceConfig.doExport(ServiceConfig.java:316)
    at com.alibaba.dubbo.config.ServiceConfig.export(ServiceConfig.java:215)
    at com.alibaba.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:121)
    at com.alibaba.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:50)

调试 发现 findConfigedHosts hostToBind = InetAddress.getLocalHost().getHostAddress();这行 拿到 的hostToBind是 127.0.0.1 所以不能广播 。

参考文章

http://dubbo.apache.org/books/dubbo-user-book/references/registry/multicast.html
http://www.cnblogs.com/ghj1976/p/5276452.html
https://blog.csdn.net/raintungli/article/details/8191701

解决办法:

我用的 是Ubuntu系统 ,
sudo vi /etc/hosts

 127.0.0.1       localhost
 #127.0.1.1       tao-TM1604
 192.168.3.3      tao-TM1604

注释 第二行 添加 第三行 192.168.3.是我局域网ip

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值