深入浅出Zookeeper(五):BadVersionExceptionはいったいどういうことなのか
本文は
ポタリポタリ本 :
https://www.jianshu.com/u/204...
バージョン#バージョン#
日付
コメント
1.0
2020.4.19
文章の先発
前言
最近では開発時にたまにzkが
ノードのプロパティ
ソースコードを分析する前に、zkノードの3つのバージョンのプロパティを理解する必要があります. version:現在のデータノードデータコンテンツのバージョン番号 cversion:現在のデータサブノードのバージョン番号 aversion:現在のデータノードACL変更バージョン番号 これらのプロパティは
関連する属性が変更されると、バージョン番号は+1になります.作成したばかりのノードで、バージョン番号は0で、このノードが0回更新されたことを示します.
ソース分析
一般的に
zookeeperのclientコードは非常に簡単です.
その後versionという属性はリクエストにシーケンス化され、サービス側に送信されます.
サービス側のコードを見てください.異常な名前から、コード
コードの分かりやすさ:zkからノードのバージョンを取り出し、比較(クライアントによって-1に設定されていない)が必要な場合は、ノードの現在のバージョンと比較します.
例外が投げ出されていない場合、このバージョン番号は+1され、更新はキューにコミットされ、最後にzkのメモリデータベースに更新されます.
明らかに、これはCAS技術の実現である.では、なぜCASに基づいてロックを実現するのでしょうか.その前に、楽観的なロックと悲観的なロックの適用シーンを振り返る必要があります.悲観ロック:データ更新の競争が激しいシーンに適しています.独占性と排他性が強いからだ. 楽観ロック:データの同時競合が少なく、トランザクションの競合が少ないシーンに適用されます.排他的にロックを実現するのではなく、一般的な実装は私たちが言及したCASです.
zkは一般的に
小結
本論文では,zkのデータ排他的機構の実現が楽観的ロックであることを知った.このように設計された理由は、zkが通常、シーンデータを使用して競合する場合が少なく(もちろん、競合を激しくすることができますが、全体的にプロセスを見ると時間がかかります)、トランザクション操作はシリアルで実行されます.
ポタリポタリ本 :
https://www.jianshu.com/u/204...
バージョン#バージョン#
日付
コメント
1.0
2020.4.19
文章の先発
前言
最近では開発時にたまにzkが
BadVersionException
と報告されているのが観測され,検索による楽観的ロックに関する問題であることがわかり,すぐに問題が解決した.しかし、単体アプリケーションでも分散システムでも、実行中にデータの排他性を保証するメカニズムが必要です.次にzkがこのメカニズムをどのように実現したかを見てみましょう.ノードのプロパティ
ソースコードを分析する前に、zkノードの3つのバージョンのプロパティを理解する必要があります.
StatPersisted
というクラスで見つけました.関連する属性が変更されると、バージョン番号は+1になります.作成したばかりのノードで、バージョン番号は0で、このノードが0回更新されたことを示します.
ソース分析
一般的に
setData
を呼び出すと、コードはこう書きます.//Curator
// 。 , -1
client.setData().withVersion(version).forPath(path, payload);
//
client.setData().forPath(path, payload);
zookeeperのclientコードは非常に簡単です.
/**
* The asynchronous version of setData.
*
* @see #setData(String, byte[], int)
*/
public void setData(final String path, byte data[], int version,
StatCallback cb, Object ctx)
{
final String clientPath = path;
PathUtils.validatePath(clientPath);
final String serverPath = prependChroot(clientPath);
RequestHeader h = new RequestHeader();
h.setType(ZooDefs.OpCode.setData);
SetDataRequest request = new SetDataRequest();
request.setPath(serverPath);
request.setData(data);
request.setVersion(version);
SetDataResponse response = new SetDataResponse();
cnxn.queuePacket(h, new ReplyHeader(), request, response, cb,
clientPath, serverPath, ctx, null);
}
その後versionという属性はリクエストにシーケンス化され、サービス側に送信されます.
サービス側のコードを見てください.異常な名前から、コード
PrepRequestProcessor.pRequest2Txn
のコードを簡単に見つけることができます. case OpCode.setData:
zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
SetDataRequest setDataRequest = (SetDataRequest)record;
if(deserialize)
ByteBufferInputStream.byteBuffer2Record(request.request, setDataRequest);
path = setDataRequest.getPath();
validatePath(path, request.sessionId);
nodeRecord = getRecordForPath(path);
checkACL(zks, nodeRecord.acl, ZooDefs.Perms.WRITE, request.authInfo);
int newVersion = checkAndIncVersion(nodeRecord.stat.getVersion(), setDataRequest.getVersion(), path);
request.setTxn(new SetDataTxn(path, setDataRequest.getData(), newVersion));
nodeRecord = nodeRecord.duplicate(request.getHdr().getZxid());
nodeRecord.stat.setVersion(newVersion);
addChangeRecord(nodeRecord);
break;
checkAndIncVersion
の論理を見てみましょう. private static int checkAndIncVersion(int currentVersion, int expectedVersion, String path)
throws KeeperException.BadVersionException {
if (expectedVersion != -1 && expectedVersion != currentVersion) {
throw new KeeperException.BadVersionException(path);
}
return currentVersion + 1;
}
コードの分かりやすさ:zkからノードのバージョンを取り出し、比較(クライアントによって-1に設定されていない)が必要な場合は、ノードの現在のバージョンと比較します.
例外が投げ出されていない場合、このバージョン番号は+1され、更新はキューにコミットされ、最後にzkのメモリデータベースに更新されます.
明らかに、これはCAS技術の実現である.では、なぜCASに基づいてロックを実現するのでしょうか.その前に、楽観的なロックと悲観的なロックの適用シーンを振り返る必要があります.
zkは一般的に
、DNS 、
に使用され、これはデータの同時競合が少ないことを意味し、トランザクションも実際にはleaderサーバによってシリアル処理されることを知っています.明らかに、これは楽観的なロックの使用シーンに合致するため、zkは「重い」悲観的なロックを採用して分布データの原子的な操作を実現していない.小結
本論文では,zkのデータ排他的機構の実現が楽観的ロックであることを知った.このように設計された理由は、zkが通常、シーンデータを使用して競合する場合が少なく(もちろん、競合を激しくすることができますが、全体的にプロセスを見ると時間がかかります)、トランザクション操作はシリアルで実行されます.