读《分布式一致性原理》JAVA客户端API操作3
?
更新數據
客戶端可以通過zookeeper的API來更新一個節點的數據內容,有如下兩個接口:
?
public Stat setData(final String path, byte data[], int version)public void setData(final String path, byte data[], int version,StatCallback cb, Object ctx)?
更新數據的接口較為簡單明了。我們重點來看下方法中的version參數。version參數是指定節點的數據版本。表明本次更新是針對指定版本進行的。
《java并發編程實踐》一書提到,在現代的絕大數計算機處理器體系架構中,都實現了對CAS指令支持,
通俗的將,CAS的意思是“對于值V,每次更新都會對其值是否是值是否是預期值A,只有符合預期,才會將A原子化的更新為B”。zookeeper中setData接口中的version參數正是由CAS原理演化而來的。
具體來說,假如有個客戶端想要進行更新操作,那么肯定會攜帶上次獲取的version值進行更新。如果在這段時間,該數據恰好被其他客戶端更新了,那么其數據版本一定也發生了變化,因此肯定與客戶端攜帶的version無法匹配,于是便無法更新成功??梢杂行У谋苊夥植际礁碌牟l問題。
?
使用同步API更新節點數據內容
package setdata;import java.io.IOException; import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.data.Stat;import getdata.GetData1;public class SetData1 implements Watcher {public static CountDownLatch connectedSemaphore = new CountDownLatch(1);private static ZooKeeper zk = null;private static Stat stat = new Stat();@Overridepublic void process(WatchedEvent event) {if (KeeperState.SyncConnected==event.getState()) {if (EventType.None.getIntValue()==event.getState().getIntValue()&&null==event.getPath()) {connectedSemaphore.countDown();}}}public static void main(String[] args) throws IOException, InterruptedException, KeeperException {String path = "/zk-book";zk = new ZooKeeper("192.168.64.60:2181", 5000, new SetData1());connectedSemaphore.await();zk.create(path, "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);Stat stat2 = zk.setData(path, "456".getBytes(), -1);System.out.println(stat.getCzxid()+"---"+stat.getMzxid()+"--"+stat.getVersion());Thread.sleep(Integer.MAX_VALUE);;}}?
在zookeeper中,數據版本都是從0開始的,所以嚴格來講-1并不是一個數據版本,它僅僅是一個
標示符,是告訴服務器對最新版本進行更新操作。如果對zookeeper數據節點的更新操作沒有原子性要求,那么就可以使用“-1”;
?
所以用異步的API更新數據內容
package getdata;import java.io.IOException; import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.AsyncCallback; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooDefs.Ids;public class GetData2 implements Watcher {public static CountDownLatch connectedSemaphore = new CountDownLatch(1);private static ZooKeeper zk = null;private static Stat stat = new Stat();@Overridepublic void process(WatchedEvent event) {if (KeeperState.SyncConnected==event.getState()) {if (EventType.None.getIntValue()==event.getState().getIntValue()&&null==event.getPath()) {connectedSemaphore.countDown();}}}public static void main(String[] args) throws IOException, InterruptedException, KeeperException {String path = "/zk-book";zk = new ZooKeeper("192.168.64.60:2181", 5000, new GetData2());connectedSemaphore.await();zk.create(path, "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL );zk.setData(path, "456".getBytes(), -1,new IDataback(),"");Thread.sleep(Integer.MAX_VALUE);;} }class IDataback implements AsyncCallback.StatCallback{@Overridepublic void processResult(int rc, String path, Object ctx, Stat stat) {if (rc==0) {System.out.println("SUCCESS");}}}?
檢測節點是否存在
客戶端可以通過zookeeper的api來檢測一個節點
?
?
?
?該接口主要用于檢測指定節點是否存在,返回值是一個Stat對象。如果在調用接口時注冊Watcher的話,
還可以對節點是否存在進行監聽,一旦節點被創建被刪除或被更新,都會通知客戶端。
?
權限控制
在zookeeper的實際使用中,我們的做法往往是搭建一個共用的zookeeper集群,同一為若干個應用提供服務,在這種情況下,不同的應用往往是不存在共享數據的場景的。因此需要解決不同應用之間的權限問題。
zookeeper提供了多種權限控制模式(Scheme),分別是world,auth,digest,ip和super。
本節中我們主要講digest模式下是如何進行zookeeper權限控制的。
?
開發人員如果要使用zookeeper的權限控制功能,需要在zookeeper完成會話創建的時候,給該會話添加相關的權限信息(AuthInfo)。zookeeper客戶端提供了相應的API接口來進行權限信息的設置。
該接口的主要作用是為當前的zookeeper會話添加權限信息,之后范式通過該會話對zookeeper服務端進行的任何操作都會帶上該權限信息。
使用包含權限信息的zookeeper會話創建數據節點。
package auth;import java.io.IOException; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper;public class AuthInfo {final static String PATH="/zk-book-auth_test";public static void main(String[] args) throws IOException, KeeperException, InterruptedException {ZooKeeper zk = new ZooKeeper("192.168.64.60:2181", 5000, null);zk.addAuthInfo("digest", "foo:true".getBytes());zk.create(PATH, "123".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.EPHEMERAL);Thread.sleep(Integer.MAX_VALUE);} }?
?使用無權限信息的zookeeper會話訪問權限信息的數據節點。
?
package auth;import java.io.IOException; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper;public class AuthInfo2 {final static String PATH="/zk-book-auth_test";public static void main(String[] args) throws IOException, KeeperException, InterruptedException {ZooKeeper zk = new ZooKeeper("192.168.64.60:2181", 5000, null);zk.addAuthInfo("digest", "foo:true".getBytes());zk.create(PATH, "123".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.EPHEMERAL);ZooKeeper zk2 = new ZooKeeper("192.168.64.60:2181", 5000, null);zk2.getData(PATH, false, null);Thread.sleep(Integer.MAX_VALUE);} }?
?
?一旦我們對一個數據節點設置了權限信息,那么其他沒有權限設置的客戶端會話將無法訪問該數據節點。
?
對于刪除及誒單(delete)接口而言,其權限控制比較特殊。
import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; /** * * @ClassName: AuthSample_Delete * @Description: TODO(刪除節點的權限控制) * @author RongShu * @date 2017年6月11日 下午8:41:23 * */ public class AuthSample_Delete { final static String PATH = "/zk-book-auth_test"; final static String PATH2 = "/zk-book-auth_test/child"; public static void main(String[] args) throws Exception { ZooKeeper zookeeper1 = new ZooKeeper("localhost:2181",5000,null); zookeeper1.addAuthInfo("digest", "foo:true".getBytes()); zookeeper1.create( PATH, "init".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT ); zookeeper1.create( PATH2, "init".getBytes(), Ids.CREATOR_ALL_ACL, CreateMode.EPHEMERAL ); try { ZooKeeper zookeeper2 = new ZooKeeper("localhost:2181",50000,null); zookeeper2.delete( PATH2, -1 ); } catch ( Exception e ) { System.out.println( "刪除節點失敗: " + e.getMessage() ); } ZooKeeper zookeeper3 = new ZooKeeper("localhost:2181",50000,null); zookeeper3.addAuthInfo("digest", "foo:true".getBytes()); zookeeper3.delete( PATH2, -1 ); System.out.println( "成功刪除節點:" + PATH2 ); ZooKeeper zookeeper4 = new ZooKeeper("localhost:2181",50000,null); zookeeper4.delete( PATH, -1 ); System.out.println( "成功刪除節點:" + PATH ); } } 輸出 刪除節點失敗: KeeperErrorCode = NoAuth for /zk-book-auth_test/child 成功刪除節點:/zk-book-auth_test/child 成功刪除節點:/zk-book-auth_test注意:
當客戶端對一個數據節點添加了權限信息后,對于刪除操作而言,其作用范圍是其子節點,也就是說,當我們對一個數據節點添加權限信息之后,依然可以自由的刪除這個節點,但是對于這個節點的子節點,就必須使用相應的權限信息才能夠刪掉它。
?
轉載于:https://www.cnblogs.com/duan2/p/9070011.html
總結
以上是生活随笔為你收集整理的读《分布式一致性原理》JAVA客户端API操作3的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 充300块钱电费七个人每人出多少钱
- 下一篇: 14亿分钟等于多少年?