zookeeper
Znode有四种形式的目录节点(默认是persistent )
(1)持久化节点(PERSISTENT)
默认 create /node1 aaa
客户端与zookeeper断开连接后,该节点依旧存在
(2)持久化顺序节点(PERSISTENT_SEQUENTIAL)
创建zookeeper时会在路径上加上序号作为后缀,适合用于分布式锁、分布式选举等场所,创建时添加 -s 参数
create -s /node1 得到的是/node1_0000001 再次执行得到/node1_0000002
客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
(3)临时节点(EPHEMERAL)
不可再拥有子节点,跟连接会话绑定
客户端与zookeeper断开连接后,该节点有zk服务端自动删除,适用于心跳、服务发现等场景,创建时添加 -e 参数
(4)临时顺序节点(EPHEMERAL_SEQUENTIAL)
不可再拥有子节点,与持久化顺序节点类似,不同之处在于EPHEMERAL_SEQUENTIAL是临时的,会在回话断开后删除,创建时添加 -e -s 参数
zookeeper选举机制
第一次启动按照启动顺序以及MyId的值进行选举,满足:启动数量过半、启动早、MyId大 为leader
非第一次选举
1.判断当前剩余主机是否过半
2.比较剩余主机数据,哪个最新,数据最新的直接当leader 参数:mZxid 数据新旧 值越大数据越新
3.如果新旧程度一样,则比较MyId,谁最大谁就当leader
JavaAPI
建立连接:
/** * 建立连接 */ @Before public void testConnect() { /* * * @param connectString 连接字符串。zk server 地址和端口 "192.168.149.135:2181,192.168.149.136:2181" * @param sessionTimeoutMs 会话超时时间 单位ms * @param connectionTimeoutMs 连接超时时间 单位ms * @param retryPolicy 重试策略 */ /* //重试策略 RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10); //1.第一种方式 CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.149.135:2181", 60 * 1000, 15 * 1000, retryPolicy);*/ //重试策略 RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10); //2.第二种方式 //CuratorFrameworkFactory.builder(); client = CuratorFrameworkFactory.builder() .connectString("192.168.200.130:2181") .sessionTimeoutMs(60 * 1000) .connectionTimeoutMs(15 * 1000) .retryPolicy(retryPolicy) .namespace("mulumingchen") .build(); //开启连接 client.start(); }
创建节点:create 持久 临时 顺序 数据;data为byte字节数组
1.基本创建:create().forPath("/demo") 在zookeeper根节点下创建demo
2.创建节点,带有数据:create().forPath("",data)
3.设置节点的类型:create().withMode().forPath("",data);withMode(CreateMode.上面四种节点类型值)
4.创建多级节点 /demo/d1:create().creatingParentsIfNeeded().forPath("/demo/d1",data);demo目录不存在时使用creatingParentsIfNeeded;临时性节点没有子节点
@Test public void testCreate() throws Exception { //2. 创建节点 带有数据 //如果创建节点,没有指定数据,则默认将当前客户端的ip作为数据存储 String path = client.create().forPath("/app2", "hehe".getBytes()); System.out.println(path); } @Test public void testCreate2() throws Exception { //1. 基本创建 //如果创建节点,没有指定数据,则默认将当前客户端的ip作为数据存储 String path = client.create().forPath("/app1"); System.out.println(path); }
/*
节点类型:
持久化节点:PERSISTENT
持久化顺序节点:PERSISTENT_SEQUENTIAL
临时化节点:EPHEMERAL
临时化顺序节点:EPHEMERAL_SEQUENTIAL
*/
@Test public void testCreate3() throws Exception { //3. 设置节点的类型 //默认类型:持久化 String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3"); System.out.println(path); } @Test public void testCreate4() throws Exception { //4. 创建多级节点 /app1/p1 //creatingParentsIfNeeded():如果父节点不存在,则创建父节点 String path = client.create().creatingParentsIfNeeded().forPath("/app4/p1"); System.out.println(path); }
查询节点:
1. 查询数据:get: getData().forPath()
2. 查询子节点: ls: getChildren().forPath()
3. 查询节点状态信息:ls -s:getData().storingStatIn(状态对象 Stat).forPath()
@Test public void testGet1() throws Exception { //1. 查询数据:get byte[] data = client.getData().forPath("/app1"); System.out.println(new String(data)); } @Test public void testGet2() throws Exception { // 2. 查询子节点: ls List<String> path = client.getChildren().forPath("/"); System.out.println(path); } @Test public void testGet3() throws Exception { Stat status = new Stat(); System.out.println(status); //3. 查询节点状态信息:ls -s client.getData().storingStatIn(status).forPath("/app1"); System.out.println(status); }
修改数据
1. 基本修改数据:setData().forPath()
2. 根据版本修改: setData().withVersion().forPath()
version 是通过查询出来的。目的就是为了让其他客户端或者线程不干扰我。
@Test public void testSet() throws Exception { client.setData().forPath("/app1", "itcast".getBytes()); } @Test public void testSetForVersion() throws Exception { Stat status = new Stat(); //3. 查询节点状态信息:ls -s client.getData().storingStatIn(status).forPath("/app1"); int version = status.getVersion();//查询出来的 3 System.out.println(version); client.setData().withVersion(version).forPath("/app1", "hehe".getBytes()); }
删除节点: delete deleteall
1. 删除单个节点:delete().forPath("/app1");
2. 删除带有子节点的节点:delete().deletingChildrenIfNeeded().forPath("/app1");
3. 必须成功的删除:为了防止网络抖动。本质就是重试。 client.delete().guaranteed().forPath("/app2");
4. 回调:inBackground
@Test public void testDelete() throws Exception { // 1. 删除单个节点 client.delete().forPath("/app1"); } @Test public void testDelete2() throws Exception { //2. 删除带有子节点的节点 client.delete().deletingChildrenIfNeeded().forPath("/app4"); } @Test public void testDelete3() throws Exception { //3. 必须成功的删除 client.delete().guaranteed().forPath("/app2"); } @Test public void testDelete4() throws Exception { //4. 回调 client.delete().guaranteed().inBackground(new BackgroundCallback(){ @Override public void processResult(CuratorFramework client, CuratorEvent event) throws Exception { System.out.println("我被删除了~"); System.out.println(event); } }).forPath("/app1"); }