快学Big Data -- Zookeeper (十)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xfg0218/article/details/82317148

Zookeeper 总结

 

 

 

 

学习是一种浮躁的事情,要静下心来慢慢的品味。    -- 小徐

 

官网:http://zookeeper.apache.org/

 

 

 

 

 

 

 

 

 

概述

    zookeeper 主要负责管理机器的正常运行,如果一台机器突然死掉,利用zookeeper的机制可以快速的启动另一台备份的机器,zookeeper在这一方面做出了杰出的贡献,底层实现的算法是fast paxos 与baxic paxos算法,当zookeeper失去太多的leader或者太多的follower时会进入回复的状态,进行选举。

ZNode用来描述ZooKeeper中的数据节点,它持有一个状态数据结构(stat),此结构中包含数据更新的版本号、访问权限(ACL)更新的版本号、时间戳。这些版本号和时间戳使ZooKeeper可以验证缓存有效性和协调更新。每当ZNode中的数据更新时,版本号都会递增。

ZooKeeper主要的职责为管理用户提交的数据,以及为用户程序提供数据节点监听服务。

 

 

角色

  Zookeeper 有两种角色分别是leader 与follower (obsever), 在选举时机器超过一半即可存活,一般的机器配置成单个数

特性

  1. 每台机器上保存的数据一致,用户不管访问那台机器获取的数据信息都是一致的
  2. 分布式的读写,更细请求转发都是由leader转发的
  3. 数据更新原子性,一次数据的更新要不成功要不失败
  4. 每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识
  5. 实时性,在一定的范围内,client能读取到最新的数据。
  6. 数据更新原子性,一次数据更新要么成功(半数以上节点成功),要么失败

选举机制

     那么,初始化的时候,是按照上述的说明进行选举的,但是当zookeeper运行了一段时间之后,有机器down掉,重新选举时,选举过程就相对复杂了,在选举时zookeeper有Fast Paxos与Basic Paxos算法来辅助选举,系统默认的选举算法为fast paxos。

需要加入数据version、leader id和逻辑时钟。

数据version:数据新的version就大,数据每次更新都会更新version。

Leader id:就是我们配置的myid中的值,每个机器一个。

逻辑时钟:这个值从0开始递增,每次选举对应一个值,也就是说:  如果在同一次选举中,那么这个值应该是一致的 ;  逻辑时钟值越大,说明这一次选举leader的进程更新.

选举的标准就变成:

1、逻辑时钟小的选举结果被忽略,重新投票

2、统一逻辑时钟后,数据id大的胜出

3、数据id相同的情况下,leader id大的胜出

根据这个规则选出leader。

Zookeeper 节点的类型

    Zookeeper有两种节点四种模式,有持久的一临时的两种节点,持久节点(PERSISTENT)、持久顺序节点(PERSISTENT_SEQUENTIAL)、临时节点(EPHEMERAL)、临时顺序节点(EPHEMERAL_SEQUENTIAL)四种模式。

 

 

 

 

Zookeeper 权限详解

ZK的节点有5种操作权限:

CREATE、READ、WRITE、DELETE、ADMIN 也就是 增、删、改、查、管理权限,这5种权限简写为crwda(即:每个单词的首字符缩写)。

 

代码显示所示zookeeper的权限:

Zookeeper 的部署

软件下载:链接:http://pan.baidu.com/s/1dEVRq2d 密码:ggng  如果无法下载请联系作者。

Zk链接工具:https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip

监控软件Node-zk-browser下载:链接:http://pan.baidu.com/s/1c2zf03Y 密码:4od0

1 -1 ) 、安装

[root@hadoop1 local]# tar -zxvf zookeeper-3.4.8.tar.gz

[root@hadoop1 local]# cd  zookeeper-3.4.8

1-2 ) 、修改配置文件 

A)、修改zoo.cfg文件

[root@hadoop1 conf]# cp zoo_sample.cfg  zoo.cfg

[root@hadoop3 conf]# cat zoo.cfg

