Dubbo Exchange 信息交换层
来源:互联网 发布:数据透视表取消总计 编辑:程序博客网 时间:2024/05/19 17:08
ReferenceCountExchangeClient:将请求交HeaderExchangeClient处理,不进行任何其他操作。
public ResponseFuture request(Object request) throws RemotingException { return client.request(request); }
HeaderExchangeClient:提供心跳检查功能;将send、request、close等事件转由HeaderExchangeChannel处理,HeaderExchangeChannel对象中的Channel为所选的NIO框架对应的client对象;以request为例,调用流程如下:HeaderExchangeClient.request(Object request)->HeaderExchangeChannel.request(Object request)->(NettyClient)AbstractPeer.send(Object message)->(NettyClient)AbstractClient.send(Object message,boolean sent)。
public ResponseFuture request(Object request) throws RemotingException { return channel.request(request);//HeaderExchangeChannel }
HeaderExchangeChannel:主要是完成同步转异步,在request(Object request,int timeout)方法中,将请求转换成Request对象,将请求消息设置到data属性上,构建DefaultFuture对象,调用NIO框架对应的Client对象(默认NettyClient)的send方法将消息发送出去,返回DefultFuture对象。
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(); req.setVersion("2.0.0"); req.setTwoWay(true); req.setData(request); DefaultFuture future = new DefaultFuture(channel, req, timeout); try{ channel.send(req); }catch (RemotingException e) { future.cancel(); throw e; } return future; }
NettyClient:完成消息的发送。在调用链的最后一个方法AbstractClient.send(Object message, boolean sent)中,首先通过调用NettyClient.getChannel()获取NettyChannel对象,在构建对象时封装了NIOSocketChannel对象(在初始化NettyClient对象时,根据nettyclient和server端建立连接时获取的socket通道)、统一数据模型URL以及channelHandler对象(NettyClient对象自身),然后调用NettyChannel对象的send方法,将Request消息写入NIOSocketChannel通道中,完成消息发送。
public void send(Object message, boolean sent) throws RemotingException {//AbstractClient if (send_reconnect && !isConnected()){ connect(); } Channel channel = getChannel(); //TODO getChannel返回的状态是否包含null需要改进 if (channel == null || ! channel.isConnected()) { throw new RemotingException(this, "message can not send, because channel is closed . url:" + getUrl()); } channel.send(message, sent); }
@Override protected com.sitech.hsf.remoting.Channel getChannel() {//nettyclient Channel c = channel; if (c == null || ! c.isConnected()) return null; return NettyChannel.getOrAddChannel(c, getUrl(), this); }
public void send(Object message, boolean sent) throws RemotingException {//NettyChannel super.send(message, sent); boolean success = true; int timeout = 0; try {//调用Netty框架 ChannelFuture future = channel.write(message); if (sent) {//sent=true等待发送失败将抛出异常,false不等待消息发出,将消息放入IO队列,即刻返回。 timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); success = future.await(timeout); } Throwable cause = future.getCause(); if (cause != null) { throw cause; } } catch (Throwable e) { throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e); } if(! success) { throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + "in timeout(" + timeout + "ms) limit"); } }
HeaderExchangeServer:提供心跳检查功能;启动心跳监测线程池,该线程初始化了一个线程,在线程中调用类HeartBeatTask进行心跳检查,HeartBeatTask处理心跳的规则:
(1)若通道的最新的写入时间或者最新的读取时间与当前时间相比,已经超过了心跳间隔时间,则发送心跳请求;
(2)如果通道的最新的读取时间与当前时间相比,已经超过了心跳的超时时间,对于客户端来说则重连,对于服务端来说则关闭通道。
public HeaderExchangeServer(Server server) { if (server == null) { throw new IllegalArgumentException("server == null"); } this.server = server; this.heartbeat = server.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);// this.heartbeatTimeout = server.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3); if (heartbeatTimeout < heartbeat * 2) { throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2"); } startHeatbeatTimer(); }3位心跳时长为心跳超时,如果不设置,默认心跳为0。
private void startHeatbeatTimer() {//HeaderExchangeServer stopHeartbeatTimer(); if (heartbeat > 0) { heatbeatTimer = scheduled.scheduleWithFixedDelay( new HeartBeatTask( new HeartBeatTask.ChannelProvider() { public Collection<Channel> getChannels() { return Collections.unmodifiableCollection( HeaderExchangeServer.this.getChannels() ); } }, heartbeat, heartbeatTimeout), heartbeat, heartbeat,TimeUnit.MILLISECONDS); } }
如果心跳为0,不执行心跳检测功能。
public void run() {//HeartBeatTask try { long now = System.currentTimeMillis();//获取当前时间 for ( Channel channel : channelProvider.getChannels() ) { if (channel.isClosed()) {//已经关闭了 continue; } try { //最后一次读的时间戳 Long lastRead = ( Long ) channel.getAttribute( HeaderExchangeHandler.KEY_READ_TIMESTAMP ); //最后一次写的时间戳 Long lastWrite = ( Long ) channel.getAttribute( HeaderExchangeHandler.KEY_WRITE_TIMESTAMP ); //如果当前时间距离最后一次写或读超过一个心跳时间 if ( ( lastRead != null && now - lastRead > heartbeat ) || ( lastWrite != null && now - lastWrite > heartbeat ) ) { Request req = new Request(); req.setVersion( "2.0.0" ); req.setTwoWay( true ); req.setEvent( Request.HEARTBEAT_EVENT ); channel.send( req ); if ( logger.isDebugEnabled() ) { logger.debug( "Send heartbeat to remote channel " + channel.getRemoteAddress() + ", cause: The channel has no data-transmission exceeds a heartbeat period: " + heartbeat + "ms" ); } } //如果上一次读距离现在已经超过心路超时时长,尝试重连 if ( lastRead != null && now - lastRead > heartbeatTimeout ) { logger.warn( "Close channel " + channel + ", because heartbeat read idle time out: " + heartbeatTimeout + "ms" ); if (channel instanceof Client) { try { ((Client)channel).reconnect(); }catch (Exception e) {//do nothing} } else { channel.close(); } } } catch ( Throwable t ) { logger.warn( "Exception when heartbeat to remote channel " + channel.getRemoteAddress(), t ); } } } catch ( Throwable t ) { logger.warn( "Unhandled exception when heartbeat, cause: " + t.getMessage(), t ); } }
在起动NettyClient和NettyServer连接时,都添加了一个HeartbeatHandler
public void received(Channel channel, Object message) throws RemotingException { setReadTimestamp(channel); if (isHeartbeatRequest(message)) {//如果是心跳请求 Request req = (Request) message; if (req.isTwoWay()) { Response res = new Response(req.getId(), req.getVersion()); res.setEvent(Response.HEARTBEAT_EVENT); channel.send(res); if (logger.isInfoEnabled()) { int heartbeat = channel.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0); if(logger.isDebugEnabled()) { logger.debug("Received heartbeat from remote channel " + channel.getRemoteAddress() + ", cause: The channel has no data-transmission exceeds a heartbeat period" + (heartbeat > 0 ? ": " + heartbeat + "ms" : "")); } } } return; } if (isHeartbeatResponse(message)) {//如果是心跳响应 if (logger.isDebugEnabled()) { logger.debug( new StringBuilder(32) .append("Receive heartbeat response in thread ") .append(Thread.currentThread().getName()) .toString()); } return; } handler.received(channel, message); }
多线程并发请求与单一长连接
public ResponseFuture request(Object request, int timeout) throws RemotingException {//HeaderExchangeChannel.request 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(); req.setVersion("2.0.0"); req.setTwoWay(true); req.setData(request); DefaultFuture future = new DefaultFuture(channel, req, timeout); try{ channel.send(req); }catch (RemotingException e) { future.cancel(); throw e; } return future; }(2)该方法返回DefaultFuture对象给客户端线程,该线程会在DefaultFuture对象的get方法上面阻塞,有两种情况唤醒该线程:(一)接收到响应消息并调用received方法,根据响应消息中返回的ID从前面的ConcurrentHashMap里面get(ID)里面获取DefaultFuture对象,然后更新该对象的Response变量值。(二)RemotingInvocationTimeoutScan线程,定时扫描响应是否超时,若超时,则从FUTURES:ConcurrentHashMap中删除掉Future对象并且将Response变量设置为超时信息。
同步转异步的逻辑
- Dubbo Exchange 信息交换层
- Dubbo——Exchange信息交换层
- dubbo--远程调用数据交换层服务端类图
- dubbo--远程调用数据交换层客户端类图
- dubbo exchange协议
- 分区交换exchange
- Exchange partition 交换分区
- 交换学生(Foreign Exchange)
- 交换指令XCHG(exchange)
- POJ1860-Currency Exchange-货币交换
- UVA10763:Foreign Exchange(交换学生)
- 信息交换
- EXCHANGE相关有用信息
- 一层交换 二层交换 三层交换 四层交换 七层交换 OSI参考模型
- 一层交换 二层交换 三层交换 四层交换 七层交换 OSI参考模型
- 第四层交换 (转载)
- 第四层交换 (转载)
- 第四层交换 (转载)
- Spring Boot 异常统一处理
- 堆与堆排序
- 数据库SQL实战
- H5轮播图简版
- creating symbolic link XXXXXX : Operation not supported
- Dubbo Exchange 信息交换层
- Head First Python第一章:列表
- 坐标转换流程与公式 七参数 四参数
- Theme读取的工具类
- Oracle数据库导入导出
- viewpager+自动轮播+无线轮播+小圆点
- 实现spring 框架需要哪些包及其作用
- think in java第十章内部类 总结随笔
- 量取牛奶codevs2094