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

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

来看一下HeaderExchangeServer.this.getChannels():

  1     public Collection<Channel> getChannels() {
 2         return (Collection) getExchangeChannels();
 3     }
 4 
 5     public Collection<ExchangeChannel> getExchangeChannels() {
 6         Collection<ExchangeChannel> exchangeChannels = new ArrayList<ExchangeChannel>();
 7         Collection<Channel> channels = server.getChannels();
 8         if (channels != null && channels.size() > 0) {
 9             for (Channel channel : channels) {
10                 exchangeChannels.add(HeaderExchangeChannel.getOrAddChannel(channel));
11             }
12         }
13         return exchangeChannels;
14     }

实际上就是获取NettyServer中的全部channel连接。

获取到需要心跳检测的channel后,对每一个channel进行如下判断:

  • 如果在heartbeat内没有进行读操作或者写操作,则发送心跳请求

  • 如果正常消息和心跳在heartbeatTimeout都没接收到,consumer端会进行重连,provider端会关闭channel

这里比较关键的是lastRead和lastWrite的设置。先来看一下获取:

1 Long lastRead = (Long) channel.getAttribute(HeaderExchangeHandler.KEY_READ_TIMESTAMP);
2 Long lastWrite = (Long) channel.getAttribute(HeaderExchangeHandler.KEY_WRITE_TIMESTAMP);

说明有地方在设置这两个值到channel中。

从请求和响应处理来看,无论是请求还是响应都会按照这个顺序处理一遍。

1 MultiMessageHandler
2 -->handler: HeartbeatHandler
3    -->handler: AllChannelHandler
4          -->url: providerUrl
5          -->executor: FixedExecutor
6          -->handler: DecodeHandler
7             -->handler: HeaderExchangeHandler
8                -->handler: ExchangeHandlerAdapter(DubboProtocol.requestHandler)

其中HeartbeatHandler源码如下:

1 public class HeartbeatHandler extends AbstractChannelHandlerDelegate {
 2 
 3     private static final Logger logger = LoggerFactory.getLogger(HeartbeatHandler.class);
 4 
 5     public static String KEY_READ_TIMESTAMP = "READ_TIMESTAMP";
 6 
 7     public static String KEY_WRITE_TIMESTAMP = "WRITE_TIMESTAMP";
 8 
 9     public HeartbeatHandler(ChannelHandler handler) {
10         super(handler);
11     }
12 
13     public void connected(Channel channel) throws RemotingException {
14         setReadTimestamp(channel);
15         setWriteTimestamp(channel);
16         handler.connected(channel);
17     }
18 
19     public void disconnected(Channel channel) throws RemotingException {
20         clearReadTimestamp(channel);
21         clearWriteTimestamp(channel);
22         handler.disconnected(channel);
23     }
24 
25     public void sent(Channel channel, Object message) throws RemotingException {
26         setWriteTimestamp(channel);
27         handler.sent(channel, message);
28     }
29 
30     public void received(Channel channel, Object message) throws RemotingException {
31         setReadTimestamp(channel);
32         if (isHeartbeatRequest(message)) {
33             Request req = (Request) message;
34             if (req.isTwoWay()) {
35                 Response res = new Response(req.getId(), req.getVersion());
36                 res.setEvent(Response.HEARTBEAT_EVENT);
37                 channel.send(res);
38                 if (logger.isInfoEnabled()) {
39                     int heartbeat = channel.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);
40                     if (logger.isDebugEnabled()) {
41                         logger.debug("Received heartbeat from remote channel " + channel.getRemoteAddress()
42                                 + ", cause: The channel has no data-transmission exceeds a heartbeat period"
43                                 + (heartbeat > 0 ? ": " + heartbeat + "ms" : ""));
44                     }
45                 }
46             }
47             return;
48         }
49         if (isHeartbeatResponse(message)) {
50             if (logger.isDebugEnabled()) {
51                 logger.debug(
52                         new StringBuilder(32)
53                                 .append("Receive heartbeat response in thread ")
54                                 .append(Thread.currentThread().getName())
55                                 .toString());
56             }
57             return;
58         }
59         handler.received(channel, message);
60     }
61 
62     private void setReadTimestamp(Channel channel) {
63         channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
64     }
65 
66     private void setWriteTimestamp(Channel channel) {
67         channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis());
68     }
69 
70     private void clearReadTimestamp(Channel channel) {
71         channel.removeAttribute(KEY_READ_TIMESTAMP);
72     }
73 
74     private void clearWriteTimestamp(Channel channel) {
75         channel.removeAttribute(KEY_WRITE_TIMESTAMP);
76     }
77 
78     private boolean isHeartbeatRequest(Object message) {
79         return message instanceof Request && ((Request) message).isHeartbeat();
80     }
81 
82     private boolean isHeartbeatResponse(Object message) {
83         return message instanceof Response && ((Response) message).isHeartbeat();
84     }
85 }
  • 连接完成时:设置lastRead和lastWrite

  • 连接断开时:清空lastRead和lastWrite

  • 发送消息时:设置lastWrite

  • 接收消息时:设置lastRead

