sequence自增原理是什么?
為什么get命令看到的cversion和實(shí)際存儲(chǔ)的cversion不一樣?
sequence自增怎么保證無(wú)并發(fā)問(wèn)題?單節(jié)點(diǎn)和多節(jié)點(diǎn)?
-
sequence自增原理是什么?
// 代碼取自(服務(wù)端代碼)org.apache.zookeeper.server.PrepRequestProcessor#pRequest2TxnCreate ChangeRecord parentRecord = getRecordForPath(parentPath); checkACL(zks, parentRecord.acl, ZooDefs.Perms.CREATE, request.authInfo); int parentCVersion = parentRecord.stat.getCversion(); if (createMode.isSequential()) { // 如果是順序節(jié)點(diǎn)的話,從父節(jié)點(diǎn)中取出cversion的值作為sequence. path = path + String.format(Locale.ENGLISH, "%010d", parentCVersion); } -
為什么get命令看到的cversion和實(shí)際存儲(chǔ)的cversion不一樣?
知道了sequence取值邏輯后,用get命令查看父節(jié)點(diǎn)的cversion字段,卻發(fā)現(xiàn)總是和新生成節(jié)點(diǎn)的sequence不一致?最后定位到get命令的代碼.
// 代碼取自(服務(wù)端代碼)org.apache.zookeeper.server.DataNode#copyStat synchronized public void copyStat(Stat to) { to.setAversion(stat.getAversion()); to.setCtime(stat.getCtime()); to.setCzxid(stat.getCzxid()); to.setMtime(stat.getMtime()); to.setMzxid(stat.getMzxid()); to.setPzxid(stat.getPzxid()); to.setVersion(stat.getVersion()); to.setEphemeralOwner(getClientEphemeralOwner(stat)); to.setDataLength(data == null ? 0 : data.length); int numChildren = 0; if (this.children != null) { numChildren = children.size(); } // 重點(diǎn)! // when we do the Cversion we need to translate from the count of the creates // to the count of the changes (v3 semantics) // for every create there is a delete except for the children still present // 當(dāng)我們進(jìn)行Cversion時(shí),我們需要從create的數(shù)量中進(jìn)行翻譯更改計(jì)數(shù)(v3語(yǔ)義)對(duì)于每個(gè)創(chuàng)建都有一個(gè)刪除,除了仍然存在的孩子(Google 翻譯) to.setCversion(stat.getCversion()*2 - numChildren); to.setNumChildren(numChildren); } -
sequence自增怎么保證無(wú)并發(fā)問(wèn)題?單節(jié)點(diǎn)和多節(jié)點(diǎn)?
先來(lái)說(shuō)多節(jié)點(diǎn)吧,(參考網(wǎng)上通常的說(shuō)法)當(dāng)一個(gè)客戶端進(jìn)行寫(xiě)數(shù)據(jù)請(qǐng)求時(shí),會(huì)指定ZooKeeper集群中的一個(gè)Server節(jié)點(diǎn),如果該節(jié)點(diǎn)為Follower,則該節(jié)點(diǎn)會(huì)把寫(xiě)請(qǐng)求轉(zhuǎn)發(fā)給Leader,Leader通過(guò)內(nèi)部的協(xié)議進(jìn)行原子廣播,直到一半以上的server節(jié)點(diǎn)都成功寫(xiě)入數(shù)據(jù),這次寫(xiě)請(qǐng)求便算是成功,然后Leader便會(huì)通過(guò)通知相應(yīng)的Follower節(jié)點(diǎn)寫(xiě)請(qǐng)求成功,該節(jié)點(diǎn)向client返回寫(xiě)入成功.
本質(zhì)上說(shuō)還是把多節(jié)點(diǎn)寫(xiě)操作轉(zhuǎn)換成了單節(jié)點(diǎn)的寫(xiě)操作,這樣就可以在單節(jié)點(diǎn)進(jìn)行并發(fā)控制了,效率更高.而在單節(jié)點(diǎn)做并發(fā)控制的話就方便的多了,通過(guò)PrepRequestProcessor->SyncRequestProcessor->FinalRequestProcessor->ZooKeeperServer->ZKDatabase->DataTree鏈路處理.有興趣可以自己翻翻代碼哦.