0


zookeeper从安装到入门

文章目录

什么是zookeeper

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Hadoop和Hbase的重要组件。

zookeeper翻译过来就是动物管理员,是管理Hadoop(大象),Hive(蜜蜂),Pig(小猪)的管理员。

zookeeper提供的主要功能包括:配置管理,分布式锁,集群管理

zookeeper的安装

我使用的是centos,于是我直接用wget命令下载下来。其他虚拟机或本地下载也可以到下面的网址下载压缩包

wget http://archive.apache.org/dist/zookeeper/zookeeper-3.5.9/apache-zookeeper-3.5.9-bin.tar.gz

之后将文件解压缩到一个自己常用的放文件的地方

tar -zxvf apache-zookeeper-3.5.9-bin.tar.gz -C/export/server

为了之后打开文件的方便,我们还可以给文件加一个软连接

ln -s /export/server/apache-zookeeper-3.5.9-bin /export/server/zookeeper

进入该目录

cd /export/server/zookeeper/conf

通过mv命令改名

mv zoo_sample.cfg zoo.cfg

你可能会好奇,为什么要改名。
官方文档中提到启动zookeeper需要一个配置文件,而这个配置文件的默认名字就是zoo.cfg,而oo_sample.cfg只是配置文件的一个示例,而我们通过改名直接把这个实例当成配置文件去使用,比较的快捷和方便,只需要修改一下参数,就可以使用了

打开文件

vim /export/server/zookeeper/conf/zoo.cfg

修改一下参数

tickTime=2000
# zookeeper数据存储目录
dataDir=/export/server/zookeeper/data
clientPort=2181
initLimit=5
syncLimit=2

要注意这里的dataDir后面的data文件夹是不存在的,需要我们自己手动创建
这个文件夹是用于我们存放数据的

到这里我们的zookeeper就算是安装完毕了

启动zookeeper并检查是否安装完成

我们可以使用一下命令启动zookeeper

/export/server/zookeeper/bin/zkServer.sh start

之后可以查看一下zookeeper服务的状态

/export/server/zookeeper/bin/zkServer.sh status

之后启动zookeeper客户端程序,进入到zookeeper的控制台中

/export/server/zookeeper/zkCli.sh

使用一下命令查看

ls /

在这里插入图片描述
如果你的结果和我一样,那么恭喜你,你的zookeeper已经装好了

zookeeper的一些操作指令

ls          查看该目录下的文件
ls -s       产看该节点的详细信息
creat       创建新文件 注意一定要有父节点才能创建子节点
create -e   创建临时节点,即关闭当前会话该节点会自己消失
create -s   创建顺序节点,会在你创捷的节点名字后面自动添加编号
get         获取节点的数据
set         修改节点的数据
delete      删除节点,但是无法删除有子节点的节点
deleteall   可以删除带有子节点的节点

zookeeper的JavaAPI

我们通过curator来简化原生的API调用

建立连接

/*
        * connectString  连接字符串  地址和端口
        * sessionTimeoutMs    会话超时时间  ms
        * connectionTimeoutMs   连接超时时间  ms
        * retryPolicy    重试策略
        *
        *
        * *///重试策略RetryPolicy retryPolicy=newExponentialBackoffRetry(3000,10);/*方法一*/CuratorFramework client =CuratorFrameworkFactory.newClient("192.168.88.130:2181",60000,15000, retryPolicy);/*方法二
         * */
         client =CuratorFrameworkFactory.builder().connectString("192.168.88.130:2181").sessionTimeoutMs(60000).connectionTimeoutMs(15000).retryPolicy(retryPolicy)//名称空间,所有的操作都会在xxx节点下.namespace("xxx").build();

        client.start();

创建节点

@TestpublicvoidtestCreate1()throwsException{//如果创建节点,没有指定数据,默认为将当前的客户端的ip当为数据String path=client.create().forPath("/app1");System.out.println(path);}@TestpublicvoidtestCreate2()throwsException{//如果创建节点,没指定数据String path=client.create().forPath("/app2","114514".getBytes(StandardCharsets.UTF_8));System.out.println(path);}@TestpublicvoidtestCreate3()throwsException{//设置节点的类型,默认为持久节点String path=client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3","114514".getBytes(StandardCharsets.UTF_8));System.out.println(path);}

我们可以进入CreatMode中看看
在这里插入图片描述
可以发现它是一个枚举类,上面的这些就是我们的节点属性

查询节点

@TestpublicvoidtestGet1()throwsException{//查询数据byte[] data = client.getData().forPath("/app1");System.out.println(newString(data));}@TestpublicvoidtestGet2()throwsException{//查询子节点List<String> path = client.getChildren().forPath("/app4");System.out.println(path);}@TestpublicvoidtestGet3()throwsException{//查询节点状态信息Stat status=newStat();byte[] data = client.getData().storingStatIn(status).forPath("/app1");System.out.println(newString(data));System.out.println(status);}

修改节点

//直接修改@TestpublicvoidtestSetData()throwsException{
        client.setData().forPath("/app1","114514".getBytes(StandardCharsets.UTF_8));}//根据版本修改@TestpublicvoidtestSetDataVersion()throwsException{Stat status=newStat();
        client.getData().storingStatIn(status).forPath("/app1");int version=status.getVersion();System.out.println(version);
        client.setData().withVersion(version).forPath("/app1","1919810".getBytes(StandardCharsets.UTF_8));}

