dubbo心跳机制 (2)
此文已由作者赵计刚授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
来看一下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)的更多相关文章
- 9.7 dubbo心跳机制
dubbo的心跳机制: 目的:检测provider与consumer之间的connection连接是不是还连接着,如果连接断了,需要作出相应的处理. 原理: provider:dubbo的心跳默认是在 ...
- dubbo心跳机制 (1)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. dubbo的心跳机制: 目的:检测provider与consumer之间的connection连接是不是还连 ...
- dubbo心跳机制 (3)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 二.consumer端心跳机制 //创建ExchangeClie ...
- dubbo之心跳机制
在网络传输中,怎么确保通道连接的可用性是一个很重要的问题,简单的说,在网络通信中有客户端和服务端,一个负责发送请求,一个负责接收请求,在保证连接有效性的背景下,这两个物体扮演了什么角色,心跳机制能有效 ...
- Dubbo之心跳机制 · 房东的小黑
在网络传输中,怎么确保通道连接的可用性是一个很重要的问题,简单的说,在网络通信中有客户端和服务端,一个负责发送请求,一个负责接收请求,在保证连接有效性的背景下,这两个物体扮演了什么角色,心跳机制能有效 ...
- 分析dubbo心跳检测机制
目的: 维持provider和consumer之间的长连接 实现: dubbo心跳时间heartbeat默认是60s,超过heartbeat时间没有收到消息,就发送心跳消息(provider,cons ...
- rabbitmq 的心跳机制&应用
官方文档说: If a consumer dies (its channel is closed, connection is closed, or TCP connection is lost) w ...
- zookeeper心跳机制流程梳理
zookeeper心跳机制流程梳理 Processor链Chain protected void setupRequestProcessors() { RequestProcessor finalPr ...
- 一个Socket连接管理池(心跳机制)
一个Socket连接管理池(心跳机制) http://cuisuqiang.iteye.com/blog/1489661
随机推荐
- Azure RBAC管理ASM资源
上一篇文章介绍了Azure基于ARM的RBAC,给不同的用户分配不同的权限. 但目前在国内使用的大部分用户还是以ASM的资源为主.比如:VM.Storage.Network.WebAPP.SQL Az ...
- Spring 自动注册及自动装配
Spring支持三种注册Bean及装配Bean的方式: 显式地在Java代码中注册及装配 显示地在Xml文件中注册及装配 隐式地装配,即自动注册及装配 这三种方式可以混合使用.选择哪种更多地是看个人品 ...
- [转]RegExp 构造函数创建了一个正则表达式对象,用于将文本与一个模式匹配
本文转自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp RegExp ...
- java 多线程系列基础篇(八)之join()、start()、run()方法
1. join()介绍 join() 定义在Thread.java中.join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行.这句话可能有点晦涩,我们还是通过例子去理解: // 主线程 ...
- mysql权限表
http://blog.csdn.net/zhangliangzi/article/details/51882710
- TypeError: 'append' called on an object that does not implement interface FormData 解决方法
使用ajax提交form表单时,$("formId").serialize()不能提交type="file"类型的input,这个时候可以选择使用FormDat ...
- Elasticsearch之curl创建索引
前提,是 Elasticsearch之curl创建索引库 [hadoop@djt002 elasticsearch-2.4.3]$ curl -XPUT 'http://192.168.80.200: ...
- Android上 dip、dp、px、sp等单位说明
dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA.HVGA和QVGA 推荐使用这个,不依赖像素. ...
- 使用Aspectj 的配置文件方式进行aop操作
- new与delete,malloc与free
1.new_delete与malloc_free ❶malloc/free: malloc原型: void *malloc(long NumBytes) 该函数分配了NumBytes个字节,并返回了指 ...