# The number of milliseconds of each tick

tickTime=2000

# The number of ticks that the initial

# synchronization phase can take

initLimit=10

# The number of ticks that can pass between

# sending a request and getting an acknowledgement

syncLimit=5

# the directory where the snapshot is stored.

# do not use /tmp for storage, /tmp here is just

# example sakes.

dataDir=/usr/local/zookeeper-3.4.5/conf

# the port at which the clients will connect

clientPort=2181

# the maximum number of client connections.

# increase this if you need to handle more clients

#maxClientCnxns=60

#

# Be sure to read the maintenance section of the

# administrator guide before turning on autopurge.

#

# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance

#

# The number of snapshots to retain in dataDir

#autopurge.snapRetainCount=3

# Purge task interval in hours

# Set to "0" to disable auto purge feature

#autopurge.purgeInterval=1

server.1=hadoop1:2888:3888

server.2=hadoop2:2888:3888

server.3=hadoop3:2888:3888

 

 

tickTime ::表示服务器端与客户端之间的心跳的间隔。

initLimit:初始化链接急群众的leader与Follower之间的通信的时长,如果超过这个时间间隔zookeeper则会任务这个客户端死掉了。

syncLimit:表示Leader与Follower之间的发送消息,请求与答应的时间的长度,最长不超过tickTime的时间的长度,总长度为2*2000=4秒的时间。

dataDir ::是zookeeper 保存数据的目录,zookeeper的日志文件也将写入到这个文件夹中。

clientPort :对外提供的端口,默认的是2181

Server.1:hadoop1:2888:3888:1代表第几台服务器的编号,hadoop1是服务器的IP地址,2888是心跳端口,3888是选举端口。

 

B)、传送文件

[root@hadoop1 local]# scp -r zookeeper-3.4.8/ hadoop2:/usr/local/

[root@hadoop1 local]# scp -r zookeeper-3.4.8/ hadoop3:/usr/local/

C)、创建myid的目录

[root@hadoop1 conf]# mkdir -p /usr/local/zookeeper-3.4.5/conf/

[root@hadoop2 conf]# mkdir -p /usr/local/zookeeper-3.4.5/conf/

[root@hadoop3 conf]# mkdir -p /usr/local/zookeeper-3.4.5/conf/

D)、在每个机器上配置myid

[root@hadoop1 local]# echo  "1"> /usr/local/zookeeper-3.4.5/conf/myid

[root@hadoop2 local]# echo  "2"> /usr/local/zookeeper-3.4.5/conf/myid

[root@hadoop3 local]# echo  "3" > /usr/local/zookeeper-3.4.5/conf/myid

 

E)、在每台机器上添加快捷方式

[root@hadoop1 local]# vi  /etc/profile

export ZK_HOME=/usr/local/zookeeper-3.4.5

export PATH=$PATH:$ZK_HOME/bin

 

使配置文件生效

[root@hadoop1 local]# source /etc/profile

 

F)、修改节点的储存大小

在zookeeper上默认的节点的储存大小是1M,如果想修节点的大小在zkServer.sh 文件中添加一下属性:

ZOO_USER_CFG="-Djute.maxbuffer=10240000" 

 

详细请看:http://blog.csdn.net/xfg0218/article/details/52709917,建议不要修改的太大,因为太大为带了zookeeper的负担。

 

1-3 ) 、启动

在hadoop1/hadoop2/hadoop3 机器上分别启动 zkServer.sh start

[root@hadoop1 zookeeper]# zkServer.sh start

ZooKeeper JMX enabled by default

Using config: /usr/local/zookeeper-3.4.8/bin/../conf/zoo.cfg

Starting zookeeper ... STARTED

1-4)、一键启动&关闭脚本

[root@hadoop1 start_sh]# vi slave

hadoop1

hadoop2

hadoop3

 

[root@hadoop1 start_sh]# vi  zookeeper.sh

#!/bin/bash

cat /usr/local/start_sh/slave |while read slave

do

