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
随机推荐
- jraiser模块加载执行简要总结
1 在html文件中,通过require方式来加载指定的入口文件:2 然后通过正则表达式来匹配入口文件中的所有require的依赖文件:注意,此时入口文件已加载完毕,不过,还没执行而已.3 之后逐一通 ...
- virtualvm一次插件安装想到的
在麒麟操作系统visualvm安装插件失败,因为使用的内网,所以在官网下载了插件到本地:因为本地安装的jdk1.6,为了享受jdk1.8,在visualvm文件中增加了对于jdk1.8的引用: exp ...
- gitlab init project
Command line instructions Git global setup git config --global user.name "zxpo" git config ...
- nginx与二级域名的绑定 nginx安装
nginx中文文档 http://www.nginx.cn/doc/ nginx 查看配置文件地址 http://blog.csdn.net/ljfrocky/article/details/5052 ...
- div 遮罩层 弹窗
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- java代码swing编程JPaswordField类
总结:JPasswordField类是JTextField类的子类.用户在JPasswordField对象中输入的字符会被其他的字符替代 而挡住,JPasswordFiled组件主要用来输入口令 pa ...
- 查看,创建,删除,映射rbd镜像
标签(空格分隔): ceph,ceph实验,pg 1. 创建镜像: [root@node3 ~]# rbd create testpool/foo --size 1024 2. 查看镜像信息: [ro ...
- C# IL中间代码注入实现切面编程
背景及现状:之前分享的那篇“面向切面编程–渲染监控日志记录方案”中提供了利用RealProxy作为代理类来生成代理的面向切面的编程方法,那个方法可以实现面向切面编程进行日志记录,现在渲染主程序也是采用 ...
- navicat for mysql ,mysql版本是8.0的版本,连接数据库报错1251,解决办法。
我的mysql版本是8.0的版本,因为毕竟新的mysql采用新的保密方式,所以就的似乎不能用,改密码方式: 用管理员身份打开cmd mysql -uroot -p(输入密码) 进 ...
- 为什么in_array(0, ['a', 'b', 'c'])返回true
为什么in_array(0, ['a', 'b', 'c'])返回true 目录 1 类型转换 2 严格比较 3 false和null 4 数组中有true 在PHP中,数据会自动转换类型后进行比较. ...