当前位置: 首页 > news >正文

zookeeper - 多线程分析(10)

概述

    这篇文章目的主要是为了讲解清楚zookeeper启动过程中启动各类服务,说白了就是启动了线程提供服务,希望通过这个文章的梳理能够让大家对整个zookeeper的线程架构有一个清晰的印象。

线程分析

整个zookeeper的线程按照功能进行划分,主要分为下面5类,分别是 选举相关线程Client连接相关线程Peer连接相关线程Peer调用链线程quorumPeer线程

img_f01a64fc503a5f83f392cc38a4582a13.png
zookeeper线程分析

选举相关线程

    选举相关线程顾名思义,就是在zookeeper集群发生重新选举的时候用于处理选举相关的线程,核心类在于FastLeaderElection,该类内部包含WorkerReceiverWorkerSender两个核心线程,负责发送和接收选举报文。 

    FastLeaderElection本身其实就在一个单独的线程,也就是后面说的quorumPeer线程中运行的,本身内部具备一个while循环再处理选举相关的逻辑,所以可以认为FastLeaderElection也是一个线程。

img_063b35d175e02026fabddb8d54e619b4.png
选举相关线程


img_1b3744ef3f50e42284a9496211843e86.png
quorumPeer的选举线程


img_920e4a097ed96fa26b261fdadfeacf83.png
FastLeaderElection


Client连接相关线程

    client连接相关线程顾名思义,就是zookeeper在处理client连接过程中相关的线程,其实zookeeper在实现的server的多线程模型其实就是Nio模型中提到的相关模型,有兴趣可以阅读《netty概念小结》。

    该实现的核心类主要是NIOServerCnxnFactory,该类内部包含expirerThread、acceptThread、selectorThreads,这里我只关注后面两者,其中acceptThread主要负责处理client的连接,selectorThreads主要负责处理每个client具体的数据读写,也就是说我们把accept和io处理进行了分离。


img_be4b0e6c7464c00d80da41cdb7e36e05.png
accept线程


img_457c146e69939787a59af2573770cf71.png
selector线程


Peer连接相关线程

    peer之间的连接主要是zookeeper集群间通信的连接,一般是指follower或learner连接server的过程。当我们的一个zookeeper节点作为leader的时候我们会启动一个accept线程LearnerCnxAcceptor用于接受peer的连接,作为server端我们会为每个peer发送过来的连接建立一个线程进行处理,针对每个连接新建线程的核心类是LearnerHandler。

    这部分的accept线程LearnerCnxAcceptor和处理线程LearnerHandler主要用于zookeeper的节点之间的通信,跟client无关,跟client无关,跟client无关

img_40c52c0b9e505060e5c46415f0271567.png
LearnerCnxAcceptor
img_be3034d31ee7f5a7016e63881800537c.png
LearnerHandler



Peer调用链线程


img_0c436ba75ed2d614ac9eb3aeeeb441c4.png
leader调用链


img_0613b99695b6a7ce63bbfffb7912f181.png
follower调用链

PrepRequestProcessor 

    PrepRequestProcessor线程。该线程消费请求队列submittedRequests,开始实施一致性算法。submittedRequests有两个来源,一是接入的客户端直接提交,提交的请求既包括写请求,也包括一些查询请求;另一个是由Follower转发,转发内容只包括写请求和同步请求。PrepRequestProcessor收到submittedRequest后,将请求转发给CommitProcessor线程和SyncRequestProcessor线程的输入队列;对于其中的写请求,向所有follower发送PROPOSAL消息(异步发送)。

img_63c8517e4b05fc4d80a5a54ee8998882.png
PrepRequestProcessor


