zoukankan      html  css  js  c++  java
  • Zookeeper学习笔记(中)

    Zookeeper学习笔记(中)

    Zookeeper的基本原理和基本实现

    深入了解ZK的基本原理

    ZK的一致性:

    • ZAB 协议: Zookeeper 原子消息广播协议

        ZK通过选举保证 leader 的高可用, 
      
        三个阶段:
        	* 发现:选举 leader
        	* 同步:Follower 或者 Observer 从 leader 中同步最新数据
        	* 广播:
      
        服务器角色:
        	* Leader:领导者, 所有更新操作通过 leader 进行
        	* Follower:跟随者, 有投票权, leader挂了之后有权作为竞选者 
        	* Observer:只能读取数据, 没有投票权, 不能参与竞选 leader
      
        服务器状态:
        	* LOOKING
        	* FOLLOWING
        	* OBSERVING
        	* LEADING
      
        集群通讯: id大的向小的发起连接
      
    • Leader的选举

        选举算法:
        	通过FastLeaderElection, tcp协议
        	触发时机:
        		1) 集群启动
        		2) Leader宕机
        	成为leader的因素 : zxid 和 myid
      
        	思考: 有3个全新节点组成一个集群,依次启动1,2,3, 哪个节点会成为 leader ?
      
        选举过程:
        	1) 每个节点状态为 LOOKING
        	2) 每一个server发出一个投自己的投票(myid+zxid)
        	3) 处理投票:将收到投票和自己投票相比(比较zxid,比较myid),有些节点修改投票,再次发送
        		比较zxid的意义:过半数即认为OK, 只要半数中的机器有一个在新的选举中, 即它会成为新leader将数据同步给其他人
        	4) 统计投票, 确定
        	5) 修改服务器状态
      
    • 各个节点数据的同步:

        leader选举之后, leader同其他节点进行同步,同步完成, leader才真正变为leader
        leader同超过一半follower同步结束才OK
        follower选举完成后尝试连接leader,带上自己最大的 zxid, 来确定数据同步的过程
      
        * 同步算法(DIFF):
      
        	适用于 follower 的最大事务id, 在 min , max 之间
        	1. 发送同步请求
        	2. 发送同步数据
        	3. 一旦过半follower完成同步,leader发送信号结束同步流程,即可以对外服务
      
      
        * 同步算法(TUNC):
      
        	适用于 leader 宕机, 恢复后作为 follower 加入, 其上有已经 proposal 的新事务, 其id > max
        	宕机之后如果 TRUNC 之后, 新集群已经有数据修改, 则需要通过 DIFF 将新修改发送给加入节点
        	简单说明步骤:
        		1) 新节点加入后收到 trunc 命令, 将只存在于新节点上的数据回滚
        		2) 确定是否新leader有新的提交,如有进行DIFF, 完成整个过程
        
        * 同步算法(SNAP):全量
        	适合宕机多时后恢复, 其id < min , 集群的事务日志文件已经有更新多个了
      
        
        * 获取同步后的数据	
      
        	读取前条用  sync 方法进行数据同步, 确保数据为最新
      
    • 以下为我在思考ZK选举原理过程中产生的一些问题, 有些还未完全获取到正确答案, 暂时提供出来供大家一起讨论

        1. zxid在一个主周期中是否肯定一致连续?
                是
        2. 无 leader 的状态时, 是否可以接受消息更新? 只有leader选举完毕才能再继续对外服务(读写)?
                无 leader 状态不可接受, 需要等待到 leader 选举完毕
        3. 如果某zxid被废弃后, 客户端如何得知? 此种情况不会让客户端得知消息已接收确认的消息 ? 
                客户端只有在消息被commit之后才会收到更新成功的确认
        4. 只经过proposal, 没有commit的数据不会返回给客户端?(前leader宕机,可能有些自己写入提交,但是别的节点还未获取的数据)这些数据会被认为是客户端正常提交的数据?
        5. 投票中每个节点都发给其他节点? 投票何时结束? 何时出发统计投票?
        6. 同步: observer 需要如何同步? 
        7. 同步是否有可能失败,导致重新选举 leader?
                有可能
        8. 个别follower无法连接leader导致无法完成同步, 重新回到选举状态, 之后如何? 会真正再次进行选举?
                会再次选举
        9. 最大,最小事务id:需要理解存储机制, min 不在快照文件中的最小id, max :事务日志中的最大id, 只要在事务日志中,即都是已经在集群中commit(个别节点上没有)
        10. 修改的proposal 是发给所有节点? 为何 diff 同步还得再发一份 ?
      

    ZK的具体实现

    1. 客户端连接:

       多个地址会随机排序,从前往后继续
       查看类 : org.apache.zookeeper.client.StaticHostProvider
      
    2. 会话:

       客户端和服务端的一个连接是TCP连接
      
       会话实现类 : SessionImpl
       	Ticktime : 会话下次超时时间
      
       会话状态:
       	CONNECTING
       	CONNECTED
       	RECONNECTING
       	RECONNECTED
       	CLOSED
      
       会话的维护
       	* 服务器通过 SessionTracker 维护会话
       	* 会话检查和清理都在 Leader 节点处理
       	* 通过三个维度管理会话:
       		sessionId , session
       		失效时间, sessionSet
       		sessionId, 失效时间
      
       分桶策略: 用于会话失效检查和清除
       	分桶策略的说明:根据失效时间划分不同的session
       	把时间按照标准时间单位进行分割
       	某会话由于操作(心跳也是一个操作)导致超时时间变化, 从一个桶移到下一个桶
       	sessionTracker 中一个线程, 某次检查分桶中还有会话, 则说明超时
      
       会话清理的步骤
       	1. 状态设为 CLOSED
       	2. 所有节点发送会话关闭
       	3. 删除临时节点
       	4. 会话列表中移出
       	5. 网络断开
      
       会话重连
       	CONNECTION_LOSS
       	SESSION_EXPIRED
       	SESSION_MOVE
      
       待解决:
       	清除之后, 还是否可以通过设置 sessionId , 连接上一个session ? 连接时设置 sessionId 如何使用 ?
      
    3. 数据和存储:

       基本结构:
       	ZKDatabase
       		存储管理所有会话, datatree 的存储和事务日志
       		定期向磁盘写入快照数据
       		节点启动恢复内存数据
      
       	DataTree
       		维护数据/目录/权限
       		数据的领域模型
      
       	DataNode
       		树形中每个节点,包括父节点,子节点,节点数据
       
       事务日志:
       	日志文件:
       		datalog 或者配置的目录
       		vsersion-2 代表日志格式的版本号
       		大小64MB
       		文件名为后缀16进制格式,其中包含了本日志文件第一个 zxid
      
       	日志格式:
       		日志文件可以通过工具解析出: LogFormatter
       		日志格式内容解析:
       			各类会话,事件和内容都存储
      
       	日志写入:
       		通过 FileTxnLog 实现日志写入, 使用 append 方式
       		写入过程:
       			1. 确定事务日志文件,确定是否需要扩容(新增文件会用0填满64MB)
       			2. 事务序列化
       			3. 生成checknum
       			4. 写入文件流
       			5. fsync, 写入磁盘
      
      
       数据快照:
       	ZK中某个时刻的完整数据,和事务日志是不同的文件
       	文件后缀为快照中所包含的最新的zxid
       	通过SnapshotFormatter可以查看内容
      
       	快照流程:
       		1. 确定是否需要快照: 默认 snapCount 100000, 算法避免集群节点同时进行快照
       		2. 切换事务日志文件
       		3. 创建快照异步线程
       		4. 生成快照数据文件
       		5. 数据刷入快照文件
       
       事务日志和数据快照的联系和异同:
       	快照存储:
       		当时内存中的数据模型
       		一旦快照存储之后,会新开事务日志文件
      
       	事务日志:
       		所有 commit 提交的数据都会记录在事务日志中
       		事务日志文件
      
       	恢复使用:
       		取最新的快照文件, 恢复到内存数据结构中
       		最新的事务日志中有些数据未反应在快照中, 需要根据事务日志中的记录, 也恢复到数据结构中
  • 相关阅读:
    MySQL练习题
    MySql基础操作
    解决使用IDEA启动Tomcat成功但localhost:8080无法访问的问题
    1417. 重新格式化字符串--来源:力扣(LeetCode)
    字符消除
    Comsol中Absolute Pressure的解释
    气体流量与质量流率换算
    FileZilla MLSD错误:连接超时、读取目录列表失败
    Avalon总线的地址对齐与NIOS编程
    同步复位和异步复位--好文章就是要记录下来
  • 原文地址:https://www.cnblogs.com/ownraul/p/5605223.html
Copyright © 2011-2022 走看看