Zookeeper中Session Timeout的那些事

前言:

RDS系统致力于MySQL数据的高可用,高可靠,高性能以及在线扩展功能,实现这些特性的主要逻辑功能都运行在管理服务器上,一旦管理服务器宕机,数据库的在线扩展功能/备份功能/故障恢复功能等都无从谈起。然而,之前RDS系统管理服务器却是单点服务,为了保证整个系统的稳定性,管理服务器需要实现高可用,结合当前主流的高可用方案,决定使用Zookeeper来实现服务的高可用。

基本设计方案原理:

如下图所示,管理服务器A B C会在zk的root节点上注册临时序列节点/root/manager000000001  /root/manager000000002 /root/manager0000000003,序列最小的节点会被选为leader对外提供服务,其他节点作为热备节点随时准备升为leader。在此图中,A是leader,B C是standby。一旦A服务器因为某些原因宕机,zk就会将该服务器注册的临时节点移除掉,然后通知所有其他节点B C,B C会选出序列号最小的节点作为新的leader对外提供服务,此时B就会被选为新主。

血案现场:

会有这么一种比较特殊的场景需要考虑,比如当前leader是A BC都是备机。假如A和zk集群之间的网络出现了异常,A会收到一个连接状态被持久化为Disconnected的event,但是ZK Server并没有在这时移除A注册的临时节点,所以理论上A还是leader直至session timeout,session timeout后zk会将A注册的临时节点移除掉,然后通知B C选出新的leader,显而易见,B因为序列号小会成为新的leader。但是问题来了,session timeout的时候A的客户端并没有接收到任何notification,换句话说,它依然会认为自己是leader,这个时候就出现了这样的场景,A认为自己是leader,而B同样会认为自己是leader,即同时出现两个leader对外提供服务的情况。这很显然是不合理的,但如何深入地理解并解决这个问题呢?

个人认为理解并解决这个问题需要理解下面三个子问题:

1. 理解Zookeeper中Session的含义以及Connection Loss和Session Expired的关系

2. 理解Zookeeper中Session为什么由Server维护,而不由Client维护

3. 理解作为leader的A在整个流程中应该如何转变自己的角色,来避免脑裂

对zookeeper中Connection Loss和Session Expired的理解

Session是指当Client创建一个同Server的连接时产生的会话。连接Connected之后Session状态就开启,Zookeeper服务器和Client采用长连接方式(Client会不停地向Server发送心跳)保证session在不出现网络问题、服务器宕机或Client宕机情况下可以一直存在。因此,在正常情况下,session会一直有效,并且ZK集群上所有机器都会保存这个Session信息。

在ZK中,很多数据和状态都是和会话绑定的,一旦会话失效,那么ZK就开始清除和这个会话有关的信息,包括这个会话创建的临时节点和注册的所有Watcher。

一旦网络连接因为某种原因断开或者zk集群发生宕机,ZK Client会马上捕获到这个异常,封装为一个ConnectionLoss的事件,然后启动自动重连机制在地址列表中选择新的地址进行重连。重连会有三种结果:

(1)在session timeout时间内重连成功,client会重新收到一个syncconnected的event,并将连接重新持久化为connected状态

(2)超过session timeout时间段后重连成功,client会收到一个expired的event,并将连接持久化为closed状态

(3)一直重连不上,client将不会收到任何event

很显然,无论重连成功与否,在session timeout那个重要的时间点,ZK Client是接收不到任何ZK Server清理临时节点的信息的。这也就导致ZK会通知了B C节点A已经不再是Leader,A自身却没有接收到这样的信息,依旧对外提供服务,进而产生脑裂的问题。

Zookeeper中Session为什么由Server维护,而不由Client维护

可能很多朋友看了上面的讨论就会想为什么ZK Client不维护Session信息,如果这样做了,ZK Client就会在Session Timeout时得到相应的通知。

好,现在假如这样实现了,看看会发生什么。设想有这么一种真实场景,某个连接的Session Timeout是15s,ZK集群因为未知原因发生宕机,5min之后集群恢复成功。在Session Timeout时,ZK Client确实可以知道Session失效,然后做降主操作,但是ZK Server却不知道Session已经失效,也就不会通知其他节点选出新的Leader,此时整个系统实际上处于没有Leader的状态。即使5min之后重连成功,因为旧Session对应的临时节点没有被清理且序号最小,ZK依然会认为Leader是该临时节点,而实际上该临时节点对应不到任何的ZK Client,所以这种情况下系统依然选不出Leader。

可见,如果由Client维护Session,在某些场景下(网络异常或者集群宕机时间超过Session Timeout),由于逻辑问题根本选不出Leader。

因此这种方案是不可行的。

那能不能从应用层面避免脑裂问题呢?带着问题进入下个部分。

避免脑裂问题:作为leader的A在整个流程中应该如何转变自己的角色

因为ZK本身的设计使得这种场景下没有一个完美的解决方案,可以考虑采用退化的方案进行处理。

A在接收到DisConnected事件后就降主,不对外提供服务。然后等待接下来的发生的事情,首先可能发生的事件是在Session Timeout时间段内重连成功得到SyncConnected事件,这时A可以重新升级为主,对外提供服务。如果这段时间内没有重连成功,ZK Server在Session Timeout时会将A注册的临时节点移除,并通知B和C A已经停止对外服务了,需要选出新的leader。因为A自己已经降主了,所以在选出新leader后也不会出现多主现象。如果A在Session Timeout时间段外重连又成功了,那此时肯定新的leader已经选出来了,A需要重新注册作为新的备机候选。