之后交由AllChannelHandler进行处理。之后会一直交由HeaderExchangeHandler进行处理。其对lastRead和lastWrite也做了设置和清理:

  1     public void connected(Channel channel) throws RemotingException {
 2         channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
 3         channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis()); 4         ...
 5     }
 6 
 7     public void disconnected(Channel channel) throws RemotingException {
 8         channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
 9         channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis());
10         ...
11     }
12 
13     public void sent(Channel channel, Object message) throws RemotingException {
14         Throwable exception = null;
15         try {
16             channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis());
17             ...
18         } catch (Throwable t) {
19             exception = t;
20         }
21     }
22 
23     public void received(Channel channel, Object message) throws RemotingException {
24         channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
25         ...
26     }
  • 连接完成时:设置lastRead和lastWrite

  • 连接断开时:也设置lastRead和lastWrite(为什么?)

  • 发送消息时:设置lastWrite

  • 接收消息时:设置lastRead

这里里有个疑问,从handler链来看,无论是请求还是响应都会按照handler链来处理一遍。那么在HeartbeatHandler中已经进行了lastWrite和lastRead的设置,为什么还要在HeaderExchangeHandler中再处理一遍?

最后,provider端认为连接断了,则会关闭channel。来看一下NettyChannel的close方法:

 1     public void close() {
 2         // 1 将close属性设为true
 3         try {
 4             super.close();
 5         } catch (Exception e) {
 6             logger.warn(e.getMessage(), e);
 7         }
 8         // 2 从全局NettyChannel缓存器中将当前的NettyChannel删掉
 9         try {
10             removeChannelIfDisconnected(channel);
11         } catch (Exception e) {
12             logger.warn(e.getMessage(), e);
13         }
14         // 3 清空当前的NettyChannel中的attributes属性
15         try {
16             attributes.clear();
17         } catch (Exception e) {
18             logger.warn(e.getMessage(), e);
19         }
20         // 4 关闭netty的channel,执行netty的channel的优雅关闭
21         try {
22             if (logger.isInfoEnabled()) {
23                 logger.info("Close netty channel " + channel);
24             }
25             channel.close();
26         } catch (Exception e) {
27             logger.warn(e.getMessage(), e);
28         }
29     }

从上边代码来看,假设consumer端挂了,provider端的心跳检测机制可以进行相关的资源回收,所以provider端的心跳检测机制是有必要的。

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

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

相关文章:
【推荐】 大咖分享 | 一文解锁首届云创大会干货——下篇(文末附演讲ppt文件免费下载)
【推荐】 Kafka实践、升级和新版本(0.10)特性预研

