第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

dubbo剖析:記一個(gè)異步方法調(diào)用的坑

標(biāo)簽:
Kubernetes

注:文章中的坑出现在2.5.4版本之前,这个坑在2.5.4版本已经得到修复。

一、问题描述


webp

问题描述


场景描述,如上图所示:
客户端远程异步调用服务A服务A在处理客户端请求的过程中需要远程同步调用服务B服务A服务B的响应中取数据时,得到的是 null !!!


二、原因分析

webp

RPC请求响应参数传递过程

2.1 Client的请求发送过程

1)Client在发起RPC调用请求前,将请求参数构建成 RpcInvocation ;
2)Client在发起RPC调用请求前,会经过Filter处理:

  • ConsumerContextFilter会将请求信息,如invoker、invocation、Address等,写入 RpcContext

@Activate(group = Constants.CONSUMER, order = -10000)public class ConsumerContextFilter implements Filter {    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        RpcContext.getContext()
                .setInvoker(invoker)
                .setInvocation(invocation)
                .setLocalAddress(NetUtils.getLocalHost(), 0)
                .setRemoteAddress(invoker.getUrl().getHost(),
                        invoker.getUrl().getPort());        if (invocation instanceof RpcInvocation) {
            ((RpcInvocation) invocation).setInvoker(invoker);
        }        try {            return invoker.invoke(invocation);
        } finally {
            RpcContext.getContext().clearAttachments();
        }
    }

}

3)Client在发起RPC调用请求前,会经过AbstractInvoker:

  • AbstractInvoker会将RpcContext中的attachments内容写入到 RpcInvocation,以实现附加参数的传递;

        Map<String, String> context = RpcContext.getContext().getAttachments();        if (context != null) {
            invocation.addAttachmentsIfAbsent(context);
        }
  • AbstractInvoker会从RPC请求参数URLASYNC_KEY的值,并设置到RpcInvocationattachment中;

       if (getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false)) {
           invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
       }

4)Client在发起RPC调用请求时,会经过DubboInvoker:

  • DubboInvoker会优先从RpcInvocationattachment中获取并判断ASYNC_KEY是否为true,以实现消费端的异步调用;

    public static boolean isAsync(URL url, Invocation inv) {        boolean isAsync;        //如果Java代码中设置优先.
        if (Boolean.TRUE.toString().equals(inv.getAttachment(Constants.ASYNC_KEY))) {
            isAsync = true;
        } else {
            isAsync = url.getMethodParameter(getMethodName(inv), Constants.ASYNC_KEY, false);
        }        return isAsync;
    }

5)Client在发起RPC调用请求时,会将RpcInvocation作为调用参数传递给服务提供方:

  • RpcInvocation中的扩展属性attachments,实现了请求调用扩展信息传递的功能;

2.2 服务A的请求接收和执行过程

1)服务端在接收到RPC请求,调用真正实现接口前,会经过ContextFilter

  • ContextFilter会将请求信息,如invoker、invocation、Address等,写入 RpcContext

  • ContextFilter会将请求参数RpcInvocationattachments扩展信息取出,过滤掉某些特定KEY之后,将其余扩展属性设置到当前RpcContextattachments中;

        Map<String, String> attachments = invocation.getAttachments();        if (attachments != null) {
            attachments = new HashMap<String, String>(attachments);
            attachments.remove(Constants.PATH_KEY);
            attachments.remove(Constants.GROUP_KEY);
            attachments.remove(Constants.VERSION_KEY);
            attachments.remove(Constants.DUBBO_VERSION_KEY);
            attachments.remove(Constants.TOKEN_KEY);
            attachments.remove(Constants.TIMEOUT_KEY);
            attachments.remove(Constants.ASYNC_KEY);//清空消费端的异步参数,2.5.4版本才新加进去的
        }
        RpcContext.getContext()
                .setInvoker(invoker)
                .setInvocation(invocation)
                .setAttachments(attachments)
                .setLocalAddress(invoker.getUrl().getHost(),
                        invoker.getUrl().getPort());

其中attachments.remove(Constants.ASYNC_KEY);//清空消费端的异步参数 这行代码是在dubbo的2.5.4版本才加进去的,也就是之前的版本中并没有这行代码。

2)在2.5.4版本之前,对于Client发来的异步调用请求,其RpcInvocation参数中包含了ASYNC=trueattachment扩展信息:

  • 此时ASYNC=true的这个扩展信息就会被设置到服务A的RpcContext的扩展属性中;

  • 服务A处理RPC调用,执行实际接口实现类的逻辑时,因为依赖的服务B,所以会继续发送RPC调用请求给服务B

  • 服务A调用服务B时,服务ARpcContext的扩展属性会被写入到A -> BRpcInvocation参数中,这就导致ASYNC=true的扩展属性参数被误传到A -> BRpcInvocation参数中,进而导致在服务A发起RPC请求调用时触发了错误的异步调用逻辑;

  • 此时服务A获取到的RPC执行结果RpcResult的内容当然是个空;

else if (isAsync) {   //1. 异步,有返回值
                ResponseFuture future = currentClient.request(inv, timeout);
                RpcContext.getContext().setFuture(new FutureAdapter<Object>(future));                return new RpcResult();
            } else {    //3. 异步->同步(默认的通信方式)
                RpcContext.getContext().setFuture(null);                return (Result) currentClient.request(inv, timeout).get();
            }

以上就是这个坑的产生原因

三、解决方法

自己写了个Filter,添加到Dubbo服务提供方接收请求后、实际处理请求前的Filter执行链中。
从请求参数URL中解析出ASYNC扩展参数标识,而不依赖RpcInvocation中的值。

@Activate(group = {Constants.PROVIDER}, order = -999)public class DubboSyncFilter implements Filter {    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {        //避免RpcContext透传,使用配置文件的async
        boolean isAsync = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY, false);
        RpcContext.getContext().setAttachment(Constants.ASYNC_KEY, String.valueOf(isAsync));        return invoker.invoke(invocation);
    }
}



作者:益文的圈
链接:https://www.jianshu.com/p/f814fa6abc82


點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫(xiě)下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶(hù)
支付方式
打開(kāi)微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專(zhuān)欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢(xún)優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消