zoukankan      html  css  js  c++  java
  • dubbo心跳机制 (3)

    此文已由作者赵计刚授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。


    二、consumer端心跳机制


                          //创建ExchangeClient,对第一次服务发现providers路径下的相关url建立长连接
                          -->getClients(URL url)
                            -->getSharedClient(URL url)
                              -->ExchangeClient exchangeClient = initClient(url)
                                -->Exchangers.connect(url, requestHandler)
                                  -->HeaderExchanger.connect(URL url, ExchangeHandler handler)
                                    -->new DecodeHandler(new HeaderExchangeHandler(handler)))
                                      -->Transporters.connect(URL url, ChannelHandler... handlers)
                                        -->NettyTransporter.connect(URL url, ChannelHandler listener)
                                          -->new NettyClient(url, listener)
                                            -->new MultiMessageHandler(HeartbeatHandler(AllChannelHandler(handler)))
                                            -->getChannelCodec(url)//获取Codec2,这里是DubboCountCodec实例
                                            -->doOpen()//开启netty客户端
                                            -->doConnect()//连接服务端,建立长连接
                                    -->new HeaderExchangeClient(Client client, boolean needHeartbeat)//上述的NettyClient实例,needHeartbeat:true
                                      -->startHeatbeatTimer()//启动心跳计数器


    客户端在initClient(url)中设置了heartbeat参数(默认为60s,用户自己设置的方式见“一”中所讲),如下:


     1     /**
     2      * Create new connection
     3      */
     4     private ExchangeClient initClient(URL url) {
     5         ...
     6         // enable heartbeat by default
     7         url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
     8 
     9         ...
    10 
    11         ExchangeClient client;
    12         try {
    13             // connection should be lazy
    14             if (url.getParameter(Constants.LAZY_CONNECT_KEY, false)) {
    15                 client = new LazyConnectExchangeClient(url, requestHandler);16             } else {
    17                 client = Exchangers.connect(url, requestHandler);
    18             }
    19         } catch (RemotingException e) {
    20             throw new RpcException("Fail to create remoting client for service(" + url + "): " + e.getMessage(), e);
    21         }
    22         return client;
    23     }


    与provider类似,来看一下最后开启心跳检测的地方。


     1 public class HeaderExchangeClient implements ExchangeClient {
     2     private static final ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(2, new NamedThreadFactory("dubbo-remoting-client-heartbeat", true));
     3     private final Client client;
     4     private final ExchangeChannel channel;
     5     // heartbeat timer
     6     private ScheduledFuture<?> heartbeatTimer;
     7     // heartbeat(ms), default value is 0 , won't execute a heartbeat.
     8     private int heartbeat;
     9     private int heartbeatTimeout;
    10 
    11     public HeaderExchangeClient(Client client, boolean needHeartbeat) {
    12         if (client == null) {
    13             throw new IllegalArgumentException("client == null");
    14         }
    15         this.client = client;
    16         this.channel = new HeaderExchangeChannel(client);
    17         String dubbo = client.getUrl().getParameter(Constants.DUBBO_VERSION_KEY);
    18         this.heartbeat = client.getUrl().getParameter(Constants.HEARTBEAT_KEY, dubbo != null && dubbo.startsWith("1.0.") ? Constants.DEFAULT_HEARTBEAT : 0);
    19         this.heartbeatTimeout = client.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
    20         if (heartbeatTimeout < heartbeat * 2) {
    21             throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2");
    22         }
    23         if (needHeartbeat) {
    24             startHeatbeatTimer();
    25         }
    26     }
    27 
    28     private void startHeatbeatTimer() {
    29         stopHeartbeatTimer();
    30         if (heartbeat > 0) {
    31             heartbeatTimer = scheduled.scheduleWithFixedDelay(
    32                     new HeartBeatTask(new HeartBeatTask.ChannelProvider() {
    33                         public Collection<Channel> getChannels() {
    34                             return Collections.<Channel>singletonList(HeaderExchangeClient.this);
    35                         }
    36                     }, heartbeat, heartbeatTimeout),
    37                     heartbeat, heartbeat, TimeUnit.MILLISECONDS);
    38         }
    39     }
    40 
    41     private void stopHeartbeatTimer() {
    42         if (heartbeatTimer != null && !heartbeatTimer.isCancelled()) {
    43             try {
    44                 heartbeatTimer.cancel(true);
    45                 scheduled.purge();
    46             } catch (Throwable e) {
    47                 if (logger.isWarnEnabled()) {
    48                     logger.warn(e.getMessage(), e);
    49                 }
    50             }
    51         }
    52         heartbeatTimer = null;
    53     }
    54 }


    主要看一下startHeartbeatTimer()方法,与provider相同,只是provider是获取NettyServer的所有的NettyChannel,而consumer只是获取当前的对象。

    consumer的handler处理链与provider完全相同。

    最后来看一下consumer的重连机制:AbstractClient#reconnect


      1     public void reconnect() throws RemotingException {
     2         disconnect(); 3         connect();
     4     }
     5 
     6     public void disconnect() {
     7         connectLock.lock();
     8         try {
     9             destroyConnectStatusCheckCommand();
    10             try {
    11                 Channel channel = getChannel();
    12                 if (channel != null) {
    13                     channel.close();
    14                 }
    15             } catch (Throwable e) {
    16                 logger.warn(e.getMessage(), e);
    17             }
    18             try {
    19                 doDisConnect();
    20             } catch (Throwable e) {
    21                 logger.warn(e.getMessage(), e);
    22             }
    23         } finally {
    24             connectLock.unlock();
    25         }
    26     }
    27 
    28     protected void connect() throws RemotingException {
    29         connectLock.lock();
    30         try {
    31             if (isConnected()) {
    32                 return;
    33             }
    34             initConnectStatusCheckCommand();
    35             doConnect();
    36             if (!isConnected()) {
    37                 throw new RemotingException(this, "Failed connect to server " + getRemoteAddress() + " from " + getClass().getSimpleName() + " "
    38                         + NetUtils.getLocalHost() + " using dubbo version " + Version.getVersion()
    39                         + ", cause: Connect wait timeout: " + getTimeout() + "ms.");
    40             } else {
    41                 if (logger.isInfoEnabled()) {
    42                     logger.info("Successed connect to server " + getRemoteAddress() + " from " + getClass().getSimpleName() + " "
    43                             + NetUtils.getLocalHost() + " using dubbo version " + Version.getVersion()
    44                             + ", channel is " + this.getChannel());
    45                 }
    46             }
    47             reconnect_count.set(0);
    48             reconnect_error_log_flag.set(false);
    49         } catch (RemotingException e) {
    50             throw e;
    51         } catch (Throwable e) {
    52             throw new RemotingException(this, "Failed connect to server " + getRemoteAddress() + " from " + getClass().getSimpleName() + " "
    53                     + NetUtils.getLocalHost() + " using dubbo version " + Version.getVersion()
    54                     + ", cause: " + e.getMessage(), e);
    55         } finally {
    56             connectLock.unlock();
    57         }
    58     }


    代码比较简单,先断连,再连接。

    免费体验云安全(易盾)内容安全、验证码等服务

    更多网易技术、产品、运营经验分享请点击


    相关文章:
    【推荐】 如何实现最佳的跨平台游戏体验?Unity成亮解密实时渲染
    【推荐】 什么是高防服务器?

  • 相关阅读:
    设置ImageView圆角
    GitHub-引导页
    GitHub-特效
    TextView总汇
    【笔记8-Redis分布式锁】从0开始 独立完成企业级Java电商网站开发(服务端)
    【笔记7-部署发布】从0开始 独立完成企业级Java电商网站开发(服务端)
    【笔记6-支付及订单模块】从0开始 独立完成企业级Java电商网站开发(服务端)
    【笔记5-购物车及地址模块】从0开始 独立完成企业级Java电商网站开发(服务端)
    【笔记4-商品模块】从0开始 独立完成企业级Java电商网站开发(服务端)
    【笔记3-用户模块】从0开始 独立完成企业级Java电商网站开发(服务端)
  • 原文地址:https://www.cnblogs.com/zyfd/p/9969969.html
Copyright © 2011-2022 走看看