Apache ZooKeeper - 集群中 Leader 的作用_事务的请求处理与调度分析

举报
小工匠 发表于 2021/09/11 00:53:27 2021/09/11
【摘要】 文章目录 事务性请求处理Leader 事务处理分析预处理阶段事务处理阶段事务执行阶段响应阶段 源码分析小结 Leader 服务器在 ZooKeeper 中的作主要是处理事务性的会话请...

在这里插入图片描述

Leader 服务器在 ZooKeeper 中的作主要是处理事务性的会话请求以及管理 ZooKeeper 集群中的其他角色服务器

那么 在接收到来自客户端的事务性会话请求后,ZooKeeper 集群内部又是如何判断会话的请求类型,以及转发处理事务性请求的呢?


事务性请求处理

在 ZooKeeper 集群接收到来自客户端的会话请求操作后,首先会判断该条请求是否是事务性的会话请求。

对于事务性的会话请求,ZooKeeper 集群服务端会将该请求统一转发给 Leader 服务器进行操作。Leader 服务器内部执行该条事务性的会话请求后,再将数据同步给其他角色服务器,从而保证事务性会话请求的执行顺序,进而保证整个 ZooKeeper 集群的数据一致性。

在这里插入图片描述

在 ZooKeeper 集群的内部实现中,是通过什么方法保证所有 ZooKeeper 集群接收到的事务性会话请求都能交给 Leader 服务器进行处理的呢?

在 ZooKeeper 集群内部,集群中除 Leader 服务器外的其他角色服务器接收到来自客户端的事务性会话请求后,必须将该条会话请求转发给 Leader 服务器进行处理。 ZooKeeper 集群中的 Follow 和 Observer 服务器,都会检查当前接收到的会话请求是否是事务性的请求,如果是事务性的请求,那么就将该请求以 REQUEST 消息类型转发给 Leader 服务器。

在 ZooKeeper集群中的服务器接收到该条消息后,会对该条消息进行解析。分析出该条消息所包含的原始客户端会话请求。之后将该条消息提交到自己的 Leader 服务器请求处理链中,开始进行事务性的会话请求操作。如果不是事务性请求,ZooKeeper 集群则交由 Follow 和 Observer 角色服务器处理该条会话请求,如查询数据节点信息。


Leader 事务处理分析

以客户端发起的创建节点请求 setData 为例,具体看看 ZooKeeper 集群的底层处理过程。

在 ZooKeeper 集群接收到来自客户端的一个 setData 会话请求后,其内部的处理逻辑基本可以分成四个部分 ,分别是预处理阶段、事务处理阶段、事务执行阶段、响应客户端。

在这里插入图片描述

预处理阶段

在预处理阶段,主要工作是通过网络 I/O 接收来自客户端的会话请求。判断该条会话请求的类型是否是事务性的会话请求,之后将该请求提交给PrepRequestProcessor 处理器进行处理。封装请求事务头并检查会话是否过期,最后反序列化事务请求信息创建 setDataRequest 请求,在 setDataRequest 记录中包含了要创建数据的节点的路径、数据节点的内容信息以及数据节点的版本信息。最后将该请求存放在 outstandingChanges 队列中等待之后的处理。
在这里插入图片描述


事务处理阶段

在事务处理阶段,ZooKeeper 集群内部会将该条会话请求提交ProposalRequestProcessor 处理器进行处理。

在这里插入图片描述


事务执行阶段

在经过预处理阶段和事务会话的投票发起等操作后,一个事务性的会话请求都已经准备好了,接下来就是在 ZooKeeper 的数据库中执行该条会话的数据变更操作。

在处理数据变更的过程中,ZooKeeper 内部会将该请求会话的事务头和事务体信息直接交给内存数据库 ZKDatabase 进行事务性的持久化操作。之后返回 ProcessTxnResult 对象表明操作结果是否成功。

在这里插入图片描述

响应阶段

在 ZooKeeper 集群处理完客户端 setData 方法发送的数据节点创建请求后,会将处理结果发送给客户端。

