【ZooKeeper】zookeeper源码9-ZooKeeper读写流程源码分析

文章详细阐述了ZooKeeper在选举和状态同步后的服务启动过程,包括Leader和Follower的角色。重点介绍了SessionTracker的工作机制,使用时间轮和ExpiryQueue管理Session,确保超时和断开连接的处理。同时,概述了Leader和Follower的RequestProcessor初始化流程,以及客户端和服务端的初始化步骤。

ZooKeeper选举和状态同步结束之后的服务启动

在Leader的lead()方法的最后,即Leader完成了和集群过半Follower的同步之后,就会调用startZkServer()来启动必要的服务,主要包括:
SessionTracker
RequestProcessor
更新Leader ZooKeeperServer的状态

Leader.lead(){
   
   
	startZkServer(){
   
   
		zk.startup(){
   
   
			//ZooKeeperServer启动
			super.startup(){
   
   
				startupWithServerState(State.RUNNING);
			}
			//ZK Container ZNode定时清除任务
			if(containerManager != null){
   
   
				containerManager.start();
			}
		}
	}
}

同理,Follower也是一样的,在完成了和Leader的状态同步之后,也就是接收到Leader发送过来的NEWLEADER消息的时候,先拍摄快照,然后调用zk.startupWithoutServing()来启动Follower必要的一些基础服务,包括:
SessionTracker
RequestProcessor
更新Leader ZooKeeperServer的状态

Leader.syncWithLeader(long newLeaderZxid){
   
   
	//创建SessionTacker
	zk.createSessionTracker();
	//启动一些服务
	zk.startupWithoutServing(){
   
   
		startupWithoutServerState(State.INITIAL);
	}
}

不管Leader还是Follower,最后都执行startupWithServerState(State state),具体实现:

ZooKeeperServer.startupWithServerState(State state){
   
   
	//创建和启动SessionTracker 重要
	if(sessionTracker == null){
   
   
		createSessionTracker();
	}
	startSessionTracker();
	
	//初始化RequestProcessors 重要
	setupRequestProcessors();

	//其他各项基础服务
	startRequestThrottler();
	registerJMX();
	startJvmPauseMonitor();
	registerMetrics();

	//更新状态为RUNNING
	setState(state);

	//解除其他线程的阻塞
	notifyAll();
}

ZooKeeper SessionTracker启动和工作机制

需求背景:现在每个客户端链接到ZK服务器的时候,在服务器内部,都会创建一个Session来管理这个链接
如果链接断开,删除这个session
如果链接超时,删除这个session(在规定的超时时间前,没有任何动作)
会遇到什么问题?大量的session管理,ZK提供的方案:桶管理机制(Session管理,Connection管理)

在Leader启动的时候,Leader会创建LeaderSessionTracker,在Follower启动的时候,内部会创建一个LearnerSessionTracker。SessionTracker的内部都有globalSessionTracker和localSessionTracker之分,都通过SessionTrackerImpl和ExpiryQueue来完成Session管理。
SessionTrackerImpl的定义:时间轮

public class SessionTrackerImpl extends ZooKeeperCriticalThread implements SessionTracker {
   
   
	// 存储 session 信息,key 是 sessionID, value 是 Session 对象
	protected final ConcurrentHashMap<Long,SessionImpl> sessionById = new ConcurrentHashMap<Long,SessionImpl>();
	// SessionTrackerImpl 本身是一个线程
	// 注意这个数据结构,这是理解 Session 和 Connection 超时管理的关键,是一个类似于 时间轮 的数据结构设计
	// 将所有要进行管理的 Session 或者 Connection 加入到不同时刻对应的某个队列中,ZK 只会每隔一段时间,针对一个队列,进行全部过期操作处理
	private final ExpiryQueue<SessionImpl> sessionExpiryQueue;
	// 存储 session 的超时时间信息,key 是 sessionID, value 是 超时时间
	private final ConcurrentMap<Long,Integer> sessionWithTimeout;

	// SessionTrackerImpl 本身是一个线程
	public void run() {
   
   
		try {
   
   
			while(running) {
   
   
				// TODO 注释: 获取下一个队列的超时时间,等待
				long waitTime = sessionExpiryQueue.getWaitTime();
				if(waitTime > 0) {
   
   
					Thread.sleep(waitTime);
					continue;
				}
				// TODO 注释: 执行 expire
				for(SessionImpl s : sessionExpiryQueue.poll()) {
   
   
					ServerMetrics.getMetrics().STALE_SESSIONS_EXPIRED.add(1);
					setSessionClosing(s.sessionId);
					expirer.expires(s);
				}
			}
		} catch(InterruptedException e) {
   
   
            handleException(this.getName(), e);
        }
        LOG.info("SessionTrackerImpl exited loop!");
	}

	public synchronized boolean touchSession(long sessionId,int timeout) {
   
   
		SessionImpl s = sessionsById.get
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值