dubbo rpc consumer 接收数据

14 篇文章 0 订阅

分析

dubbo与netty之间通过一个BlockQueue传输数据

一个是主线程([main,5,main]),通过调用threadlessExecutor.waitAndDrain()从一个LinkedBlockingQueue中获取数据。

另一个是netty的线程([NettyClientWorker,优先级不知道,main]),将数据存入LinkedBlockingQueue中。

主线程尝试获取数据

堆栈 主线程尝试从队列中获取数据

waitAndDrain:89, ThreadlessExecutor (org.apache.dubbo.common.threadpool)
get:179, AsyncRpcResult (org.apache.dubbo.rpc)
invoke:61, AsyncToSyncInvoker (org.apache.dubbo.rpc.protocol)//从这里发送和接收开始不同
invoke:78, ListenerInvokerWrapper (org.apache.dubbo.rpc.listener)
invoke:89, MonitorFilter (org.apache.dubbo.monitor.support)
invoke:81, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:51, FutureFilter (org.apache.dubbo.rpc.protocol.dubbo.filter)
invoke:81, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:69, ConsumerContextFilter (org.apache.dubbo.rpc.filter)
invoke:81, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:56, InvokerWrapper (org.apache.dubbo.rpc.protocol)
doInvoke:82, FailoverClusterInvoker (org.apache.dubbo.rpc.cluster.support)
invoke:259, AbstractClusterInvoker (org.apache.dubbo.rpc.cluster.support)
intercept:47, ClusterInterceptor (org.apache.dubbo.rpc.cluster.interceptor)
invoke:92, AbstractCluster$InterceptorInvokerNode (org.apache.dubbo.rpc.cluster.support.wrapper)
invoke:82, MockClusterInvoker (org.apache.dubbo.rpc.cluster.support.wrapper)
invoke:74, InvokerInvocationHandler (org.apache.dubbo.rpc.proxy)
sayHello:-1, proxy0 (org.apache.dubbo.common.bytecode)
main:33, Consumer (org.apache.dubbo.samples.mock)

关键代码 主线程尝试从队列中获取数据

/**
 * Waits until there is a task, executes the task and all queued tasks (if there're any). The task is either a normal
 * response or a timeout response.
 */
public void waitAndDrain() throws InterruptedException {
    /**
     * Usually, {@link #waitAndDrain()} will only get called once. It blocks for the response for the first time,
     * once the response (the task) reached and being executed waitAndDrain will return, the whole request process
     * then finishes. Subsequent calls on {@link #waitAndDrain()} (if there're any) should return immediately.
     *
     * There's no need to worry that {@link #finished} is not thread-safe. Checking and updating of
     * 'finished' only appear in waitAndDrain, since waitAndDrain is binding to one RPC call (one thread), the call
     * of it is totally sequential.
     */
    if (finished) {
        return;
    }
 
    Runnable runnable = queue.take();//89行,如果当前没有数据,此处会阻塞
 
    synchronized (lock) {
        waiting = false;
        runnable.run();
    }
 
    runnable = queue.poll();
    while (runnable != null) {
        try {
            runnable.run();
        } catch (Throwable t) {
            logger.info(t);
 
        }
        runnable = queue.poll();
    }
    // mark the status of ThreadlessExecutor as finished.
    finished = true;
}

netty线程将获取到的数据存入BlockQueue中,并唤醒主线程

堆栈 netty线程因插入新的数据,而唤醒阻塞的BlockQueue(下文会对BlockQueue进行简单介绍)

unpark:140, LockSupport (java.util.concurrent.locks)
tryMatch:265, SynchronousQueue$TransferStack$SNode (java.util.concurrent)
transfer:383, SynchronousQueue$TransferStack (java.util.concurrent)
offer:913, SynchronousQueue (java.util.concurrent)
execute:1371, ThreadPoolExecutor (java.util.concurrent)
caught:76, AllChannelHandler (org.apache.dubbo.remoting.transport.dispatcher.all)
caught:63, AbstractChannelHandlerDelegate (org.apache.dubbo.remoting.transport)
caught:63, AbstractChannelHandlerDelegate (org.apache.dubbo.remoting.transport)
caught:152, AbstractPeer (org.apache.dubbo.remoting.transport)
exceptionCaught:138, NettyClientHandler (org.apache.dubbo.remoting.transport.netty4)
invokeExceptionCaught:285, AbstractChannelHandlerContext (io.netty.channel)
notifyHandlerException:850, AbstractChannelHandlerContext (io.netty.channel)
invokeUserEventTriggered:331, AbstractChannelHandlerContext (io.netty.channel)
invokeUserEventTriggered:315, AbstractChannelHandlerContext (io.netty.channel)
fireUserEventTriggered:307, AbstractChannelHandlerContext (io.netty.channel)
channelIdle:371, IdleStateHandler (io.netty.handler.timeout)
run:494, IdleStateHandler$ReaderIdleTimeoutTask (io.netty.handler.timeout)
run:466, IdleStateHandler$AbstractIdleTask (io.netty.handler.timeout)
call:38, PromiseTask$RunnableAdapter (io.netty.util.concurrent)
run:125, ScheduledFutureTask (io.netty.util.concurrent)
safeExecute$$$capture:163, AbstractEventExecutor (io.netty.util.concurrent)
safeExecute:-1, AbstractEventExecutor (io.netty.util.concurrent)
runAllTasks:404, SingleThreadEventExecutor (io.netty.util.concurrent)
run:465, NioEventLoop (io.netty.channel.nio)
run:884, SingleThreadEventExecutor$5 (io.netty.util.concurrent)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:748, Thread (java.lang)