在响应客户端的过程中,ZooKeeper 内部首先会创建一个 setDataResponse 响应体类型,该对象主要包括当前会话请求所创建的数据节点,以及其最新状态字段信息 stat。

之后创建请求响应头信息,响应头作为客户端请求响应的重要信息,客户端在接收到 ZooKeeper 集群的响应后,通过解析响应头信息中的事务 ZXID 和请求结果标识符 err 来判断该条会话请求是否成功执行。

在这里插入图片描述


源码分析

首先,ZooKeeper 集群在收到客户端发送的事务性会话请求后,会对该请求进行预处理。在代码层面,ZooKeeper 通过调用 PrepRequestProcessor 类来实现预处理阶段的全部逻辑。

可以这样理解:在处理客户端会话请求的时候,首先调用的就是 PrepRequestProcessor 类。而在 PrepRequestProcessor 内部,是通过 pRequest 方法判断客户端发送的会话请求类型。如果是诸如 setData 数据节点创建等事务性的会话请求,就调用 pRequest2Txn 方法进一步处理。

protected void pRequest(Request request){

...

  switch (request.type) {

  case OpCode.setData:

    SetDataRequest setDataRequest = new SetDataRequest();                

    pRequest2Txn(request.type, zks.getNextZxid(), request, setDataRequest, true);

    break;

   }

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

而在 pRequest2Txn 方法的内部,就实现了预处理阶段的主要逻辑。如下面的代码所示,首先通过 checkSession 方法检查该条会话请求是否有效(比如会话是否过期等),之后调用 checkACL 检查发起会话操作的客户端在 ZooKeeper 服务端是否具有相关操作的权限。最后将该条会话创建的相关信息,诸如 path 节点路径、data 节点数据信息、version 节点版本信息等字段封装成setDataRequest 类型并传入到 setTxn 方法中,最后加入处理链中进行处理。

case OpCode.setData:

    zks.sessionTracker.checkSession(request.sessionId, request.getOwner());

    SetDataRequest setDataRequest = (SetDataRequest)record;

    if(deserialize)

        ByteBufferInputStream.byteBuffer2Record(request.request, setDataRequest);

    path = setDataRequest.getPath();

    validatePath(path, request.sessionId);

    nodeRecord = getRecordForPath(path);

    checkACL(zks, request.cnxn, nodeRecord.acl, ZooDefs.Perms.WRITE, request.authInfo, path, null);

    int newVersion = checkAndIncVersion(nodeRecord.stat.getVersion(), setDataRequest.getVersion(), path);

    request.setTxn(new SetDataTxn(path, setDataRequest.getData(), newVersion));

    nodeRecord = nodeRecord.duplicate(request.getHdr().getZxid());

    nodeRecord.stat.setVersion(newVersion);

    addChangeRecord(nodeRecord);


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

小结

主要梳理了 ZooKeeper 集群中 Leader 服务器是如何处理事务性的会话请求的,并且在处理完事务性的会话请求后,是如何通知其他角色服务器进行同步操作的。

可以说在 ZooKeeper 集群处理事务性的请过程中,Follow 和 Observer 服务器主要负责接收客户端的会话请求,并转发给 Leader 服务器。而真正处理该条会话请求的是 Leader 服务器。

这就会引发一个问题:当一个业务场景在查询操作多而创建删除等事务性操作少的情况下,ZooKeeper 集群的性能表现的就会很好。

而如果是在极端情况下,ZooKeeper 集群只有事务性的会话请求而没有查询操作,那么 Follow 和 Observer 服务器就只能充当一个请求转发服务器的角色, 所有的会话的处理压力都在 Leader 服务器。

在处理性能上整个集群服务器的瓶颈取决于 Leader 服务器的性能。ZooKeeper 集群的作用只能保证在 Leader 节点崩溃的时候,重新选举出 Leader 服务器保证系统的稳定性。这也是 ZooKeeper 设计的一个缺点。

在这里插入图片描述

文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。

原文链接:artisan.blog.csdn.net/article/details/111658214

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。