(十)dubbo原理
来源:互联网 发布:等腰三角形面积算法 编辑:程序博客网 时间:2024/06/15 00:56
原理机制
远程调用时,发送请求的封装对象com.alibaba.dubbo.remoting.exchange.Request
远程调用时,接收返回的封装对象
com.alibaba.dubbo.remoting.exchange.Response
请求发出后,返回一个com.alibaba.dubbo.remoting.exchange.ResponseFuture对象,
ResponseFuture的默认实现类com.alibaba.dubbo.remoting.exchange.support.DefaultFuture
在我们的业务层调用dubbo封装的service时,dubbo底层会调用com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker<T>的doInvoke方法:
public interface Invocation { String getMethodName(); Class<?>[] getParameterTypes(); Object[] getArguments(); Map<String, String> getAttachments(); String getAttachment(String key); String getAttachment(String key, String defaultValue); Invoker<?> getInvoker();}可以看出,Invocation对象封装了消费者调用提供者的
类名: getInvoker()返回Invoker可以获得接口名;
方法名: getMethodName();
参数类型列表: getParameterTypes();
参数值列表: getArguments();
@Overrideprotected Result doInvoke(final Invocation invocation) throws Throwable { RpcInvocation inv = (RpcInvocation) invocation; final String methodName = RpcUtils.getMethodName(invocation); inv.setAttachment(Constants.PATH_KEY, getUrl().getPath()); inv.setAttachment(Constants.VERSION_KEY, version); ExchangeClient currentClient; if (clients.length == 1) { currentClient = clients[0]; } else { currentClient = clients[index.getAndIncrement() % clients.length]; } try { boolean isAsync = RpcUtils.isAsync(getUrl(), invocation); boolean isOneway = RpcUtils.isOneway(getUrl(), invocation); int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT); if (isOneway) { boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false); currentClient.send(inv, isSent); RpcContext.getContext().setFuture(null); return new RpcResult(); } else if (isAsync) { //11处,调用服务的结果,异步返回模式。 ResponseFuture future = currentClient.request(inv, timeout) ; //12处,向提供者发送消息 RpcContext.getContext().setFuture(new FutureAdapter<Object>(future)); return new RpcResult(); } else { RpcContext.getContext().setFuture(null); return (Result) currentClient.request(inv, timeout).get(); //13处,调用服务的结果,同步返回结果 } } catch (TimeoutException e) { throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); } catch (RemotingException e) { throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); }}如果调用服务,是异步返回结果,则是"11处",其中"12处"是向提供者发送服务消息。
如果调用服务,是同步返回结果,则是"13处",currentClient.request(inv, timeout)会向提供者发送消息,并返回ResponseFuture对象,然后调用ResponseFuture的get方法,返回结果;
这里的currentClient.request(inv, timeout),其实就是调用对象ReferenceCountExchangeClient.request()方法;
下面是调用dubbo服务的轨迹:
at com.alibaba.dubbo.remoting.transport.AbstractClient.send(AbstractClient.java:268)at com.alibaba.dubbo.remoting.transport.AbstractPeer.send(AbstractPeer.java:51)at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.request(HeaderExchangeChannel.java:112)at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeClient.request(HeaderExchangeClient.java:91)at com.alibaba.dubbo.rpc.protocol.dubbo.ReferenceCountExchangeClient.request(ReferenceCountExchangeClient.java:81)at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:96)at com.alibaba.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:144)at com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:53)at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)at com.alibaba.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:48)at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)at com.alibaba.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:74)at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53)at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:77)追随轨迹,看到com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.request方法:
public ResponseFuture request(Object request, int timeout) throws RemotingException { if (closed) { throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!"); } // create request. Request req = new Request(); //14处,创建一个Request对象 req.setVersion("2.0.0"); req.setTwoWay(true); req.setData(request); DefaultFuture future = new DefaultFuture(channel, req, timeout); //15处,创建一个结果封装对象DefaultFuture try{ channel.send(req); }catch (RemotingException e) { future.cancel(); throw e; } return future;}可以看到,"14处"会先创建一个Request对象,然后"15处"将Request对象放进DefaultFuture对象,DefaultFuture对象负责等待处理服务调用的返回消息。
先看看Request创建时的逻辑:
public class Request { private static final AtomicLong INVOKE_ID = new AtomicLong(0); private final long mId; public Request() { mId = newId(); } private static long newId() { // getAndIncrement()增长到MAX_VALUE时,再增长会变为MIN_VALUE,负数也可以做为ID return INVOKE_ID.getAndIncrement(); }}而每个Request对象都会生成一个id,也就是说每个dubbo服务请求都对应一个id。
再看看DefaultFuture的内容结构:
下面看看ResponseFuture的实现类DefaultFuture
public class DefaultFuture implements ResponseFuture { private static final Map<Long, Channel> CHANNELS = new ConcurrentHashMap<Long, Channel>(); private static final Map<Long, DefaultFuture> FUTURES = new ConcurrentHashMap<Long, DefaultFuture>(); private final Request request; private volatile Response response; public DefaultFuture(Channel channel, Request request, int timeout){ this.channel = channel; this.request = request; this.id = request.getId(); this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); // put into waiting map. FUTURES.put(id, this); //16处,将Request id和Request对象关联起来 CHANNELS.put(id, channel); } public Object get() throws RemotingException { return get(timeout); } public Object get(int timeout) throws RemotingException { if (timeout <= 0) { timeout = Constants.DEFAULT_TIMEOUT; } if (! isDone()) { long start = System.currentTimeMillis(); lock.lock(); try { while (! isDone()) { done.await(timeout, TimeUnit.MILLISECONDS); //17处,如果调用服务,提供者还没返回消息,则一直阻塞时长timeout。 if (isDone() || System.currentTimeMillis() - start > timeout) { break; } } } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } if (! isDone()) { throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false)); } } return returnFromResponse(); //18处,返回dubbo服务调用结果 } private Object returnFromResponse() throws RemotingException { Response res = response; if (res == null) { throw new IllegalStateException("response cannot be null"); } if (res.getStatus() == Response.OK) { return res.getResult(); //19处,服务调用状态是OK,返回提供者返回的结果。 } if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) { //20处,提供者一直没返回结果,则状态会是超时。 throw new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage()); } throw new RemotingException(channel, res.getErrorMessage()); }}消费者发送了请求消息后,会调用DefaultFuture的get方法,直到有结果返回或超时,如果还没结果返回,看"17处",提供者还没返回消息,则一直阻塞时长timeout。
提供者返回了结果,则服务调用状态是OK,则是"19处";提供者一直没返回结果,则状态会是超时,则是"20处"。
这里,会有个问题,就是返回消息中,dubbo如何识别返回消息对应是哪个请求消息?
下面继续看看返回消息时,dubbo是如何处理的。
有消息返回时,调用DefaultFuture的静态方法received:
public static void received(Channel channel, Response response) { try { DefaultFuture future = FUTURES.remove(response.getId()); //1处,根据消息的id,可以获得消息对应的DefaultFuture if (future != null) { future.doReceived(response); //2处,调用DefaultFuture方法doReceived,设置返回对象Response } else { logger.warn("The timeout response finally returned at " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date())) + ", response " + response + (channel == null ? "" : ", channel: " + channel.getLocalAddress() + " -> " + channel.getRemoteAddress())); } } finally { CHANNELS.remove(response.getId()); }}从1处看,根据消息的id,可以获得消息对应的DefaultFuture,然后在2处,调用DefaultFuture方法doReceived,设置返回对象Response
private void doReceived(Response res) { lock.lock(); try { response = res; //3处 if (done != null) { done.signal(); //4处 } } finally { lock.unlock(); } if (callback != null) { invokeCallback(callback); //5处 }}从3处看,就是设置返回对象Response,并且4处,释放,则get方法就可以不再阻塞,返回远程调用的结果;如果调用结果是异步返回的,则会在"5处",调用callback方法。
总结:
dubbo底层使用一个长连接,不断传输client和server的数据,client的Request和server的Response是用一个请求id(即是Request的id属性)来绑定对应关系的,所以不管长连接传输的数据是否按照顺序的,都没关系,因为可以根据id找到对应的client的Request。
线程派发
接着,我们来看看dubbo的提供者对这一长连接上的数据如何处理。
对一个长连接会有几个事件:
1.建立连接
2.断开连接
3.发送消息
4.接收消息
5.出现异常
dubbo会使用线程池来处理这几个事件,也即是,可能对一个事件派发线程来处理的,根据派发线程方式不同,分为几种:
all, direct, message, execution, connection
即是通过标签<dubbo:protocol dispatcher="all"/>的dispatcher来设置的,默认是"all"
1).all,在事件1.2.4.5,都会派发线程处理,如果根据用户配置的线程池创建方式得到线程池为null,但会有默认的线程池Executors.newCachedThreadPool(),
dubbo会创建com.alibaba.dubbo.remoting.transport.dispatcher.all.AllDispatcher
2)direct,不派发线程,对应com.alibaba.dubbo.remoting.transport.dispatcher.direct.DirectDispatcher
3)message,在事件4,派发线程处理,对应com.alibaba.dubbo.remoting.transport.dispatcher.message.MessageOnlyDispatcher
4)connection,在1.2.4.5,派发线程,并且对1.2事件会保证顺序,对应com.alibaba.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedDispatcher
5)execution,除发送全部使用线程池处理,对应com.alibaba.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatcher
线程池
下面看看dubbo是如何创建线程池
使用标签指定线程池:
<dubbo:provider threadpool="fixed"/>或者<dubbo:protocol threadpool="fixed"/>
可配置:
fixed=com.alibaba.dubbo.common.threadpool.support.fixed.FixedThreadPoolcached=com.alibaba.dubbo.common.threadpool.support.cached.CachedThreadPoollimited=com.alibaba.dubbo.common.threadpool.support.limited.LimitedThreadPool下面是三种线程池的源码
/** * 此线程池可伸缩,线程空闲一分钟后回收,新请求重新创建线程,来源于:<code>Executors.newCachedThreadPool()</code> * * @see java.util.concurrent.Executors#newCachedThreadPool() * @author william.liangf */public class CachedThreadPool implements ThreadPool { public Executor getExecutor(URL url) { String name = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME); int cores = url.getParameter(Constants.CORE_THREADS_KEY, Constants.DEFAULT_CORE_THREADS); int threads = url.getParameter(Constants.THREADS_KEY, Integer.MAX_VALUE); int queues = url.getParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES); int alive = url.getParameter(Constants.ALIVE_KEY, Constants.DEFAULT_ALIVE); //default_alive:60000 return new ThreadPoolExecutor(cores, threads, alive, TimeUnit.MILLISECONDS, queues == 0 ? new SynchronousQueue<Runnable>() : (queues < 0 ? new LinkedBlockingQueue<Runnable>() : new LinkedBlockingQueue<Runnable>(queues)), new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url)); }}
/** * 此线程池启动时即创建固定大小的线程数,不做任何伸缩,来源于:<code>Executors.newFixedThreadPool()</code> * * @see java.util.concurrent.Executors#newFixedThreadPool(int) * @author william.liangf */public class FixedThreadPool implements ThreadPool { public Executor getExecutor(URL url) { String name = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME); int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); int queues = url.getParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES); return new ThreadPoolExecutor(threads, threads, 0, TimeUnit.MILLISECONDS, queues == 0 ? new SynchronousQueue<Runnable>() : (queues < 0 ? new LinkedBlockingQueue<Runnable>() : new LinkedBlockingQueue<Runnable>(queues)), new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url)); }}
/** * 此线程池一直增长,直到上限,增长后不收缩。 * * @author <a href="mailto:gang.lvg@alibaba-inc.com">kimi</a> */public class LimitedThreadPool implements ThreadPool { public Executor getExecutor(URL url) { String name = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME); int cores = url.getParameter(Constants.CORE_THREADS_KEY, Constants.DEFAULT_CORE_THREADS); int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); int queues = url.getParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES); return new ThreadPoolExecutor(cores, threads, Long.MAX_VALUE, TimeUnit.MILLISECONDS, queues == 0 ? new SynchronousQueue<Runnable>() : (queues < 0 ? new LinkedBlockingQueue<Runnable>() : new LinkedBlockingQueue<Runnable>(queues)), new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url)); }}
..
- (十)dubbo原理
- (三)dubbo工作原理
- (二)dubbo工作原理
- Dubbo原理
- dubbo原理
- dubbo原理
- dubbo原理
- dubbo原理
- Dubbo!dubbo原理设计详解
- Dubbo系列(十)Dubbo源码分析之Javassist字节码技术生成代理
- dubbo学习笔记 十 dubbo-rpc
- (十)轻松Dubbo管理控制台
- Dubbo学习(十):异步调用
- (十)Spring Boot 整合dubbo
- Dubbo服务框架原理
- Dubbo原理解析
- Dubbo原理及应用
- Dubbo原理解析-监控
- 友盟推送遇到的坑
- java的4种代码块
- MongoDB逻辑操作符$or, $and,$not,$nor
- nginx启动不了
- JZOJ1296.【USACO题库】3.4.4 Raucous Rockers“破锣摇滚”乐队
- (十)dubbo原理
- ubuntu 安装 Visual studio code (c/c++ python php ...)
- 使用Jenkins持续集成JavaWeb项目(War包部署方式)
- 读入优化
- jvm读书笔记之垃圾收集器
- 用树莓派实现远程唤醒
- ActiveMQ 即时通讯服务 浅析
- Groovy的可选形参
- 第一次使用stackoverflow的寻求帮助