ZooKeeper如何保证事务原子性?

50592681f51342fb330208eeac2093bf.png

先解答疑惑,题主对ZAB理解是正确的。为了便于描述,本文将事务理解为具有ACID的一组操作,一个ZooKeeper请求(例如:create)称之为提案。

ZAB协议是共识算法的一种,共识算法仅能保证单个提案在集群中达成共识,如果是多个提案要保证事务的话,需要在上层再做一次封装。ZAB被称为原子广播协议,也是做了这一层封装,即:multi命令。

multi命令让多个提案,要么同时成功,要么同时失败,所以要知道ZooKeeper怎么处理事务的,只需要关注multi命令的实现即可。

ZooKeeper对提案的协商,是以责任链的形式处理,下图是协商提案的责任链路,大家可以参考。

43efd33c68ba721e8216f8d867c5033d.png

不难发现,客户端的请求,先到达PrepRequestProcessor,那么在PrepRequestProcessor一定可以找到对multi命令的特殊操作。

以下代码为PrepRequestProcessor#pRequestHelper,我省略掉了try-catch和其他无关代码,在处理multi请求时,ZooKeeper会先遍历multiRequest,把每个元素当做一个单独的提案调用pRequest2Txn()方法来协商,当某个提案协商发生异常时,ZooKeeper会调用rollbackPendingChanges()回滚正在执行中的提案。

// PrepRequestProcessor
private void pRequestHelper(Request request) throws RequestProcessorException {
	switch (request.type) {
	case OpCode.multi:
		MultiOperationRecord multiRequest = new MultiOperationRecord();
		try {
			ByteBufferInputStream.byteBuffer2Record(request.request, multiRequest);
		} catch (IOException e) {
			request.setHdr(new TxnHeader(request.sessionId, request.cxid, zks.getNextZxid(), Time.currentWallTime(), OpCode.multi));
			throw e;
		}
		List<Txn> txns = new ArrayList<Txn>();
		long zxid = zks.getNextZxid();
		KeeperException ke = null;

		Map<String, ChangeRecord> pendingChanges = getPendingChanges(multiRequest);
		request.setHdr(new TxnHeader(request.sessionId, request.cxid, zxid,
				Time.currentWallTime(), request.type));

		for (Op op : multiRequest) {
			Record subrequest = op.toRequestRecord();
			int type;
			Record txn;
			if (ke != null) {
				type = OpCode.error;
				txn = new ErrorTxn(Code.RUNTIMEINCONSISTENCY.intValue());
			} else {
				try {
					pRequest2Txn(op.getType(), zxid, request, subrequest, false);
					type = op.getType();
					txn = request.getTxn();
				} catch (KeeperException e) {
					ke = e;
					type = OpCode.error;
					txn = new ErrorTxn(e.code().intValue());

					if (e.code().intValue() > Code.APIERROR.intValue()) {
						LOG.info("Got user-level KeeperException when processing {} aborting"
								 + " remaining multi ops. Error Path:{} Error:{}",
								 request.toString(),
								 e.getPath(),
								 e.getMessage());
					}

					request.setException(e);

					/* Rollback change records from failed multi-op */
					rollbackPendingChanges(zxid, pendingChanges);
				}
			}

			try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
				BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
				txn.serialize(boa, "request");
				ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
				txns.add(new Txn(type, bb.array()));
			}
		}
		request.setTxn(new MultiTxn(txns));
		if (digestEnabled) {
			setTxnDigest(request);
		}
		break;
}


回到问题本身,使用multi命令,创建一个节点和删除一个节点时,当创建节点成功了,但是删除节点失败了,那么ZooKeeper会回滚创建操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值