{

echo $line

ssh $line "source /etc/profile;nohup zkServer.sh start"

}&

wait

done

 

 

[root@hadoop1 start_sh]# vi  stop_zookeeper.sh

#!/bin/bash

cat /usr/local/start_sh/slave |while read slave

do

{

echo $line

ssh $line "source /etc/profile;nohup zkServer.sh stop"

}&

wait

done

 

 

[root@hadoop1 start_sh]# chmod a+x zookeeper.sh

[root@hadoop1 start_sh]# ./ zookeeper.sh

1-5 ) 、查看进程状态

[root@hadoop1 conf]# jps

3101 QuorumPeerMain

 

 

[root@hadoop1 conf]# zkServer.sh status

ZooKeeper JMX enabled by default

Using config: /usr/local/zookeeper-3.4.8/bin/../conf/zoo.cfg

Mode: follower

 

[root@hadoop2 ~]# zkServer.sh status

ZooKeeper JMX enabled by default

Using config: /usr/local/zookeeper-3.4.8/bin/../conf/zoo.cfg

Mode: follower

 

[root@hadoop3 ~]# zkServer.sh status

ZooKeeper JMX enabled by default

Using config: /usr/local/zookeeper-3.4.8/bin/../conf/zoo.cfg

Mode: leader

1-6) 、节点类型

A)、znode 的特征

Znode是客户端访问ZooKeeper的主要实体,它包含以下几个特征:

1-1)、Watches

客户端可以在节点上设置watch(我们称之为监视器)。当节点状态发生改变时(数据的增、删、改)将会触发watch所对应的操作。当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,因为watch只能被触发一次。

1-2)、数据访问

     ZooKeeper中的每个节点存储的数据要被原子性的操作。也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。

 

1-3)、节点类型

    ZooKeeper中的节点有两种,分别为临时节点和永久节点。节点的类型在创建时即被确定,并且不能改变。

ZooKeeper的临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话结束,临时节点将被自动删除,当然可以也可以手动删除。另外,需要注意是, ZooKeeper的临时节点不允许拥有子节点。

ZooKeeper的永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。

 

1-4)、顺序节点(唯一性的保证)

     当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数。这个计数对于此节点的父节点来说是唯一的,它的格式为"%10d"(10位数字,没有数值的数位用0补充,例如"0000000001")。当计数值大于232-1时,计数器将溢出。

 

B)、CreateMode的类型

org.apache.zookeeper.CreateMode中定义了四种节点类型,分别对应:

PERSISTENT:永久节点

EPHEMERAL:临时节点

PERSISTENT_SEQUENTIAL:永久节点、序列化

EPHEMERAL_SEQUENTIAL:临时节点、序列化

 

C)、znode的版本号

1-1)、dataVersion

    数据版本号,每次对节点进行set操作,dataVersion的值都会增加1(即使设置的是相同的数据)。

1-2)、cversion

子节点的版本号。当znode的子节点有变化时,cversion 的值就会增加1。

1-3)、aclVersion

    ACL的版本号,关于znode的ACL(Access Control List,访问控制),可以参考资料1 有关ACL的描述。

1-7 ) 、zookerper 的客户端连接

  1. 、Linux 端链接

1-1)、查看帮助信息

运行 zkCli.sh –server <ip>进入命令行工具

 

[root@hadoop1 conf]# zkCli.sh -server hadoop1

**********

Welcome to ZooKeeper!

2016-10-03 07:58:35,247 [myid:] - INFO  [main-SendThread(hadoop1:2181):ClientCnxn$SendThread@1032] - Opening socket connection to server hadoop1/192.168.215.134:2181. Will not attempt to authenticate using SASL (unknown error)

JLine support is enabled

2016-10-03 07:58:35,510 [myid:] - INFO  [main-SendThread(hadoop1:2181):ClientCnxn$SendThread@876] - Socket connection established to hadoop1/192.168.215.134:2181, initiating session

