zookeeper诞生背景和基于Curator的基本操作

zookeeper诞生背景和基于Curator的基本操作

一、包含的知识点

  • zookeeper出现的背景
  • zookeeper核心知识点
  • zookeeper包含的特性
  • zookeeper基于Curator的实践操作

二、zookeeper出现的背景

​ 在讲解zookeeper之前, 先了解Google Chubby的作用, Chubby是用来解决分布式一致性问题的组件, 同时也是粗粒度的分布式锁服务。关于Google Chubby更详细内容可以根据对应链接进行查看 。Chubby提供的功能:

  • 解决分布式一致性问题
  • 粗力度分布式锁

2.1 分布式一致性问题

​ 互联网开发过程中, 分布式系统必然存在多个节点, 以投票操作为例, 如果需要达到一致性结果, 需要满足

  1. 每个节点都会提出请求,

  2. 所有节点请求只有一个能通过,

  3. 这个结果对所有节点都是一致的。

​ 但是实际环境可能存在下面的问题:

  • 通信异常
    • 节点和节点之间存在网络不可用、消息延时、消息丢失问题
  • 网络分区
    • 服务组内通信正常, 组间通信异常, 通常提到的 “脑裂” 现象
  • 节点故障
    • 节点出现宕机、器件损坏
  • 请求三态
    • 节点请求存在成功、失败、超时, 如果请求超时, 请求者无法知道是否成功处理

​ 其实这就是常说的**拜占庭将军问题**, 即如何在网络通信不可靠、消息可能丢失、网络延迟背景下对某个请求达成一致。

那Chubby实现原理是怎样的呢 ?

​ 在进行选举投票阶段, 所有的节点Server通过Chubby提供的通信协到Chubby Server创建同一个文件, 最终只有一个文件能够获准创建这个文件, 创建成功的Server成为master, 并在这个文件中写入自己相关信息, 其它节点通过读取这个文件获取master地址信息。

2.2 粗力度分布式锁

​ Chubby是通过创建文件来提供锁功能, 节点向Chubby Server创建文件的过程其实就是加锁操作, 文件创建成功表示抢占到了锁。而Chubby没有开源, 雅虎基于Chubby思想研发了zookeeper, 所以作为高可靠的分布式协调中间件zookeeper, 它是Google Chubby的一个开源实现。

:

1. zookeeper是基于Chubby思想来设计的, 它的作用是实现分布式锁, 注册中心只是它实现的一种功能而已。

2. 本篇文章主要讨论zookeeper相关知识, 对分布式一致性解决方案的具体讨论, 后面会专门整理一篇文章来说明

三、Zookeeper核心知识点

​ 如果需要对zookeeper有深入的了解, 对其相关名词的了解肯定少不了, 下面对zookeeper常见的名词进行整理

  • 集群角色

    • Leader
      • 领导者, 集群只有一个, 处理客户端的写请求, 参与选举
    • Follower
      • 跟随者, 集群中除Leader外可参与选择的Server, 处理客户端的读请求, 参与选举
    • Observer
      • 观察者, 处理客户端的读请求, 不参与选举
  • ZNode

    • zookeeper的视图结构和标准文件系统类似, 每个节点称之为ZNode, 是zookeeper的最小单元, 每个节点可以保存数据以及挂载子节点
  • ZNode分类

    • 持久节点(PERSISTENT)
      • 当客户端失去连接时, znode不会自动删除
    • 持久有序节点(PERSISTENT_SEQUENTIAL)
      • 当客户端失去连接时, znode不会自动删除
      • 节点以单调递增的方式命名
    • 临时节点(EPHEMERAL)
      • 当客户端失去连接时, znode会自动删除
    • 临时节点(EPHEMERAL_SEQUENTIAL)
      • 当客户端失去连接时, znode会自动删除
      • 节点以单调递增的方式命名
  • 会话Session

    zookeeper会话流转图

    • Client初始化连接, 状态转为Connecting
    • Client与Server成功建立连接, 状态转为Connected
    • Client与Server连接丢失或没有收到Server响应, 状态转为Connecting
    • Client主动关闭会话, 状态转为Closed
    • 会话过期(Server负责会话过期), 状态转为Closed
  • Stat状态信息

    @InterfaceAudience.Public
    public class Stat implements Record {
      private long czxid; // 表示该节点被创建时的事务ID
      private long mzxid; // 表示该节点最后一次被更新时的事务ID
      private long ctime; // 表示节点被创建时的时间
      private long mtime; // 表示节点最后一次被更新时的时间
      private int version; // 数据节点版本号
      private int cversion;	// 子节点版本号
      private int aversion;	// 子节点ACL版本号
      private long ephemeralOwner;	// 创建临时结点时的会话sessionId, 如果是持久化结点, 固定值0
      private int dataLength; // 数据内容长度
      private int numChildren; // 当前结点的子节点个数
      private long pzxid; // 表示当前结点的子节点列表最后一次被修改时的事务ID, NOTE: 只有子节点列表变更时才会变更pzxid, 子节点内容变更不会影响pzxid
    }
    
  • zookeeper 权限

  • Create 允许对子节点执行创建操作

  • Delete 允许对子节点执行删除操作

  • Read 允许对本节点执行 getChildren 和 getData操作

  • Write 允许对本节点执行 setData操作

  • Admin 允许对本节点执行setAcl操作

  • zookeeper重试策略

zookeeper重试策略

  • ExponentialBackoffRetry : 重试指定次数, 每次重试之间停顿时间增加

  • RetryNTimes : 指定最大重试次数的重试策略

  • RetryOneTime : 重试次数只有一次的重试策略

  • RetryUntilElapsed : 一直重试直到达到指定时间的重试策略

  • zookeeper事件

