zookeeper_节点数据版本号问题
转自:Simba_cheng
更新节点数据的方法:
- 同步方法:Stat setData(final String path, byte data[], int version)
- 异步方法:void setData(final String path, byte data[], int version, StatCallback cb, Object ctx)
参数说明:
- path:指定数据节点路径
- data[]:一个字节数组,即需要使用该数据来覆盖节点现在的数据内容
- version:指定节点的数据版本
- cb:注册一个异步回调函数
- ctx:用于传递上下文信息的对象
其中:
version参数用于指定节点的数据版本,表名本次更新操作是针对指定的数据版本进行的。
指定数据版本更新的意义何在呢?
通俗的讲"CAS":对于值V,每次更新前都会比对其值是否是预期值A,只有符合预期,才会将V原子化的更新到新值B
CAS具体解释
zookeeper的setData接口中的version参数是CAS衍化来的
zookeeper每个节点都有数据版本的概念,在调用更新操作的时候,就可以添加version这个参数,该参数可以对应于CAS
原理中对的"预期值",表明是针对该数据版本进行更新。
形象一些说:
假如有一个客户端试图进行更新操作,它会携带上次获取到的version值进行更新。
而如果在这段时间内,ZooKeeper服务器上该节点的数值恰好已经被其他客户端更新了,那么其数据版本一定也会发生变化,
因此肯定与客户端携带对的version无法匹配,于是便无法成功更新 -- 因此可以有效地避免一些分布式更新的并发问题。
Demo代码:
public class TestSetData implements Watcher {
// 屏障,计数器
private static CountDownLatch downLatch = new CountDownLatch(1);
private static ZooKeeper zookeeper = null;
public static void main(String[] args) throws Exception {
zookeeper = new ZooKeeper("10.0.227.66:2181", 5000, new TestSetData());
System.out.println("zookeeper.getState()1 : " + zookeeper.getState());
try {
downLatch.await();// 在计数器未归零之前,所有线程等待
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("zookeeper.getState()2 : " + zookeeper.getState());
zookeeper.create("/cyx", "ccc".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
zookeeper.getData("/cyx", true, null);
// 第一次设置
Stat stat = zookeeper.setData("/cyx", "456".getBytes(), -1);
System.out.println(stat.getCzxid() + " , " + stat.getMzxid() + " , " + stat.getVersion());
// 第二次设置
Stat stat2 = zookeeper.setData("/cyx", "789".getBytes(), -1);
System.out.println(stat2.getCzxid() + " , " + stat2.getMzxid() + " , " + stat2.getVersion());
// 获取第一次设置得到version,进行更新
try {
zookeeper.setData("/cyx", "123".getBytes(), stat.getVersion());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void process(WatchedEvent event) {
System.out.println("receive watched event : " + event);
if (KeeperState.SyncConnected == event.getState()) {
if (EventType.None == event.getType() && null == event.getPath()) {
downLatch.countDown();// 计数器-1
}
}
}
}
输出结果:
zookeeper.getState()1 : CONNECTING
receive watched event : WatchedEvent state:SyncConnected type:None path:null
zookeeper.getState()2 : CONNECTED
receive watched event : WatchedEvent state:SyncConnected type:NodeDataChanged path:/cyx
197568501464 , 197568501465 , 1
197568501464 , 197568501466 , 2
org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for /cyx
代码编写思路:
- 首先创建节点"/cyx"节点,设置节点参数"ccc"
- 接着我们第一次setData,更新节点参数为"456",同时获取stat,此时version已经改变
- 然后我们再次setData,更新节点参数为"789",同时获取stat,version也改变了
- 接着我们使用第一次获取的version版本号,去setData。
- 然后就抛异常,因为第二次setData的时候,版本号已经更新,这时候,我们拿第一次的更新的版本号去更新,是没法成功的。
解释下setData时的"-1":
在ZooKeeper中,数据版本都是从0开始计数额,所以严格的讲,"-1"不是一个合法得到数据版本,它仅仅是一个标示符。
如果客户端传入的版本参数是"-1",就是告诉zookeeper服务器,客户端需要基于数据的最新版本进行更新操作。
zookeeper_节点数据版本号问题的更多相关文章
- .Net客户端监听ZooKeeper节点数据变化
一个很简单的例子,用途是监听zookeeper中某个节点数据的变化,具体请参见代码中的注释 using System; using System.Collections.Generic; using ...
- C# 对 App.config的appSettings节点数据进行加密
.NET平台下的Winform和Asp.net的配置文件默认都是明文保存的,本文使用的是.Net自身如何加密配置文件,不包含自定义的加密规则 但.Net是提供了直接对配置文件加密的功能的,使用.Net ...
- zTree实现获取一级节点数据
zTree实现获取一级节点数据 1.实现源码 <!DOCTYPE html> <html> <head> <title>zTree实现基本树</t ...
- openLDAP安装时无法操作根节点数据,提示的是This base cannot be created with PLA.
1.无法操作根节点数据,提示的是This base cannot be created with PLA. 解决办法 1)添加一个base.ldif文件,里面的dc和配置文件里的保持一致即可 dn: ...
- javascript读取xml文件读取节点数据的例子
分享下用javascript读取xml文件读取节点数据方法. 读取的节点数据,还有一种情况是读取节点属性数据. <head> <title></title> < ...
- ztree插件的使用及列表项拖拽的实现(jQuery)+异步加载节点数据
为了实现如图所示的树状结构图,并使列表项可拖动到盒子里,研究了ztree这个插件的使用,并仔细研究了列表项的拖动事件.完成了预期需求,对jQuery的运用得到了提高.这个插件的功能非常强大,除了基本的 ...
- C#XML格式字符串取节点数据
XML格式的字符串: <xml><return_code><![CDATA[{0}]]></return_code><return_msg> ...
- 用LINQ获取XML节点数据
Insus.NET想对<从字符串中获取XML节点数据> http://www.cnblogs.com/insus/p/3299052.html 这篇改写为使用LINQ的方法实现.LINQ中 ...
- 从字符串中获取XML节点数据
从字符串中获取XML节点数据,前一篇<字符串创建XML文档> http://www.cnblogs.com/insus/p/3298579.html 是储存为一个XML文档.现在,Insu ...
随机推荐
- linq to sql 中增删改查
首先我先说一下,如果真的要用linq做项目的话,也会是比较方便的.已经尝试了在三层架构中应用linq to sql 比较方便. //有三个不同的数据库表,所以写法不一样 public class Li ...
- ajax和原生ajax、文件的上传
ajax理解: ajax发送的请求是异步处理的.也就是说如下形式: function f1(){ $.ajax( { ....... success:function(){ a= return a } ...
- vue2 broadcast和dispatch的理解
/* broadcast 事件广播 @param {componentName} 组件名称 @param {eventName} 事件名 @param {params} 参数 遍历寻找所有子孙组件,假 ...
- 【Linux】LVM逻辑卷管理和RAID
LVM概述: 是对磁盘分区进行管理的一种机制 是一种将一个或多个硬盘的分区在逻辑上集合,相当于一个大硬盘来使用,当硬盘的空间不 够使用的时候,可以继续将其它的硬盘的分区加入其中,这样可以实现一种磁盘空 ...
- 使用promis串行化异步操作
该代码可在chrome下运行,对于低版本浏览器可以引入Q库 function async1() { var defer = Promise.defer() setTimeout(function(){ ...
- 2015306 白皎 《网络攻防》Exp5 MSF基础应用
2015306 白皎 <网络攻防>Exp5 MSF基础应用 一.基础问题 用自己的话解释什么是exploit,payload,encode. exploit指由攻击者或渗透测试者利用一个系 ...
- 20155308 加分题-mybash的实现(第五周)
20155308 加分题-mybash的实现(第五周) 实验要求 使用fork,exec,wait实现mybash 写出伪代码,产品代码和测试代码 发表知识理解,实现过程和问题解决的博客(包含代码托管 ...
- python基础学习1-面向对象
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo:#定义类 def mail(self,email,message):#定义类的方法 pri ...
- K近邻算法小结
什么是K近邻? K近邻一种非参数学习的算法,可以用在分类问题上,也可以用在回归问题上. 什么是非参数学习? 一般而言,机器学习算法都有相应的参数要学习,比如线性回归模型中的权重参数和偏置参数,SVM的 ...
- 【转载】COM 组件设计与应用(六)——用 ATL 写第一个组件
原文:http://vckbase.com/index.php/wv/1216.html 一.前言 1.与 <COM 组件设计与应用(五)>的内容基本一致.但本回讲解的是在 vc.net ...