follower 节点在 zookeeper proposal 请求阶段是否刷新请求到磁盘?
Was follower node flush request to disk when in zookeeper proposal request stage?
看过zookeeper的源码,在集群上有很奇怪的操作。
众所周知,写入zookeeper集群节点时,流程步骤为:
- Leader 向所有 Follower 和自己发送提议请求
- 当follower收到proposal request,然后ack
- 当leader收到最多的ack response,然后发送commit requst
- 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 集群的状态保持一致,只是客户端遇到了超时,超时意味着请求是否已提交是未知的。
看过zookeeper的源码,在集群上有很奇怪的操作。 众所周知,写入zookeeper集群节点时,流程步骤为:
- Leader 向所有 Follower 和自己发送提议请求
- 当follower收到proposal request,然后ack
- 当leader收到最多的ack response,然后发送commit requst
- 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 集群的状态保持一致,只是客户端遇到了超时,超时意味着请求是否已提交是未知的。