dubbo心跳机制 (2)的更多相关文章

  1. 9.7 dubbo心跳机制

    dubbo的心跳机制: 目的:检测provider与consumer之间的connection连接是不是还连接着,如果连接断了,需要作出相应的处理. 原理: provider:dubbo的心跳默认是在 ...

  2. dubbo心跳机制 (1)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. dubbo的心跳机制: 目的:检测provider与consumer之间的connection连接是不是还连 ...

  3. dubbo心跳机制 (3)

    此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 二.consumer端心跳机制                       //创建ExchangeClie ...

  4. dubbo之心跳机制

    在网络传输中,怎么确保通道连接的可用性是一个很重要的问题,简单的说,在网络通信中有客户端和服务端,一个负责发送请求,一个负责接收请求,在保证连接有效性的背景下,这两个物体扮演了什么角色,心跳机制能有效 ...

  5. Dubbo之心跳机制 · 房东的小黑

    在网络传输中,怎么确保通道连接的可用性是一个很重要的问题,简单的说,在网络通信中有客户端和服务端,一个负责发送请求,一个负责接收请求,在保证连接有效性的背景下,这两个物体扮演了什么角色,心跳机制能有效 ...

  6. 分析dubbo心跳检测机制

    目的: 维持provider和consumer之间的长连接 实现: dubbo心跳时间heartbeat默认是60s,超过heartbeat时间没有收到消息,就发送心跳消息(provider,cons ...

  7. rabbitmq 的心跳机制&应用

    官方文档说: If a consumer dies (its channel is closed, connection is closed, or TCP connection is lost) w ...

  8. zookeeper心跳机制流程梳理

    zookeeper心跳机制流程梳理 Processor链Chain protected void setupRequestProcessors() { RequestProcessor finalPr ...

  9. 一个Socket连接管理池(心跳机制)

    一个Socket连接管理池(心跳机制) http://cuisuqiang.iteye.com/blog/1489661

随机推荐

  1. (转)C#程序开发中经常遇到的10条实用的代码

    原文地址:http://www.cnblogs.com/JamesLi2015/p/3147986.html 1 读取操作系统和CLR的版本 OperatingSystem os = System.E ...

  2. iOS播放视频

    1.首先导入 MediaPlayer import MediaPlayer 2.播放事件 class ViewController:UIViewController{ var pc:MPMoviePl ...

  3. java继承初级

    总结:重写方法,方法体内容不同. 还有子类都不能加public.它表示公共,一个程序只能有一个公共类 package com.sa; public class Ac { public void rea ...

  4. Rails的静态资源管理(四)—— 生产环境的 Asset Pipeline

    官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...

  5. 图解缓存淘汰算法三之FIFO

    1.概念分析 FIFO(First In First Out),即先进先出.最先进入的数据,最先出来.一个很简单的算法.只要使用队列数据结构即可实现.那么FIFO淘汰算法基于的思想是"最近刚 ...

  6. Oracle、SqlServer——临时表

    一.oracle 1.概述: oracle数据库的临时表的特点: 临时表默认保存在TEMP中: 表结构一直存在,直到删除:即创建一次,永久使用: 不支持主外键. 可以索引临时表和在临时表基础上建立视图 ...

  7. Go并发原理

    Go语言是为并发而生的语言,Go语言是为数不多的在语言层面实现并发的语言:也正是Go语言的并发特性,吸引了全球无数的开发者. 并发(concurrency)和并行(parallellism) 并发(c ...

  8. mysql show status 参数解析

    状态名 作用域 详细解释 Aborted_clients Global 由于客户端没有正确关闭连接导致客户端终止而中断的连接数 Aborted_connects Global 试图连接到MySQL服务 ...

  9. MSScriptControl详解(可实现在C#等语言中调用JAVASCRIPT代码)

    ScriptControl接口 属性名称 类型 备注 AllowUI BOOL 检测是否允许运行用户的接口元素.如果为False,则诸如消息框之类的界面元素不可见. CodeObject Object ...

  10. getUserMedia API

    getUserMedia API 特别有趣的一个 API,能够调用电脑的摄像头,未来这个 API 将被广泛用来让浏览器和用户之间互动. 如果 <video> 标签和 Canvas 现结合 ...