zoukankan      html  css  js  c++  java
  • Zookeeper单机模式下RequestProcessor流程与源码理解

    多个NIOServerCnxn公用同一个zkServer对象

    处理CRUD请求逻辑:


    largeRequestThreadshold (请求大小阈值,默认为-1)
    zk处理请求时,并不是并行处理。requestThrottler会将请求放到队列submittedRequests(LinkedBlockingQueue)中
    requestThrottler为请求限流器,其实也是一个线程
    ZK中如何优雅的停止?
    请求限流器这类的线程,如果要停止,其实就是使run方法跑完。因为run方法中有while循环逻辑,所以只要使while循环停止,就可以优雅的停止线程。

    ZK限流的逻辑:
    if (maxRequests > 0) {
    while (!killed) {
    if (dropStaleRequests && request.isStale()) {
    // Note: this will close the connection
    // closeSession
    dropRequest(request);
    ServerMetrics.getMetrics().STALE_REQUESTS_DROPPED.add(1);
    request = null;
    break;
    }
    // 真正被处理的请求
    if (zks.getInProcess() < maxRequests) {
    break;
    }
    // 超过了则睡眠一会
    throttleSleep(stallTime);
    }
    }
    请求处理器链:
    PrepRequestsProcessor
    SyncRequestProcessor
    FinalRequestsProcessor

    当两个create请求被处理时,如何既要保证安全性,又要保证一定的高效能性?(安全:加锁,取ChangeRecord容器的节点信息;高效:执行请求操作是异步的,避免同步串行阻塞)
    不安全主要有:顺序节点需要序号递增,要考虑线程安全
    在前一个create请求进行创建之前,会记录一条ChangeRecord记录,这里记录的是最新的父节点的信息(比如cVersion属性),下一个请求进来时,会直接从ChangeRecord中去取父节点的最新信息。
    此时因为上一个请求可能还没来得及修改DataTree,当然也可能没来得及做持久化操作。所以下一个请求只能从ChangeRecord中去取。
    当然,在对ChangeRecord进行操作时,要对操作加上同步锁,避免不安全(因为线程执行都是异步的)。

    ZK是否绝对可靠?
    理论上来说,是可以做到的。因为ZK是采用日志加快照的方式备份数据到磁盘中。恢复的时候会根据最近一次快照加日志文件去恢复原始Datatree。
    但是在写日志文件时,因为采用了多次缓存到缓存流,然后一次性写入日志文件。如果在一组日志还未持久化,ZK集群挂了。此时这些还未持久化的日志就无法存盘。导致这部分日志丢失。

    ZK中几个RequestProcessor作用解析:
    PrepRequestProcessor
    1、以线程加队列的方式来处理Request,保证了顺序执行
    2、设置了Request的Hdx和Txn
    3、根据不同的命令操作类型生成ChangeRecord表示对某一个节点的一次修改。需要注意的是,一个操作可能对应不止一条的ChangeRecord,比如一个create请求就包括了创建当前节点,以及修改父节点的属性。
    把ChangeRecord放到OutstandingChanges队列中,OutstandingChanges意思是排队的修改记录。当我们需要create一个节点时,我们需要获取父节点的信息。如果OutstandingChanges中没有父节点信息,则要通过DataBase中拿,影响效率。
    4、验证ACL
    5、把Request交给nextProcessor处理
    SyncRequestProcessor
    1、以线程加队列的方式来处理Request,保证了顺序执行
    2、把Request中的Hdx和Txn进行持久化【请求持久化:日志:DataTree持久化:快照】
    3、单独创建一个线程打快照
    4、把Request交给nextProcessor处理
    FinalRequestsProcessor
    1、根据Request更新ZKDatabase
    2、触发Watch
    3、发送Response给客户端


    else if (toFlush.isEmpty()) {
    // toFlush是一个队列,表示需要进行持久化的Request,当Request被持久化了之后,就会把Request从toFlush中移除,直接调用nextProcessor
    // 所以如果一个Request的hdr为null,表示不用进行持久化,
    // 并且当toFlush队列中有值时不能先执行这个Request请求,得等toFlush中请求都执行完了之后才能执行

    // optimization for read heavy workloads
    // iff this is a read, and there are no pending
    // flushes (writes), then just pass this to the next
    // processor
    if (nextProcessor != null) {
    nextProcessor.processRequest(si);
    if (nextProcessor instanceof Flushable) {
    ((Flushable) nextProcessor).flush();
    }
    }
    continue;
    }

    // 把当前请求添加到待flush队列中
    toFlush.add(si); // 写 读

    解释:如果队列中还有写请求,则继续讲请求add到队列中待处理。

  • 相关阅读:
    javaEE企业级基础介绍(一)
    SQL学习笔记系列(十)窗口函数
    SQL学习笔记系列(九)索引优化分析
    Tableau教程笔记
    淘宝用户行为分析--基于MySQL、Tableau
    Stop thinking,start living--《心灵奇旅》观后感
    SQL刷题
    SQL学习笔记系列(八)流程控制结构
    SQL学习笔记系列(七)存储过程和函数
    在超算系统上使用sbatch提交MXNet分布式训练任务
  • 原文地址:https://www.cnblogs.com/yibao/p/14058837.html
Copyright © 2011-2022 走看看