zookeeper 的心跳
假定:主机 A, B 通过 tcp 连接发送数据,如果拔掉 A 主机的网线,B 是无法感知到的。但是如果 A 定时给 B 发送心跳,则能根据心跳的回复来判断连接的状态。
以 zookeeper 为例:zk client 会记录上一次发送数据的时间(lastSend)和上一次接收数据的时间(lastHeard),zk client 给 server 发送心跳(ping),这些心跳和其他命令一起发送给 zk server,如果 zk client 发现好长的时间没有接收到数据,认为超时,则断开与 server 的连接,并重连服务器。
// zookeeper 3.3.3
// void org.apache.zookeeper.ClientCnxn.SendThread.run()
public void run() {
long now = System.currentTimeMillis();
long lastHeard = now;
long lastSend = now; // 这里的 zooKeeper 是客户端
while (zooKeeper.state.isAlive()) {
try {
if (sockKey == null) {
// don't re-establish connection if we are closing
if (closing) {
break;
}
// 连接 zk server
startConnect();
lastSend = now;
lastHeard = now;
}
int idleRecv = (int) (now - lastHeard);
int idleSend = (int) (now - lastSend);
int to = readTimeout - idleRecv;
if (zooKeeper.state != States.CONNECTED) {
to = connectTimeout - idleRecv;
}
// 接收数据超时,抛异常,异常会在后面的 catch 块中处理
if (to <= 0) {
throw new SessionTimeoutException(
"Client session timed out, have not heard from server in "
+ idleRecv + "ms"
+ " for sessionid 0x"
+ Long.toHexString(sessionId));
}
if (zooKeeper.state == States.CONNECTED) {
int timeToNextPing = readTimeout/2 - idleSend;
// 发送 ping 命令(心跳),更新 lastSend
if (timeToNextPing <= 0) {
sendPing();
lastSend = now;
enableWrite();
} else {
if (timeToNextPing < to) {
to = timeToNextPing;
}
}
} selector.select(to);
Set<SelectionKey> selected;
synchronized (this) {
selected = selector.selectedKeys();
}
// Everything below and until we get back to the select is
// non blocking, so time is effectively a constant. That is
// Why we just have to do this once, here
now = System.currentTimeMillis();
for (SelectionKey k : selected) {
SocketChannel sc = ((SocketChannel) k.channel());
if ((k.readyOps() & SelectionKey.OP_CONNECT) != 0) {
if (sc.finishConnect()) {
lastHeard = now;
lastSend = now;
primeConnection(k);
}
} else if ((k.readyOps() & (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) != 0) {
if (outgoingQueue.size() > 0) {
// We have something to send so it's the same
// as if we do the send now.
lastSend = now;
}
if (doIO()) {
lastHeard = now;
}
}
}
if (zooKeeper.state == States.CONNECTED) {
if (outgoingQueue.size() > 0) {
enableWrite();
} else {
disableWrite();
}
}
selected.clear();
} catch (Exception e) {
if (closing) {
if (LOG.isDebugEnabled()) {
// closing so this is expected
LOG.debug("An exception was thrown while closing send thread for session 0x"
+ Long.toHexString(getSessionId())
+ " : " + e.getMessage());
}
break;
} else {
// this is ugly, you have a better way speak up
if (e instanceof SessionExpiredException) {
LOG.info(e.getMessage() + ", closing socket connection");
} else if (e instanceof SessionTimeoutException) {
LOG.info(e.getMessage() + RETRY_CONN_MSG);
} else if (e instanceof EndOfStreamException) {
LOG.info(e.getMessage() + RETRY_CONN_MSG);
} else {
LOG.warn("Session 0x"
+ Long.toHexString(getSessionId())
+ " for server "
+ ((SocketChannel)sockKey.channel())
.socket().getRemoteSocketAddress()
+ ", unexpected error"
+ RETRY_CONN_MSG,
e);
}
// 断开连接
cleanup();
if (zooKeeper.state.isAlive()) {
eventThread.queueEvent(new WatchedEvent(
Event.EventType.None,
Event.KeeperState.Disconnected,
null));
} now = System.currentTimeMillis();
lastHeard = now;
lastSend = now;
}
}
}
cleanup();
try {
selector.close();
} catch (IOException e) {
LOG.warn("Ignoring exception during selector close", e);
}
if (zooKeeper.state.isAlive()) {
eventThread.queueEvent(new WatchedEvent(
Event.EventType.None,
Event.KeeperState.Disconnected,
null));
}
ZooTrace.logTraceMessage(LOG, ZooTrace.getTextTraceLevel(),
"SendThread exitedloop.");
}
zk server 对 session 也会有一个跟踪,它也会关掉超时的 session,具体逻辑在
void org.apache.zookeeper.server.SessionTrackerImpl.run()
zk server 每收到一个请求,就会触发 touchSession

zookeeper 的心跳的更多相关文章
- zookeeper(单机/集群)安装与配置
一.安装与单机配置 1.下载: wget http://archive.apache.org/dist/zookeeper/stable/zookeeper-3.4.6.tar.gz 如果网站下载不了 ...
- zookeeper dubbo 问题解决录
问题1: 运行起来不报错,不过在Console没有zookeeper的心跳信息,也就是说没有配置上zookeeper,而出错的原因是下面蓝色这段解析不了 spring-dubbo-provider.x ...
- Zookeeper集群的安装和使用
Apache Zookeeper 由 Apache Hadoop 的 Zookeeper 子项目发展而来,现已经成为 Apache 的顶级项目,它是一个开放源码的分布式应用程序协调服务,是Google ...
- dubbo与zookeeper的关系
Dubbo建议使用Zookeeper作为服务的注册中心. 1. Zookeeper的作用: zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知道,简单来说就是 ...
- spring Boot环境下dubbo+zookeeper的一个基础讲解与示例
一,学习背景 1. 前言 对于我们不管工作还是生活中,需要或者想去学习一些东西的时候,大致都考虑几点: a) 我们为什么需要学习这个东西? b) 这个东西是什么? c) ...
- linux下配置zookeeper注册中心及运行dubbo服务
dubbo和zookeeper的关系 简单来说打个比方:dubbo就是动物园的动物,zookeeper是动物园.如果游客想看动物的话那么就去动物园看.比如你要看老虎,那么动物园有你才能看到.换句话说我 ...
- Zookeeper(一)CentOS7.5搭建Zookeeper3.4.12集群与命令行操作
一. 分布式安装部署 1.0 下载地址 官网首页: https://zookeeper.apache.org/ 下载地址: http://mirror.bit.edu.cn/apache/zookee ...
- 为什么zookeeper会导致磁盘IO高【转】
由于早期的storm版本心跳信息严重依赖zookeeper,心跳风暴会导致zookeeper的事务日志频繁的写磁盘,带来的问题首当其冲的是磁盘IO会爆掉. 优化思路 将zookeeper事务的日志放入 ...
- zookeeper和dubbo的关系
Dubbo建议使用Zookeeper作为服务的注册中心. 1. Zookeeper的作用: zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知 ...
随机推荐
- 在Idea创建Spring Boot + MyBatis的web项目
创建步骤如下 选择Spring initializr 2. 修改group 与 atifact id,点击next 3. dependencies里面选择Web->Web , SQL -> ...
- 【Mysql】外键
MYSQL数据表建立外键 MySQL创建关联表可以理解为是两个表之间有个外键关系,但这两个表必须满足三个条件 1.两个表必须是InnoDB数据引擎 2.使用在外键关系的域必须为索引型(Index) 3 ...
- async函数对比Generator函数
首先定义一个读取文件的异步函数 var readFile = function(fileName){ return new Promise((resolve,reject)=>{ fs.read ...
- list转化为json数组
今天做项目,用Thrift获取数据,在servlet里面获取的是数组,但是通过Ajax传输到js文件里是一个list,我获取长度失败,这个时候需要将list转化为json数组,我们可以通过eval() ...
- Easyui使用心得(1)--DateGrid表格
最近一直在用easyui这个控件,有一点心得,在这里和大家分享一下,也是对自己工作的一个小小的总结,希望可以形成一个完整的Easyui的笔记体系,可以方便更多的人 因为自己也是在摸索中前进,难免有遗漏 ...
- JDBC Connection Configuration
如果在Jmeter 中想用到连接数据库的功能,必须下载jar包,常见的关系型数据库jar包见以下共享链接 链接:https://pan.baidu.com/s/1t-k9RW141lw0j_QSw53 ...
- 让DOM从页面中消失的方法
1. 在隐藏的方法中,display取none值这种方法一般是不可取的!因为display:none是直接不显示,也就是不渲染此元素,如果它所作用的元素排版在页面较前,先渲染,就容易引起回流(refl ...
- linux c/c++ 文件是否存在
linux c/c++ 文件是否存在 #include <unistd.h> int FileExist(const char* fname) { return access(fname, ...
- Qt5模型/视图结构-视图(View)
实现自定义的View,可继承自QAbstractItemView类,对所需的纯虚函数进行重定义与实现,对于QAbstractItemView类中的纯虚函数,在子类中必须进行重定义,但不一定要实现,可根 ...
- centos 7 安装TensorFlow
查看linux版本 uname -a 查看磁盘大小 准备好python 2.7 查看python版本 import sysprint sys.version print sys.version_in ...