CommitProcessor

    该线程主要消费两个队列queuedRequests和committedRequests。queuedRequests保存PrepRequestProcessor线程下发的submittedRequest消息。committedRequests保存Proposal通过后,LearnerHanlder线程(后文会有说明)发来的提交请求。

    CommitProcessor在这里做了如下处理:对于queuedRequests中客户端的查询request,直接返回本地数据;对于客户端提交的或follower转发来的写请求,作为一个pendingRequest等待相应的表决结果返回committedRequest到committedRequests队列。对于队列中到来的每一个committedRequest,如果当前有pendingRequest等待,并且其sessionId,zxid和这个请求匹配,则处理pendingRequest(如果原始请求发自客户端,pendingRequest会携带客户端连接对象,从而能够发送响应给客户端),否则直接处理committedRequest(这种情况对应Follower中的CommitProcessor直接接收到了commit消息)。处理的过程是记录committedLog,变更本地数据。如果请求从客户端来,发送响应给客户端。那么如果一个pendingRequest始终等不到对应的committedRequest到来呢?答案是会一直等待,从而会阻止之后所有queuedRequest请求的处理!开始看到这里以为是个bug,后来想想,如果发生这种情况,已经说明Zookeeper的voter节点超过半数Fault了(不管是消息丢失还是宕机)。这时整个Zookeeper服务只能是不可用了。否则只要过半的voter节点可用,一定会有相应的committedRequest返回。同时这里也保证了写请求按到达顺序生效。

img_6a7906c1a07ce736c0fdb5d416fbd257.png
CommitProcessor


SyncRequestProcessor

    该线程负责将submittedRequest记录到Log。ZooKeeper使用一个简单的内存数据库ZKDatabase来处理日志、session信息和datatree(znode树,类似文件系统结构,用来组织存放实际数据。与文件系统不同的是目录也可以有数据)日志采用1000条批量flush到日志文件,满一定条数起单独线程生成snap文件。记录完日志后直接发送ACK消息给Leader对象—作为一个投票者投出自己的一票。

img_fd4a09cb26299a43798c3c19d2a92c00.png
SyncRequestProcessor


FollowerRequestProcessor

    该线程主要是负责follower接收client连接后的报文处理链条,follower接收到client的报文后提交到queuedRequests队列,由FollowerRequestProcessor进行处理并提交到CommitProcessor进行处理。

img_8dc5852b03d4f85eb45660c5a3749df3.png
FollowerRequestProcessor


quorumPeer线程

    quorumPeer的在zookeeper集群模式下每个节点本身就是一个quorumPeer服务,内部启用线程来处理发生重新选举的场景,也就是说白了就是每个zk节点就是quorumPeer节点。

img_6133267c52b278d02c846c1e011da045.png
QuorumPeer线程用于选举


参考文章

    ZooKeeper 核心模块代码浅析

相关文章:

  • Android 8.0 功能和 API
  • 1000个中国“富一代”今日来杭州,要搞什么大事?
  • Zabbix监控指定端口
  • 网卡绑定技术teaming!
  • Date8
  • Promise初体验
  • PHP 使用GD库生成二维码 实现圆角
  • session一致性架构设计
  • 《shell编程实战》第4章shell变量进阶(上)
  • 批量实现多台服务器之间ssh无密码登录的相互信任关系
  • 与Bob McWhirter的问答:WildFly Swarm更名为Thorntail项目
  • AsyncTask实现原理
  • 最简单的无缝轮播
  • c中perror函数
  • 小身材超能量Oracle新一代数据库机帮助所有规模企业迈向云端
  • docker-consul
  • express.js的介绍及使用
  • HTTP中的ETag在移动客户端的应用
  • JavaScript新鲜事·第5期
  • java小心机(3)| 浅析finalize()
  • opencv python Meanshift 和 Camshift
  • vue-cli3搭建项目
  • webpack4 一点通
  • 产品三维模型在线预览
  • 构造函数(constructor)与原型链(prototype)关系
  • 记一次删除Git记录中的大文件的过程
  • 什么软件可以剪辑音乐?
  • 思维导图—你不知道的JavaScript中卷
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 第二十章:异步和文件I/O.(二十三)
  • 正则表达式-基础知识Review
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • #stm32驱动外设模块总结w5500模块
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (二开)Flink 修改源码拓展 SQL 语法
  • (四) 虚拟摄像头vivi体验
  • (转) Face-Resources
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)Mysql的优化设置
  • ***原理与防范
  • .java 9 找不到符号_java找不到符号
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .Net Core 中间件验签
  • .net core使用ef 6
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET Project Open Day(2011.11.13)
  • .Net Web窗口页属性
  • .project文件
  • /etc/sudoers (root权限管理)
  • [BROADCASTING]tensor的扩散机制
  • [BZOJ 4129]Haruna’s Breakfast(树上带修改莫队)