follower 节点在 zookeeper proposal 请求阶段是否刷新请求到磁盘?

Was follower node flush request to disk when in zookeeper proposal request stage?

看过zookeeper的源码,在集群上有很奇怪的操作。 众所周知,写入zookeeper集群节点时,流程步骤为:

  1. Leader 向所有 Follower 和自己发送提议请求
  2. 当follower收到proposal request,然后ack
  3. 当leader收到最多的ack response,然后发送commit requst
  4. follower和leader共同提交

问题出在第2步,当follower收到proposal request时,requst同步到zk tx log(见列表代码),commit request只写入内存。但是在ack之前和同步到磁盘时间之后,重启所有节点,未提交的请求是最新的请求吗?

 //  the follower receive the proposal request method , forword to syncProcessor
 public void FollowerZooKeeperServer#logRequest(TxnHeader hdr, Record txn) {
            Request request = new Request(null, hdr.getClientId(), hdr.getCxid(),
                    hdr.getType(), null, null);
            request.hdr = hdr;
            request.txn = txn;
            request.zxid = hdr.getZxid();
            if ((request.zxid & 0xffffffffL) != 0) {
                pendingTxns.add(request);
            }
            syncProcessor.processRequest(request);
        }



 // the SyncRequestProcessor operation , after tx log commit to disk , it response the ack request. Was it ok ?
private void flush(LinkedList<Request> toFlush)
        throws IOException, RequestProcessorException
    {
        if (toFlush.isEmpty())
            return;

        zks.getZKDatabase().commit();
        while (!toFlush.isEmpty()) {
            Request i = toFlush.remove();
            if (nextProcessor != null) {
                nextProcessor.processRequest(i);
            }
        }
        if (nextProcessor != null && nextProcessor instanceof Flushable) {
            ((Flushable)nextProcessor).flush();
        }
    }

答案是肯定的。

tx日志commit到磁盘后,假设txid为N,则写入被接受。如果重启所有节点,则txid个节点使用的将是N个。选举成功后,N个将被视为committed。

我觉得困扰你的是,客户端实际上没有收到写的响应,但是写被提交了。这是可以接受的,因为 zookeeper 集群的状态保持一致,只是客户端遇到了超时,超时意味着请求是否已提交是未知的。