Zookeeper技术原理(二):会话session管理、客户端请求处理

会话机制

Session

代表一个客户端与服务端之间的会话,包含以下4个基本属性:

  1. sessionID:每一个sessionID都是全局唯一的,用来唯一的标识一个会话。SessionTracker(会话管理器,负责会话创建、管理和删除)初始化的时候,会生成一个初始sessionID(高8位为当前机器配置的SID,低54位为时间戳),然后在每次建立会话时,服务端递增该sessionID并返回给客户端,作为当前session的唯一标识;
  2. TimeOut:建立会话时,客户端会在连接请求中指定超时时间,服务端会根据自己的超时时间限制最终确定会话的超时时间;
  3. TickTime:下次超时时间点,用于服务端对会话进行分桶管理;
  4. isClosing:用于标识一个会话是否已经被关闭;

分桶策略

ZK服务端通过SessionTracker的分桶策略来管理所有的会话。具体来说,SessionTracker将所有的会话按照下一次超时时间点的不同来分类(每一个类就是一个桶,对应的数据结构为Set<超时时间点, Set>)。当一个会话新建立时,其下一个超时时间点为currentTime+TimeOut,然后向上取整为SessionTracker进行超时检查间隔的整数倍,此后服务端每收到客户端的消息就会按照该方式来修改会话的超时时间点。所以会话的下一次超时时间点都是SessionTracker超时检查间隔的整数倍,并且每一个超时时间点处都对应了一批会话session。

客户端会每隔一段时间向服务端发送心跳消息,服务端收到心跳消息后会计算一个新的超时时间点,然后将会话从旧的超时时间点对应的桶迁移到新的桶中。

SessionTracker中有一个专门的线程负责进行会话超时检查,该线程是一个定时任务,每隔一个超时检查间隔执行一次超时检查,找到该时刻对应的会话桶中剩余的所有没有迁移的会话,这些会话就是超时的会话。

收集到超时的会话后,需要关闭这些会话,具体来说有以下步骤:

  1. 标记会话状态为已关闭,这样就不用再去处理客户端请求了;
  2. 收集需要清理的临时结点,在ZK的内存数据库中为每个会话都保存了一份由该会话创建的临时结点的集合;
  3. 为每一个收集到的结点创建一个结点删除的事务请求,并提交给处理器链去处理;
  4. 从SessionTracker中移除超时会话,然后关闭TCP连接;

请求处理

ZK服务端使用责任链模式来处理每一个客户端请求,同时为了保证事务请求被顺序执行,从而保证分布式数据一致性,所有的事务请求都必须由Leader来执行,非Leader服务器如果收到事务请求,需要将其转发给Leader服务器来处理。各个角色的处理器链如下:

Leader:

img

Follower:

在这里插入图片描述

Observer:与Follower一样可以处理非事务请求,但是它不参与投票,可以在不影响事务处理能力的前提下,提升集群非事务处理能力

在这里插入图片描述

  • PrepRequestProcessor:请求预处理器,能够识别出当前客户端请求是否是事务请求。对于事务请求,该处理器会对其进行一系列预处理,如创建请求事务头、事务体、会话检查、ACL检查和版本检查等。

  • FollowerRequestProcessor/ObserverRequestProcessor:判断当前请求是否为事务请求,如果是将其转发给Leader去处理,否则交付给下一个处理器。

  • ProposalRequestProcessor:事务投票处理器,Leader服务器事务处理流程的发起者,对于非事务性请求,该处理器会直接将请求直接转发转发到CommitProcessor处理器,不再做任何处理;而对于事务性请求,处理将请求转发到CommitProcessor外,还会根据请求类型创建对应的Proposal提议,并发送给所有的Follower服务器来发起一次集群内的事务投票。同时,ProposalRequestProcessor还会将事务请求交付给SyncRequestProcessor进行事务日志的记录。

  • SyncRequestProcessor:事务日志记录处理器,将事务请求记录到事务日志文件中,同时会触发ZK进行数据快照。

  • AckRequestProcessor/SendAckRequestProcessor:负责在SyncRequestProcessor完成事务日志记录后,向Proposal的投票收集器发送ACK反馈。

  • CommitProcessor:事务提交处理器。对于非事务请求,该处理器会直接将其交付给下一级处理器处理;对于事务请求,其会阻塞等待集群内针对Proposal的投票直到该Proposal可被提交,利用CommitProcessor,每个服务器都可以很好地控制对事务请求的顺序处理。

  • FinalRequestProcessor:用来进行客户端请求返回之前的操作,包括执行请求对应的操作、创建客户端请求的响应等,针对事务请求,该处理还会负责将事务应用到内存数据库中去。

请求处理流程(这里以Leader为例):

  1. 从IO层接收到来自客户端的请求;
  2. 判断当前请求是否为会话创建请求,服务端和每一个客户端通过ServerCnxn来维护一个连接,所以如果ServerCnxn未被初始化过,就是会话创建请求。如果是会话创建请求,会协商超时时间、生成sessionID和会话密码、将其注册到sessionTracker中;
  3. 将请求交给PrepRequestProcessor处理器处理,如果是非事务请求则直接传递给下一个处理器,如果是事务请求,在这里会创建请求事务头和请求事务体,事务头中包含了sessionID、客户端的操作序列号cxid、Leader为该事务请求生成的zxid等内容,并且会进行ACL检查。然后还会创建ChangeRecord记录并将其放入到outstandingChanges队列中(事务被提交后从队列中删除),该队列的作用是记录当前服务器正在处理的事务请求,以便处理后续请求(流水线式地处理请求)的过程中需要针对之前客户端请求进行相关处理,比如说会话关闭请求,在收集临时结点时就不需要去收集outstandingChanges队列中删除结点请求对应的那些节点;
  4. 将请求交给ProposalRequestProcessor处理器,如果是非事务请求则直接传递给下一个处理器CommitProcessor,不做其他任何处理。如果是事务请求则会进行以下3个操作:①生成提议Proposal,并将其广播给其它所有服务器,然后收集投票结果,其他服务器收到提议后会进行事务日志的记录,完成以后会发送Ack给Leader;②同时将提议传给SyncRequestProcessor处理器,进行Leader上的事务日志记录,完成以后给ProposalRequestProcessor处理器发送一个Ack;③将请求传递给CommitProcessor处理器,然后阻塞在这里等待提议的投票结果。当收集到半数以上的服务器投票认可后,会向其它服务器广播事务提交COMMIT消息,然后唤醒阻塞线程。
  5. 被唤醒后commit流程会将请求传递给FinalRequestProcessor处理器,这里才是请求被真正执行的地方,此时会将事务变更应用到内存数据库中去,或者完成非事务请求的执行;
  6. 最后,会创建响应,然后将其序列化后通过IO层发送给客户端;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值