2016-10-03 07:58:36,231 [myid:] - INFO  [main-SendThread(hadoop1:2181):ClientCnxn$SendThread@1299] - Session establishment complete on server hadoop1/192.168.215.134:2181, sessionid = 0x1578a466e400001, negotiated timeout = 30000

 

WATCHER::

 

WatchedEvent state:SyncConnected type:None path:null

// 查看命令帮助

[zk: hadoop1(CONNECTED) 0] list

ZooKeeper -server host:port cmd args

connect host:port

get path [watch]

ls path [watch]

set path data [version]

rmr path

delquota [-n|-b] path

quit

printwatches on|off

create [-s] [-e] path data acl

stat path [watch]

close

ls2 path [watch]

history

listquota path

setAcl path acl

getAcl path

sync path

redo cmdno

addauth scheme auth

delete path [version]

setquota -n|-b val path

 

1-2)、创建节点

[zk: localhost:2181(CONNECTED) 11] create /testzookeeper "xiaozhang"

Created /testzookeeper

1-3)、查看当前节点是否有子节点

[zk: localhost:2181(CONNECTED) 15] ls /testzookeeper

[]

1-4)、查看数据节点的信息

[zk: hadoop1(CONNECTED) 3] get /testzookeeper

// 节点的数据

"xiaozhang"

// 表示该ZNode被创建时的事务ID

cZxid = 0x500000001f

// Created Time,表示该ZNode被创建的时间

ctime = Sun Oct 02 19:46:06 PDT 2016

// Modified ZXID,表示该ZNode最后一次被更新时的事务ID

mZxid = 0x500000001f

// Modified Time,表示该节点最后一次被更新的时间

mtime = Sun Oct 02 19:46:06 PDT 2016

// 表示该节点的子节点列表最后一次被修改时的事务ID。注意,只有子节点列表变更了才会变更pZxid,子节点内容变更不会影响pZxid

pZxid = 0x5000000023

// 子节点的版本号

cversion = 2

// 数据节点的版本号

dataVersion = 0

// ACL版本号(权限的版本)

aclVersion = 0

// 创建该节点的会话的seddionID。如果该节点是持久节点,那么这个属性值为0。

ephemeralOwner = 0x0

// 数据内容的长度

dataLength = 0

// 子节点的个数

numChildren = 2

// 对spark的子节点数据的变化进行了监听

[zk: hadoop1(CONNECTED) 4] ls /spark watch

[master_status, leader_election]

// 获取spark子节点的变化监听

[zk: hadoop1(CONNECTED) 5] get /spark watch

cZxid = 0x500000001f

ctime = Sun Oct 02 19:46:06 PDT 2016

mZxid = 0x500000001f

mtime = Sun Oct 02 19:46:06 PDT 2016

pZxid = 0x5000000023

cversion = 2

dataVersion = 0

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 0

numChildren = 2

 

1-5)、查看数据版本修改的问题

[zk: localhost:2181(CONNECTED) 17] set /testzookeeper "xiaowang"

cZxid = 0x2f00000007

ctime = Thu Nov 24 06:16:33 PST 2016

mZxid = 0x2f0000000a

mtime = Thu Nov 24 06:22:09 PST 2016

pZxid = 0x2f00000007

cversion = 0

// 数据的版本

dataVersion = 1

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 10

numChildren = 0

1-6)、wacth的使用

Watcher(事件监听器),是ZooKeeper中一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去。该机制是ZooKeeper实现分布式协调服务的重要特性。

A)、原始数据

[zk: localhost:2181(CONNECTED) 18] get /testzookeeper watch

"xiaowang"

cZxid = 0x2f00000007

ctime = Thu Nov 24 06:16:33 PST 2016

mZxid = 0x2f0000000a

mtime = Thu Nov 24 06:22:09 PST 2016

pZxid = 0x2f00000007

cversion = 0

dataVersion = 1

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 10

numChildren = 0

[zk: localhost:2181(CONNECTED) 19]

 

B)、修改数据

[zk: localhost:2181(CONNECTED) 3] set /testzookeeper "xiaoming"

cZxid = 0x2f00000007

