[apache/dubbo]在不改变消费者代码的前提下,生产者怎样获取消费者的applicationName,ip?

2024-07-31 685 views
6

在不改变消费者代码的前提下,生产者怎样获取消费者的applicationName,ip?

回答

8

dubbo有现成的api开放出来,如下 //获取远程ip RpcContext context = RpcContext.getContext(); String remoteHost = context.getRemoteHost(); System.out.println(remoteHost); //应用名 String applicationName= context.getUrl().getParameter("application"); System.out.println(applicationName); 通过获取RpcContext的实例,该上下文实例,在当前线程内,是一个全局变量。

1

我知道有这个api,但是这个api在生产者方调用只会获取生产者的信息。remoteHost和 aplicationName都是生产者的,不是消费者的。

6

` @Override protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException { RpcInvocation inv = (RpcInvocation) data;

    out.writeUTF(inv.getAttachment(Constants.DUBBO_VERSION_KEY, DUBBO_VERSION));
    out.writeUTF(inv.getAttachment(Constants.PATH_KEY));
    out.writeUTF(inv.getAttachment(Constants.VERSION_KEY));

    out.writeUTF(inv.getMethodName());
    out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes()));
    Object[] args = inv.getArguments();
    if (args != null)
    for (int i = 0; i < args.length; i++){
        out.writeObject(encodeInvocationArgument(channel, inv, i));
    }
    out.writeObject(inv.getAttachments());
}`

看了dubbo源码,在DubboCodec类的encodeRequestData中,压根就没有向生产者发送自己的applicationName 和ip. 所以生产者是获取不到的

8

applicationName真有问题; 不过IP是没有问题。 两台服务器之间通信,IP在理论上是互知的。并不需要客户端显式传值;如果不考虑多级转发的问题,服务端获取的客户端的地址,就是消费者的;实际上,多级转发比如A调用B,B调用C,这和用户通过浏览器经过多级代理,不一样;这里,更多滴看作是服务端之间的调用,IP控制的话,只对上一级负责就可以了。当然,要看你自己的实际需求了。

3

ip地址:RpcContext.getRemoteAddress() appName: 目前dubbo框架层面是没有传递appname到provider端的,需要使用者通过attachments等自己传递

7

ip可以,不过ip不是通过业务参数传过去的,是通过通讯层的机制实现的。applicationName是不行的。 不知道为什么dubbo不传这些参数,然道真的是为了实现所谓的无状态,透明?

2

需要在消费者端自己实现一个 Filter

@Activate(group = Constants.CONSUMER, order = -10000)
public class DubboContextFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String application = RpcContext.getContext().getUrl().getParameter("application");
        RpcContext.getContext().setAttachment("application", application);
        return invoker.invoke(invocation);
    }
}

需要配置声明一下这个filter(com.alibaba.dubbo.rpc.Filter)以遍能扫描到:

image

然后配置一下filter:

<dubbo:consumer application="pdl-gateway" layer="gateway" filter="dubboContextFilter" />

然后再服务端就可以通过RpcContext.getContext().getAttachment("application")拿到了

2

思路:provider端的filter中扩展获取

途径:

  1. IP可以通过RemoteHost直接获取
  2. 应用名是无法直接获取的,需要consumer传入,所以consumer也需要扩展一个filter。

以下是一个完整可用的,记录ip,appName,耗时的一对filter,请自行取用

@Activate(group = Constants.CONSUMER)
public class LogTraceConsumerFilter implements Filter {

    private static final Logger LOG = LoggerFactory.getLogger(LogTraceConsumerFilter.class);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        //手动设置consumer的应用名进attachment
        String application = invoker.getUrl().getParameter(Constants.APPLICATION_KEY);
        if (application != null) {
            RpcContext.getContext().setAttachment("dubboApplication", application);
        }

        Result result = null;
        String serverIp = null;
        long startTime = System.currentTimeMillis();
        try {
            result = invoker.invoke(invocation);
            serverIp = RpcContext.getContext().getRemoteHost();//这次返回结果是哪个ip
            return result;
        } finally {
            Throwable throwable = (result == null) ? null : result.getException();
            Object resultObj = (result == null) ? null : result.getValue();
            long costTime = System.currentTimeMillis() - startTime;
            LOG.info("[TRACE] Call {}, {}.{}() param:{}, return:{}, exception:{}, cost:{} ms!", serverIp, invoker.getInterface(), invocation.getMethodName(), invocation.getArguments(), resultObj, throwable, costTime);
        }
    }
}
@Activate(group = Constants.PROVIDER)
public class LogTraceProviderFilter implements Filter {

    private static final Logger LOG = LoggerFactory.getLogger(LogTraceProviderFilter.class);

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        //上游如果手动设置了consumer的应用名进attachment,则取出来打印
        String clientIp = RpcContext.getContext().getRemoteHost();//这次请求来自哪个ip
        String application = RpcContext.getContext().getAttachment("dubboApplication");
        String from = clientIp;
        if (!StringUtils.isEmpty(application)) {
            from = application+"("+clientIp+")";
        }

        LOG.info("[Trace]From {}, {}.{}() param:{}", from, invoker.getInterface(), invocation.getMethodName(), invocation.getArguments());
        return invoker.invoke(invocation);
    }
}

关于更多详情我写了一个博客:http://jaskey.github.io/blog/2020/05/18/dubbo-filter-trace-consumer/