接触 dubbo 有一段时间,特别想拿 dubbo 和 tomcat 比较一番。

tomcat 是 web 服务器,提供 http 服务,当 tomcat 收到浏览器发送的 http 请求时,根据 url 查询对应的 servlet 处理请求,然后发送 http 响应。

dubbo 是 rpc 框架,提供 dubbo 服务,当 provider 收到 consumer 发送的请求后,解析请求,找到对应的接口服务类(原始接口服务类的外面裹着代理和一系列 filter),处理请求,发送响应。

初看上去,很相同,仔细一想,却也大不同。

相同点:
tomcat 是 http 服务器,基于 tcp 协议,dubbo 框架支持多种协议(dubbo, hessian 等),常用的 dubbo 协议也是基于 tcp 协议。即 dubbo 的 consumer 和 provider 首先要建立 tcp 连接,然后才能发送数据。

不同点:
(1)http 客户端如何发送请求?首先建立 tcp 连接,然后发送 http 请求报文,接着等待 http 响应报文,http 报文都是明文字符串。
dubbo 客户端如何发送请求呢?正常情况下,provider 会暴露服务,consumer 去 refer 服务获得代理,然后通过代理调用服务,这里有很长的一个调用栈,底层也是 consumer 发送 request,等待 provider 的 response,但是这里的 request 和 response 都是序列化的 java 对象。
(2)http 客户端发送请求,必然会收到对应的 http 响应,而 dubbo consumer 发送请求时可以设置为 oneway,即不需要响应,则 dubbo provider 不会发送响应,请求也可以设置为同步或者异步,不管同步还是异步都是有响应的。

最后看看,dubbo provider 如何根据请求定位到具体的服务实现类,调用栈如下图:

Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException{
    boolean isCallBackServiceInvoke = false;
    boolean isStubServiceInvoke = false;
    int port = channel.getLocalAddress().getPort();
    String path = inv.getAttachments().get(Constants.PATH_KEY);
    //如果是客户端的回调服务.
    isStubServiceInvoke = Boolean.TRUE.toString().equals(inv.getAttachments().get(Constants.STUB_EVENT_KEY));
    if (isStubServiceInvoke){
        port = channel.getRemoteAddress().getPort();
    }
    //callback
    isCallBackServiceInvoke = isClientSide(channel) && !isStubServiceInvoke;
    if(isCallBackServiceInvoke){
        path = inv.getAttachments().get(Constants.PATH_KEY)+"."+inv.getAttachments().get(Constants.CALLBACK_SERVICE_KEY);
        inv.getAttachments().put(IS_CALLBACK_SERVICE_INVOKE, Boolean.TRUE.toString());
    }
    // serviceKey = "com.zhang.HelloService:20880"
    String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY));

    DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);
    
    if (exporter == null)
        throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + exporterMap.keySet() + ", may be version or group mismatch " + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + inv);

    return exporter.getInvoker();
}

主要是根据 serviceKey 查找 exporter。

posted on 2018-06-15 21:42  偶尔发呆  阅读(2805)  评论(0编辑  收藏  举报