motan源码分析八:涉及到底层的客户端调用

之前我们分析了客户端调用服务端的源码,但是没有涉及到通讯层和序列化层,本文将之前讲过的内容做一次串联。

1.上层通过动态代理调用refer的call,每个refer又对应一个nettyclient,下面来看一下nettyclient的调用服务端操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private Response request(Request request, boolean async) throws TransportException {
    Channel channel = null;
 
    Response response = null;
 
    try {
        // return channel or throw exception(timeout or connection_fail)
        channel = borrowObject();//向连接池拿连接
 
        if (channel == null) {
            LoggerUtil.error("NettyClient borrowObject null: url=" + url.getUri() + " "
                    + MotanFrameworkUtil.toString(request));
            return null;
        }
 
        // async request
        response = channel.request(request);//调用channel的request
        // return channel to pool
        returnObject(channel);//归还连接
    } catch (Exception e) {
        LoggerUtil.error(
                "NettyClient request Error: url=" + url.getUri() + " " + MotanFrameworkUtil.toString(request), e);
        //TODO 对特定的异常回收channel
        invalidateObject(channel);//销毁坏的连接
 
        if (e instanceof MotanAbstractException) {
            throw (MotanAbstractException) e;
        } else {
            throw new MotanServiceException("NettyClient request Error: url=" + url.getUri() + " "
                    + MotanFrameworkUtil.toString(request), e);
        }
    }
 
    // aysnc or sync result
    response = asyncResponse(response, async);//处理response
 
    return response;
}

2.nettychannel的request操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public Response request(Request request) throws TransportException {
    int timeout = nettyClient.getUrl().getMethodParameter(request.getMethodName(), request.getParamtersDesc(),
            URLParamType.requestTimeout.getName(), URLParamType.requestTimeout.getIntValue());
    if (timeout <= 0) {
           throw new MotanFrameworkException("NettyClient init Error: timeout(" + timeout + ") <= 0 is forbid.",
                   MotanErrorMsgConstant.FRAMEWORK_INIT_ERROR);
       }
    NettyResponseFuture response = new NettyResponseFuture(request, timeout, this.nettyClient);//创建异步response对象
    this.nettyClient.registerCallback(request.getRequestId(), response);//将此response存入到map,处理完后,会移出
    ChannelFuture writeFuture = this.channel.write(request);//向服务端传递request对象,写之前会进行序列化的操作
 
    boolean result = writeFuture.awaitUninterruptibly(timeout, TimeUnit.MILLISECONDS);//标识是否成功
 
    if (result && writeFuture.isSuccess()) {
        response.addListener(new FutureListener() {//增加response的监听器
            @Override
            public void operationComplete(Future future) throws Exception {
                if (future.isSuccess() || (future.isDone() && ExceptionUtil.isBizException(future.getException()))) {
                    // 成功的调用
                    nettyClient.resetErrorCount();//成功
                } else {
                    // 失败的调用
                    nettyClient.incrErrorCount();//对失败次数+1,如果同一个client连续失败达到所有的连接次数时,标识此client不可用,由心跳管理器负责恢复此client的可用状态
                }
            }
        });
        return response;//返回此response,此response为异步的response,由业务线程接手后续接收的过程
    }
 
    writeFuture.cancel();
    response = this.nettyClient.removeCallback(request.getRequestId());//在map中移出此response
 
    if (response != null) {
        response.cancel();
    }
 
    // 失败的调用
    nettyClient.incrErrorCount();
 
    if (writeFuture.getCause() != null) {
        throw new MotanServiceException("NettyChannel send request to server Error: url="
                + nettyClient.getUrl().getUri() + " local=" + localAddress + " "
                + MotanFrameworkUtil.toString(request), writeFuture.getCause());
    } else {
        throw new MotanServiceException("NettyChannel send request to server Timeout: url="
                + nettyClient.getUrl().getUri() + " local=" + localAddress + " "
                + MotanFrameworkUtil.toString(request));
    }
}

3.异步的response NettyResponseFuture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public Object getValue() {
    synchronized (lock) {
        if (!isDoing()) {
            return getValueOrThrowable();//返回成功值或失败
        }
 
        if (timeout <= 0) {
            try {
                lock.wait();//未接收完毕则一直等待
            } catch (Exception e) {
                cancel(new MotanServiceException("NettyResponseFuture getValue InterruptedException : "
                        + MotanFrameworkUtil.toString(request) + " cost="
                        + (System.currentTimeMillis() - createTime), e));
            }
 
            // don't need to notifylisteners, because onSuccess or
            // onFailure or cancel method already call notifylisteners
            return getValueOrThrowable();
        } else {
            long waitTime = timeout - (System.currentTimeMillis() - createTime);//等待的时间
 
            if (waitTime > 0) {
                for (;;) {
                    try {
                        lock.wait(waitTime);//要么被通知,要么超时
                    } catch (InterruptedException e) {
                    }
 
                    if (!isDoing()) {
                        break;
                    } else {
                        waitTime = timeout - (System.currentTimeMillis() - createTime);
                        if (waitTime <= 0) {
                            break;
                        }
                    }
                }
            }
 
            if (isDoing()) {
                timeoutSoCancel();
            }
        }
        return getValueOrThrowable();
    }
}

本章知识点:

1.motan通过NettyResponseFuture来实现在框架层面异步处理同一笔业务,提升了框架的性能;

2.对于连续失败的client,进行下线操作。

  

posted @   【刘光亮】  阅读(758)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示