@InterfaceAudience.Public
public enum EventType {
  None (-1),										//当zookeeper客户端连接状态发生变更时(KeeperState),该事件被触发
  NodeCreated (1),							//当结点被创建时, 该事件被触发
  NodeDeleted (2),							//当结点被删除时, 该事件被触发
  NodeDataChanged (3),					//当结点的数据发生变更时, 该事件被触发
  NodeChildrenChanged (4);			//当结点的直接子节点发生创建、删除操作时, 该事件被触发
}
//客户端连接状态
public enum KeeperState {
  Unknown (-1),
  Disconnected (0),
  NoSyncConnected (1),
  SyncConnected (3),
  AuthFailed (4),
  ConnectedReadOnly (5),
  SaslAuthenticated(6),
  Expired (-112);
}
  • Zookeeper watch监听结点变化方式
    • PathChildCache
      • 监听某路径下子结点创建、删除、更新
    • NodeCache
      • 监听当前结点的创建、更新、删除, 并将结点数据缓存在本地
    • TreeCache
      • 同时具有PathChildCache和NodeCahce功能, 监听某路径下创建、删除、更新事件, 并缓存路径下所有结点数据

四、zookeeper特性

​ 从第二节、第三节内容了解, zookeeper具有如下特点

  • 临时节点
  • 持久化节点
  • 顺序节点
  • 临时节点不能创建子节点
  • 同一级节点不能创建相同名称的节点
  • TTL和容器节点

五、zookeeper基于Curator的实践操作

5.1 pom文件

<dependency>
  <groupId>org.apache.curator</groupId>
  <artifactId>curator-framework</artifactId>
  <version>4.0.0</version>
</dependency>
<dependency>
  <groupId>org.apache.curator</groupId>
  <artifactId>curator-recipes</artifactId>
  <version>4.0.0</version>
</dependency>
<dependency>
  <groupId>org.apache.zookeeper</groupId>
  <artifactId>zookeeper</artifactId>
  <version>3.4.13</version>
</dependency>

5.2 增删改查操作

public class CuratorMain {
    private static String CONNECTION_STR="127.0.0.1:2181";

    public static void main(String[] args) throws Exception {
        CuratorFramework curatorFramework= CuratorFrameworkFactory.builder()
                .connectString(CONNECTION_STR)
                .sessionTimeoutMs(5000)
                .retryPolicy(new ExponentialBackoffRetry(1000,3))
                .build();
        curatorFramework.start(); //启动
      
        createData(curatorFramework);
//        updateData(curatorFramework);
//        queryData(curatorFramework);
//        deleteData(curatorFramework);
    }

    // 新增
    private static void createData(CuratorFramework curatorFramework) throws Exception {
        curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).
                forPath("/data/program","test".getBytes());

    }

    // 更新
    private static void updateData(CuratorFramework curatorFramework) throws Exception {
        curatorFramework.setData().forPath("/data/program","up".getBytes());
    }

    private static void queryData(CuratorFramework curatorFramework) throws Exception {
        byte[] bytes = curatorFramework.getData().forPath("/data/program");
        String data = new String(bytes) ;
        System.out.println(data);
    }
    // 删除
    private static void deleteData(CuratorFramework curatorFramework) throws Exception {
        Stat stat=new Stat();
        String value=new String(curatorFramework.getData().storingStatIn(stat).forPath("/data/curator"));
        curatorFramework.delete().withVersion(stat.getVersion()).forPath("/data/curator");
    }
}

5.3 zookeeper watch 监听机制

public class WatchMain {
    private static String CONNECTION_STR="127.0.0.1:2181";

    public static void main(String[] args) throws Exception {
        CuratorFramework curatorFramework = CuratorFrameworkFactory.builder().
                connectString(CONNECTION_STR).sessionTimeoutMs(5000).
                retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
        curatorFramework.start();
//        addListenerWithNode(curatorFramework);
        addListenerWithChild(curatorFramework) ;

        System.in.read();
    }

    //配置中心
    //创建、修改、删除
    private static void addListenerWithNode(CuratorFramework curatorFramework) throws Exception {
        NodeCache nodeCache=new NodeCache(curatorFramework,"/watch",false);
        NodeCacheListener nodeCacheListener = () -> {
            System.out.println("receive Node Changed");
            System.out.println(nodeCache.getCurrentData().getPath()+"---"+new String(nodeCache.getCurrentData().getData()));
        };
        nodeCache.getListenable().addListener(nodeCacheListener);
        nodeCache.start();
    }

    //实现服务注册中心的时候,可以针对服务做动态感知
    private static void addListenerWithChild(CuratorFramework curatorFramework) throws Exception {
        PathChildrenCache nodeCache=new PathChildrenCache(curatorFramework,"/watch",true);
        PathChildrenCacheListener nodeCacheListener= (curatorFramework1, pathChildrenCacheEvent) -> {
            System.out.println(pathChildrenCacheEvent.getType() + "->" + new String(pathChildrenCacheEvent.getData().getData()));
        } ;
        nodeCache.getListenable().addListener(nodeCacheListener);
        nodeCache.start(PathChildrenCache.StartMode.NORMAL);
    }
}

//addListenerWithNode 测试命令
# create /watch watch-create
# set /watch watch-update
# delete /watch

//addListenerWithChild 测试命令
# create /watch/child child-create
# update /watch/child child-update
# delete /watch/child
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值