ctime = Thu Nov 24 06:16:33 PST 2016

mZxid = 0x2f0000000b

mtime = Thu Nov 24 06:28:02 PST 2016

pZxid = 0x2f00000007

cversion = 0

dataVersion = 2

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 10

numChildren = 0

 

C)、查看修改的事件

[zk: localhost:2181(CONNECTED) 18] get /testzookeeper watch

"xiaowang"

cZxid = 0x2f00000007

ctime = Thu Nov 24 06:16:33 PST 2016

mZxid = 0x2f0000000a

mtime = Thu Nov 24 06:22:09 PST 2016

pZxid = 0x2f00000007

cversion = 0

dataVersion = 1

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 10

numChildren = 0

[zk: localhost:2181(CONNECTED) 19]

WATCHER::

 

WatchedEvent state:SyncConnected type:NodeDataChanged path:/testzookeeper

 

对于监听的事件只监听一次

 

1-7)、watch 过程详解

  1. 、当客户端请求时并添加了wacth的时候
  2. 、会开启listen(监听)  thread线程来监听事件,底层实现的也是scoker进行通信的
  3. 、在集群中收到监听的IP以及端口的信息,并这这些信息传递给其他的机器上、

 

1-8)、ACL 概念

ZooKeeper采用ACL(Access Control Lists)策略来进行权限控制。ZooKeeper定义了如下5种权限。

 

CREATE: 创建子节点的权限。

READ: 获取节点数据和子节点列表的权限。

WRITE:更新节点数据的权限。

DELETE: 删除子节点的权限。

ADMIN: 设置节点ACL的权限。

 

注意:CREATE 和 DELETE 都是针对子节点的权限控制。

 

1-9)、查看当前的ZNode的节点数

[zk: localhost:2181(CONNECTED) 1]  ls  /   

[testZookeeper, hadoop-ha, hbase, admin, zookeeper, consumers, config, spark, yarn-leader-election, brokers, controller_epoch]

1-10)、删除一个ZNode 节点

[zk: localhost:2181(CONNECTED) 2] delete /admin

 

1-11)、删除一个Child znode

[zk: localhost:2181(CONNECTED) 3] ls /admin

[delete_topics]

[zk: localhost:2181(CONNECTED) 4] delete /admin/delete_topics

1-12)、递归删除ZNode

[zk: localhost:2181(CONNECTED) 4] rmr /admin

B)、Windows端链接

链接工具:链接:http://pan.baidu.com/s/1eSgEfPg 密码:g1bb 无法下载请联系作者。

 

进入到ZooInspector的build的目录会看到一个JAR包,执行以下命令

 

 

 

 

之前有保存的信息,所以会显示的多一点。

 

1-8)、查看zookeeper版本的控制

[root@hadoop1 /]# cd /usr/local/zookeeper-3.4.5/conf/version-2

[root@hadoop1 version-2]# ls

acceptedEpoch  log.200000001 log.2d00000001  log.500000001        snapshot.16000002b3  snapshot.1800000002  snapshot.1c0000001d

currentEpoch   log.2700000045  log.300000054   snapshot.1300000300  snapshot.1700000056  snapshot.1900000017  snapshot.2c00000098

 

acceptedEpoch: 在集群中都被认可的元数据

currentEpoch:当前机器的元数据

 

Snapshot:参考物件的版本

Zookeeper 内存数据库

1-1)、ZKDatabase 内存数据库的实质载体

搜索zkDatabase的类即可查看初始化的信息

 

1-2)、详解DataTree

DateTree 是zookeeper中的核心代码,代表了内存中核心的数据,通过下面可以看出dataTree维护了两个并行的数据结构,一个是hash表,一个是数据节点的构成的树,所有的访问都是通过哈希表来映射查找数据的,如果数据已经加载到磁盘上才会去遍历。

 

Nodes : 用于快速查找数据节点的并发哈希表。

Key:数据节点路径

Value:DataNode

 

 

这个数据结构是专门用来存放临时节点的,方便实时访问和及时清理

 

