ZooKeeper之Java客户端API使用—更新数据。

        客户端可以通过ZooKeeper的API来更新一个节点的数据内容,有如下两个接口:

  • Stat setData(final String path, byte data[], int version)
  • void setData(final String path, byte data[], int version, StatCallback cb, Object ctx)

        这里列出的两个API分别是同步和异步的更新接口,API方法的参数说明如下表所示。

参数名说明
path指定数据节点的节点路径,即API调用的目的是更新该节点的数据内容
data[]一个字节数组,即需要使用该数据内容来覆盖节点现在的数据内容
version指定节点的数据版本,即表明本次更新操作室针对该数据版本进行的
cb注册一个异步回调函数
ctx用于传递上下文信息的对象

version参数

        version参数用于指定节点的数据版本,表明本次更新操作是针对指定的数据版本进行的。具体来说,假如一个客户端试图进行更新操作,他会携带上次获取到的version值进行更新。而如果在这段时间内,ZooKeeper服务器上该节点的数据恰好已经被其他客户端更新了,那么其数据版本一定也发生了变化,因此肯定与客户端携带的version无法匹配,于是便无法更新成功——因此可以有效地避免一些分布式更新的并发问题,ZooKeeper的客户端就可以利用该特性构建更复杂的应用场景,例如分布式锁服务等。

使用同步API更新节点数据内容

// ZooKeeper API 更新节点数据内容,使用同步(sync)接口

public class SetData_API_Sync_Usage implements Watcher {

private static CountDownLatch connectedSemaphore = new CountDownLatch(1);

private static ZooKeeper zk;

public static void main(String[] args) throws Exception {

String path = "/zk-book";

zk = new ZooKeeper("domain1.book.zookeeper:2181", 5000, new SetData_API_Sync_Usage());

connectedSemaphore.await();

zk.create(path, "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

zk.getData(path, true, null);

Stat stat = zk.setData(path, "456".getBytes(), -1);

System.out.println(stat.getCzxid() + "," + stat.getMzxid() + "," + stat.getVersion());

Stat stat2 = zk.setData(path, "456".getBytes(), stat.getVersion());

System.out.println(stat2.getCzxid() + "," + stat2.getMzxid() + "," + stat2.getVersion());

try {

zk.setData(path, "456".getBytes(), stat.getVersion());

} catch (KeeperException e) {

System.out.println("Error: " + e.code() + "," + e.getMessage());

}

Thread.sleep(Integer.MAX_VALUE);

}

@Override

public void process(WatchedEvent event) {

if(KeeperState.SyncConnected == event.getState()) {

if(EventType.None == event.getType() && null == event.getPath()) {

connectedSemaphore.countDown();

}

}

}

}

        运行程序,输出结果如下:

        在上面的示例程序中,我们前后进行了三次更新操作,分别使用了不同的version,接下来我们针对这三次更新操作分别作讲解。

        在第一次更新操作中,使用的版本是“-1”,并且更新成功。版本“-1”代表什么:在ZooKeeper中,数据版本都是从0开始计数的,所以严格的讲,“-1”并不是一个合法的数据版本,它仅仅是一个标识符,如果客户端传入的版本参数是“-1”,就是告诉ZooKeeper服务器,客户端需要基于数据的最新版本进行更新操作。如果对ZooKeeper数据节点的更新操作没有原子性要求,那么就可以使用“-1”.

        第一次更新操作成功执行后,ZooKeeper服务端会返回给客户端一个数据节点的节点状态信息对象:stat,从这个数据结构中我们可以获取服务器上该节点的最新数据版本。从程序的运行情况可以看出,第一次更新操作完成后,节点的数据版本变更为“1”.于是在第二次更新操作中,我们在接口中传入了这个版本号,也执行成功,同时我们看到了,此时的数据版本已经变更为“2”了。

        在进行第三次操作的时候,程序依然使用了之前的数据版本“1”来进行更新操作,于是更新失败了。

        从上面这个例子中,我们可以看出,基于Version参数,可以很好的控制ZooKeeper上节点数据的原子性操作。

使用异步API更新节点数据内容

// ZooKeeper API 更新节点数据内容,使用异步(async)接口

public class SetData_API_ASync_Usage implements Watcher {

private static CountDownLatch connectedSemaphore = new CountDownLatch(1);

private static ZooKeeper zk;

public static void main(String[] args) throws Exception {

String path = "/zk-book";

zk = new ZooKeeper("domain1.book.zookeeper:2181", 5000, new SetData_API_ASync_Usage());

connectedSemaphore.await();

zk.create(path, "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

zk.setData(path, "456".getBytes(), -1, new IStatCallback(), null);

Thread.sleep(Integer.MAX_VALUE);

}

@Override

public void process(WatchedEvent event) {

if(KeeperState.SyncConnected == event.getState()) {

if(EventType.None == event.getType() && null == event.getPath()) {

connectedSemaphore.countDown();

}

}

}

}

class IStatCallback implements AsyncCallback.StatCallback {

public void processResult(int rc, String path, Object ctx, Stat stat) {

if (rc == 0) {

System.out.println("SUCCESS");

}

}

}

        异步API的使用和前面的例子基本类似,这里不再赘述。

CAS(Compare and Swap)理论

        在现代绝大多数的计算机处理器体系架构中,都实现了对CAS的指令支持。通俗地讲,CAS的意义就是:“对于值V,每次更新前都会比对其值是否是预期值A,只有符合预期,才会将V原子化地更新到新值B。”ZooKeeper的setData接口中的version参数正式由CAS原理衍化而来的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值