删除节点

//删除单个节点@TestpublicvoidtestDelete()throwsException{
        client.delete().forPath("/app1");}//删除带有子节点的节点@TestpublicvoidtestDelete2()throwsException{
        client.delete().deletingChildrenIfNeeded().forPath("/app4");}//保证删除@TestpublicvoidtestDelete3()throwsException{
        client.delete().guaranteed().forPath("/app2");}//回调@TestpublicvoidtestDelete4()throwsException{
        client.delete().guaranteed().inBackground(newBackgroundCallback(){@OverridepublicvoidprocessResult(CuratorFramework curatorFramework,CuratorEvent curatorEvent)throwsException{System.out.println("删除成功");System.out.println(curatorEvent);}}).forPath("/app2");}

事件监听

zookeeper通过watcher机制实现实现了发布/订阅功能,能够让多个订阅者监听某一个对象,当一个对象自身发生状态变化是会通知所有的订阅者。
zookeeper提供了三种watcher
nodeCache:只监听某一个特定的节点
PathCildrenCache:监控一个节点所有的子节点,不包括他本身
TreeCache:监控一个树上的所有节点,相当于PathCildrenCache,但是同时监控这个节点本身

@TestpublicvoidtestNodeCache()throwsException{NodeCache nodeCache=newNodeCache(client,"/app1");
        nodeCache.getListenable().addListener(newNodeCacheListener(){@OverridepublicvoidnodeChanged()throwsException{System.out.println("节点变化");byte[] data = nodeCache.getCurrentData().getData();System.out.println(newString(data));}});
        nodeCache.start();while(true){}}@TestpublicvoidtestPathchildrenCache()throwsException{PathChildrenCache pathChildrenCache=newPathChildrenCache(client,"/app2",true);

        pathChildrenCache.getListenable().addListener(newPathChildrenCacheListener(){@OverridepublicvoidchildEvent(CuratorFramework curatorFramework,PathChildrenCacheEvent pathChildrenCacheEvent)throwsException{System.out.println("子节点变化");PathChildrenCacheEvent.Type type=pathChildrenCacheEvent.getType();//监听子节点的更新,并但会更新后的数据//设置一个过滤器,只监听update的情况if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){System.out.println("数据发生改变");byte[] data = pathChildrenCacheEvent.getData().getData();System.out.println(newString(data));}}});

        pathChildrenCache.start();while(true){}}@TestpublicvoidtestTreeCache()throwsException{TreeCache treeCache=newTreeCache(client,"/app2");

        treeCache.getListenable().addListener(newTreeCacheListener(){@OverridepublicvoidchildEvent(CuratorFramework curatorFramework,TreeCacheEvent treeCacheEvent)throwsException{System.out.println("节点变化了");System.out.println(treeCacheEvent);}});

        treeCache.start();while(true){}}

分布式锁

当我们在进行单机开发是常常采用sysnchronized或lock的方式解决线程同步问题,但是当我们的服务分布在个个服务器中的时候,这种方法已经不再使用了,因而我们引用了分布式锁的概念来解决线程同步问题。

创建的分布式锁有三种实现方式,第一种是以redis为代表的基于缓存实现的分布式锁,第二种就是我们的zookeeper实现的分布式锁,第三种就是基于数据库的悲观锁和乐观锁。

那么,我们的zookeeper又是如何实现分布式锁的呢

zookeeper实现分布式锁的核心就是当用户要获取锁时创建节点,用完时删除该节点
1.当用户获取到锁时,会在lock节点下创建一个临时顺序节点
2.之后获取lock节点下所有的子节点,当该节点的序号最小,我们就默认该节点获取到锁,用完之后将其删除
3.如果当前节点并非最小的节点,则该节点会找到比自己小1的节点,并对其注册事件监听器
4.如果收到该节点删除的消息,则该节点获取到锁

集群

leader选举规则

所有的服务器会推举最新加入集群的服务器作为leader,一个服务器超过了半数的服务器的推举,就会成为leader。当选举出了leader之后,新加入的服务器便不会在进行选举了。

当leader挂掉后,会重新选举出新的leader

集群角色

leader:处理事务请求,集群内部各服务器的调度者
follower:处理客户端非事务请求,转发请求事务给leader;参与leader选举投票
observer:与follower作用相同,但是不参与leader选举


本文转载自: https://blog.csdn.net/qq_61057438/article/details/129383464
版权归原作者 风过于前 所有, 如有侵权,请联系我们删除。

“zookeeper从安装到入门”的评论:

还没有评论