1-3)、DataNode 类的属性

 

 

 

parent:父节点信息

data[]:数据信息

acl:访问控制信息

stat:持久化到磁盘上的统计信息

children:子节点信息

Zookeeper 的客户端的API的使用

1 -1 ) 、基本方法

功能         描述

create         在本地目录树中创建一个节点

delete         删除一个节点

exists         测试本地是否存在目标节点

get/set data     从目标节点上读取?/?写数据

get/set ACL     获取?/?设置目标节点访问控制列表信息

get children     检索一个子节点上的列表

sync             等待要被传送的数据

1-2 )、 增删改查znode数据

先在编辑器中导入zookeeper-3.4.5\lib的JAR包,还有一个是zookeeper根目录下的zookeeper-3.4.5.jar

 

package zookeeperTest;

 

import java.io.IOException;

 

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.KeeperException;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooDefs.Ids;

import org.apache.zookeeper.ZooKeeper;

 

/**

 * zookeeper的基本的操作

 */

public class ZookeeperSimple {

// 会话超时时间,设置为与系统默认时间一致

private static final int SESSION_TIMEOUT = 30000;

// 创建 ZooKeeper 实例

ZooKeeper zk;

// 创建 Watcher 实例

Watcher wh = new Watcher() {

public void process(org.apache.zookeeper.WatchedEvent event) {

System.out.println(event.toString());

}

};

 

/**

 * 初始化zookeeper的操作

 */

private void createZKInstance() throws IOException {

zk = new ZooKeeper("hadoop1:2181", ZookeeperSimple.SESSION_TIMEOUT,

this.wh);

}

 

/**

 * zookeeper的基本的操作

 *

 * @throws IOException

 * @throws InterruptedException

 * @throws KeeperException

 */

private void ZKOperations() throws IOException, InterruptedException,

KeeperException {

// 创建节点

zk.create("/testZookeeper", "mytestZookeeper".getBytes(),

Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

// 删除节点

System.out

.println(new String(zk.getData("/testZookeeper", false, null)));

// 修改节点

zk.setData("/testZookeeper", "zookeeperModify".getBytes(), -1);

// 获取修改节点的状态

System.out

.println(new String(zk.getData("/testZookeeper", false, null)));

// 删除节点

zk.delete("/testZookeeper", -1);

// 查看删除节点的状态

System.out.println("节点状态:" + zk.exists("/testZookeeper", false));

}

 

/**

 * 关闭zookeeper的链接

 */

private void ZKClose() throws InterruptedException {

zk.close();

}

 

public static void main(String[] args) throws IOException,

InterruptedException, KeeperException {

ZookeeperSimple dm = new ZookeeperSimple();

dm.createZKInstance();

dm.ZKOperations();

dm.ZKClose();

}

}

 

1-3)、zookeeper服务器上下线动态感知

A)、概述

    在分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线。

B)、设计思路

需求让客户端动态感知在线的服务器的运行状态。

1-1)、服务器端

获取链接 ( process )

利用zookeeper链接注册服务器的信息

启动业务的逻辑实现

服务器端不需要实现监听

1-2)、客户端

获取链接(process)

获取server上的子节点的信息,并从中获服务器的信息列表

业务启动线程

C)、代码实现

1-1)、服务端代码实现

package zookeeperPerception;

 

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooDefs.Ids;

import org.apache.zookeeper.ZooKeeper;

 

/**

 * 动态感知Server

 */