可以使用如下的流程图解释这个过程:

这种应用层面的方案在一定程度上解决了脑裂问题,但是会出现一段时间系统无Leader的情况,持续时间最长为Session超时时间。

总结:

结合上述分析,可以针对Session Timeout的问题得出一个应用层面的解决方案,即Client分阶段转变角色方案。如下图所示,箭头上方红色标示表示Client所处不同阶段,箭头下方蓝色标示表示Client在不同阶段的角色转变。

本文章为作者原创

??禁止??

其他公众账号转载,若有转载,请标明出处

时间: 2024-10-20 04:12:35

Zookeeper中Session Timeout的那些事的相关文章

asp.net中session的原理及应用

Session简介丶特性 1.Session是一种Web会话中的常用状态之一. 2.Session提供了一种把信息保存在服务器内存中的方式.他能储存任何数据类型,包含自定义对象. 3.每个客户端的Seesion是独立存储的. 4.在整个会话过程中,只要SessionID的cookie不丢失,都会保存Session信息的. 5.Session不能跨进程访问,只能由该会话的用户访问.应为提取Session数据的id标识是以Cookie的方式保存到访问者浏览器的缓存里的. 6.当会话终止,或过期时,服

ASP.NET中Session的sessionState 4种mode模式

1. sessionState的4种mode模式 在ASP.NET中Session的sessionState的4中mode模式:Off.InProc.StateServer及SqlServer. 2. Off模式 <sessionState mode="Off"></sessionState> 关闭模式,即不需要使用Session. 单个页面关闭Session: <%@ Page EnableSessionState="false" %

zookeeper中Watcher和Notifications

问题导读:1.zookeeper观察者什么时候调用?2.传统远程轮询服务存在什么问题?3.zk中回调服务的机制是什么?4.zk中watcher为什么不永久注册?5.什么是znode? 在阅读之前首先明确个概念:1.什么是znode? 2.什么是客户端? 我们使用znode这个术语来表示ZooKeeper的数据节点. znode维持一个stat结构,它包含数据变化的版本号.ACL变化和时间戳,以允许cache校验和协调化的更新.每当znode的数据变化时,版本号将增加.一个客户端收到数据时,它也会

hibernate中session线程安全的实现

在hibernate中session是使用ThreadLocal实现线程安全的. ThreadLocal并不是一个Thread,而是一个线程副本,ThreadLocal为每个使用该变量的线程提供一个变量副本,线程修改自己的变量副本不会影响其他线程的变量副本 ThreadLocal有四个方法: set():设置当前线程的局部变量的值 get():获取当前线程的局部变量的值 remove():将当前线程局部变量的值删除,此方法不必显示的调用,因为局部变量自有垃圾回收器去清理 initialValue

HttpSession与Hibernate中Session的区别

HttpSession与Hibernate中Session的区别 一.javax.servlet.http.HttpSession是一个抽象接口 它的产生:J2EE的Web程序在运行的时候,会给每一个新的访问者建立一个HttpSession,这个Session是用户身份的唯一表示.注意,是容器(Tomcat,Resin)自动创建的. 用途:存放这个用户的一些经常被用到的信息,例如:用户名,权限.例如在购物车程序里,存放用户买的商品. 销毁:一定时间(跟容器有关)内,用户无任何动作,session

Session Timeout 与 $.ajaxSetup

对于session过期跳转的问题,很简单,就是一个过滤器,然后判断session为空?跳转:继续.但是对于ajax的请求,需要做特殊处理,见下面代码中的 // 此处考虑ajax操作session过期的操作,如果ajax请求过程中session过期,则指定过期状态码为:911.String requestType = req.getHeader("X-Requested-With"); 因为ajax请求的时候请求头是:X-Requested-With,so我们可以根据该请求头做sessi

ASP.NET中Session的个人浅谈

看到博客园的一个哥们写的面试经历,想到了面试中常问到的Session,一时手痒就谈下自己对Session的理解,这东西最开始在用户登录登出的时候用到过,后来一直没怎么用过,里面还是有很多知识点值得注意的.先简单的说下吧,Session是分为客户端Session和服务端Session: 客户端Session Session称为会话状态,是Web系统中最常用的状态,用于维护和当前浏览器实例相关的一些信息,当用户首次与Web服务器建立连接的时候,服务器会给当前访问用户分发一个 SessionID作为标

.net中session的使用

什么是Session? Session即会话,是指一个用户在一段时间内对某一个站点的一次访问. Session对象在.NET中对应HttpSessionState类,表示"会话状态",可以保存与当前用户会话相关的信息. Session对象用于存储从一个用户开始访问某个特定的aspx的页面起,到用户离开为止,特定的用户会话所需要的信息.用户在应用程序的页面切换时,Session对象的变量不会被清除.   如何使用Session? 对于一个Web应用程序而言,所有用户访问到的Applica

通过Global.asax文件里面的Session_End事件记录用户退出 (or session timeout)

Session.Abandon()和timeout会触发Global.asax的Session_End事件.可以通过这个事件来记录用户退出或者session timeout,这样每个用户都会有一条登陆和退出记录. 退出登陆调用方法: public void PerformLogout() { HttpContext.Current.Session["PerformLogout"] = true; HttpContext.Current.Session.Abandon(); } Sess