关键代码 netty线程因插入新的数据,而唤醒阻塞的BlockQueue

/**
 * Makes available the permit for the given thread, if it
 * was not already available.  If the thread was blocked on
 * {@code park} then it will unblock.  Otherwise, its next call
 * to {@code park} is guaranteed not to block. This operation
 * is not guaranteed to have any effect at all if the given
 * thread has not been started.
 *
 * @param thread the thread to unpark, or {@code null}, in which case
 *        this operation has no effect
 */
public static void unpark(Thread thread) {
    if (thread != null)//140行
        UNSAFE.unpark(thread);
}

主线程被唤醒

堆栈 主线程从BlockQueue中成功获取到数据

waitAndDrain:91, ThreadlessExecutor (org.apache.dubbo.common.threadpool)
get:179, AsyncRpcResult (org.apache.dubbo.rpc)
invoke:61, AsyncToSyncInvoker (org.apache.dubbo.rpc.protocol)
invoke:78, ListenerInvokerWrapper (org.apache.dubbo.rpc.listener)
invoke:89, MonitorFilter (org.apache.dubbo.monitor.support)
invoke:81, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:51, FutureFilter (org.apache.dubbo.rpc.protocol.dubbo.filter)
invoke:81, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:69, ConsumerContextFilter (org.apache.dubbo.rpc.filter)
invoke:81, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:56, InvokerWrapper (org.apache.dubbo.rpc.protocol)
doInvoke:82, FailoverClusterInvoker (org.apache.dubbo.rpc.cluster.support)
invoke:259, AbstractClusterInvoker (org.apache.dubbo.rpc.cluster.support)
intercept:47, ClusterInterceptor (org.apache.dubbo.rpc.cluster.interceptor)
invoke:92, AbstractCluster$InterceptorInvokerNode (org.apache.dubbo.rpc.cluster.support.wrapper)
invoke:82, MockClusterInvoker (org.apache.dubbo.rpc.cluster.support.wrapper)
invoke:74, InvokerInvocationHandler (org.apache.dubbo.rpc.proxy)
sayHello:-1, proxy0 (org.apache.dubbo.common.bytecode)
main:33, Consumer (org.apache.dubbo.samples.mock)

关键代码

/**
 * Waits until there is a task, executes the task and all queued tasks (if there're any). The task is either a normal
 * response or a timeout response.
 */
public void waitAndDrain() throws InterruptedException {
    /**
     * Usually, {@link #waitAndDrain()} will only get called once. It blocks for the response for the first time,
     * once the response (the task) reached and being executed waitAndDrain will return, the whole request process
     * then finishes. Subsequent calls on {@link #waitAndDrain()} (if there're any) should return immediately.
     *
     * There's no need to worry that {@link #finished} is not thread-safe. Checking and updating of
     * 'finished' only appear in waitAndDrain, since waitAndDrain is binding to one RPC call (one thread), the call
     * of it is totally sequential.
     */
    if (finished) {
        return;
    }
 
    Runnable runnable = queue.take();
 
    synchronized (lock) {//第91行,唤醒之后主线程接着运行,此时"runnable"这个对象中已经存有接收的数据了
        waiting = false;
        runnable.run();
    }
 
    runnable = queue.poll();
    while (runnable != null) {
        try {
            runnable.run();
        } catch (Throwable t) {
            logger.info(t);
 
        }
        runnable = queue.poll();
    }
    // mark the status of ThreadlessExecutor as finished.
    finished = true;
}

调试过程中的截图

有关多线程 BlockQueue的调试

在其他线程中添加对象并解锁

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值