public class ZookeeperServer {

private String groupNode = "sgroup";

private String subNode = "sub";

 

/**

 * 连接zookeeper

 *

 * @param address

 *            server的地址

 */

public void connectZookeeper(String address) throws Exception {

ZooKeeper zk = new ZooKeeper("hadoop1:2181,hadoop2:2181,hadoop3:2181",

5000, new Watcher() {

public void process(WatchedEvent event) {

// 不做处理

}

});

// 在"/sgroup"下创建子节点

// 子节点的类型设置为EPHEMERAL_SEQUENTIAL, 表明这是一个临时节点, 且在子节点的名称后面加上一串数字后缀

// 将server的地址数据关联到新创建的子节点上

String createdPath = zk.create("/" + groupNode,

address.getBytes("utf-8"), Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

System.out.println("create: " + createdPath);

}

 

/**

 * server的工作逻辑写在这个方法中 此处不做任何处理, 只让server sleep

 */

public void handle() throws InterruptedException {

Thread.sleep(Long.MAX_VALUE);

}

 

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

ZookeeperServer as = new ZookeeperServer();

as.connectZookeeper("server1");

as.handle();

}

}

 

1-2)、客户端代码实现

package zookeeperPerception;

 

import java.util.ArrayList;

import java.util.List;

 

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.Watcher.Event.EventType;

import org.apache.zookeeper.ZooKeeper;

import org.apache.zookeeper.data.Stat;

 

/**

 * 动态感知Client

 */

public class ZookeeperClient {

private String groupNode = "sgroup";

private ZooKeeper zk;

private Stat stat = new Stat();

private volatile List<String> serverList;

 

/**

 * 连接zookeeper

 */

public void connectZookeeper() throws Exception {

zk = new ZooKeeper("hadoop1:2181,hadoop2:2181,hadoop3:2181", 5000,

new Watcher() {

public void process(WatchedEvent event) {

// 如果发生了"/sgroup"节点下的子节点变化事件, 更新server列表, 并重新注册监听

if (event.getType() == EventType.NodeChildrenChanged

&& ("/" + groupNode).equals(event.getPath())) {

try {

updateServerList();

} catch (Exception e) {

e.printStackTrace();

}

}

}

});

updateServerList();

}

 

/**

 * 更新server列表

 */

private void updateServerList() throws Exception {

List<String> newServerList = new ArrayList<String>();

// 获取并监听groupNode的子节点变化

// watch参数为true, 表示监听子节点变化事件.

// 每次都需要重新注册监听, 因为一次注册, 只能监听一次事件, 如果还想继续保持监听, 必须重新注册

List<String> subList = zk.getChildren("/" + "sgroup0000000039", true);

for (String subNode : subList) {

// 获取每个子节点下关联的server地址

byte[] data = zk.getData("/" + "sgroup0000000039", false, stat);

newServerList.add(new String(data, "utf-8"));

}

 

// 替换server列表

serverList = newServerList;

System.out.println("server list updated: " + serverList.size());

}

 

/**

 * client的工作逻辑写在这个方法中 此处不做任何处理, 只让client sleep

 */

public void handle() throws InterruptedException {

Thread.sleep(Long.MAX_VALUE);

}

 

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

ZookeeperClient ac = new ZookeeperClient();

ac.connectZookeeper();

ac.handle();

}

}

 

 

D)、Alibaba实现动态感知的代码实现

https://github.com/alibaba/taokeeper/tree/master/taokeeper-research

 

1-4) 、分布式共享锁

A)、概述

    在我们自己的分布式业务系统中,可能会存在某种资源,需要被整个系统的各台服务器共享访问,但是只允许一台服务器同时访问

 

B)、设计思路

     先查看所有机器上的锁,查看自己的锁是不是最小的,如果是最小的则会访问最大的那把锁,并把数据同步下来,访问完后把自己的锁删掉后,再会重新注册一把新锁。

 

C)、代码实现

package lock;

 

import java.util.Collections;

import java.util.List;

import java.util.Random;

 

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.Watcher.Event.EventType;

import org.apache.zookeeper.ZooDefs.Ids;

import org.apache.zookeeper.ZooKeeper;

 

public class DistributedClientLock {

 

// 会话超时

private static final int SESSION_TIMEOUT = 2000;

// zookeeper集群地址

private String hosts = "hadoop1:2181,hadoop2:2181,hadoop3:2181";

private String groupNode = "locks";

private String subNode = "sub";

private boolean haveLock = false;

 

private ZooKeeper zk;

// 记录自己创建的子节点路径

private volatile String thisPath;

 

/**

 * 连接zookeeper

 */

public void connectZookeeper() throws Exception {

zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {

public void process(WatchedEvent event) {

try {

// 判断事件类型,此处只处理子节点变化事件

if (event.getType() == EventType.NodeChildrenChanged

&& event.getPath().equals("/" + groupNode)) {

// 获取子节点,并对父节点进行监听

List<String> childrenNodes = zk.getChildren("/"

+ groupNode, true);

String thisNode = thisPath

.substring(("/" + groupNode + "/").length());

// 去比较是否自己是最小id

Collections.sort(childrenNodes);

if (childrenNodes.indexOf(thisNode) == 0) {

// 访问共享资源处理业务,并且在处理完成之后删除锁

doSomething();

// 重新注册一把新的锁

thisPath = zk.create("/" + groupNode + "/"

+ subNode, null, Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

});

 

// 1、程序一进来就先注册一把锁到zk

thisPath = zk.create("/" + groupNode + "/" + subNode, null,

Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

 

// wait一小会,便于观察

Thread.sleep(new Random().nextInt(1000));

 

// 从zk的锁父目录下,获取所有子节点,并且注册对父节点的监听

List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

 

// 如果争抢资源的程序就只有自己,则可以直接去访问共享资源

if (childrenNodes.size() == 1) {

doSomething();

thisPath = zk.create("/" + groupNode + "/" + subNode, null,

Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

}

}

 

/**

 * 处理业务逻辑,并且在最后释放锁

 */

private void doSomething() throws Exception {

try {

System.out.println("gain lock: " + thisPath);

Thread.sleep(2000);

// do something

} finally {

System.out.println("finished: " + thisPath);

//

// 访问完毕后,需要手动去删除之前的锁节点,-1代表删除所有的版本的  记录信息。

zk.delete(this.thisPath, -1);

}

}

 

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

DistributedClientLock dl = new DistributedClientLock();

dl.connectZookeeper();

Thread.sleep(Long.MAX_VALUE);

}

}

Node-zk-browser 安装

软件下载:链接:http://pan.baidu.com/s/1c2zf03Y 密码:4od0 如果无法下载,请联系作者。

A)、准备环境,nodes需要gcc环境

[root@hadoop1 /]# yum -y install gcc make gcc-c++ openssl-devel

B)、安装 nodes 

[root@hadoop1 /]# wget http://nodejs.org/dist/v0.10.26/node-v0.10.26.tar.gz

C)、解压文件

[root@hadoop1 /]#tar -zxvf  node-v0.10.26.tar.gz

D)、编辑文件

[root@hadoop1 node-v0.10.26]# make && make install

E)、查看node版本

[root@hadoop1 node-v0.10.26]# node -v

v0.10.26

F)、下载node-zk-browser

[root@hadoop1 zookeeperWeb]# wget https://github.com/killme2008/node-zk-browser/archive/master.zip

G)、安装node-zk-browser

[root@hadoop2 node-zk-browser-master]# npm install -d

H)、安装zk的版本

[root@hadoop1 node-zk-browser-master]# npm install zookeeper

I)、修改配置文件

[root@hadoop1 node-zk-browser-master]# vi app.js

找到以下配置修改

var host = process.env.ZK_HOST || 'hadoop1:2181,hadoop2:2181,hadoop3:2181';

[root@hadoop2 node-zk-browser-master]# vi user.json

修改一下配置

{

  "admin" : "admin"

}

J)、启动服务

[root@hadoop1  node-zk-browser-master]# ./start.sh

L)、界面展示

查看运行的Log发现运行的端口是3000

[root@hadoop1 logs]# vi node-zk-browser.log

********

Express server listening on port 3000

Caught exception: Error: listen EADDRINUSE

zk session established, id=15b4374b7a60002

 

http://hadoop1:3000

可以点击Signin登录,用户名与密码都是admin

猜你喜欢

转载自blog.csdn.net/xfg0218/article/details/82317148