zookeeper
2016-06-19 21:39
387 查看
zookeeper
zookeeper是一个为分布式应用提供一致性服务的软件
1.zookeeper的数据模型
其数据模型有些像操作系统的文件结构,结构如下图所示
(1)每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识,如/SERVER2节点的标识就为/APP3/SERVER2
(2)znode可以有子znode,并且znode里可以存数据,但是EPHEMERAL类型的节点不能有子节点
(3)znode中的数据可以有多个版本,比如某一个路径下存有多个数据版本,那么查询这个路径下的数据就需要带上版本号。
(4)znode可以是临时节点,一旦创建这个 znode 的客户端与服务器失去联系,这个 znode 也将自动删除,Zookeeper 的客户端和服务器通信采用长连接方式,
每个客户端和服务器通过心跳来保持连接,这个连接状态称为 session,如果 znode 是临时节点,这个 session 失效,znode 也就删除了
(5)znode的目录名可以自动编号,如 App1 已经存在,再创建的话,将会自动命名为 App2
(6)znode可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,
通过这个特性可以实现的功能包括配置的集中管理,集群管理,分布式锁等等。
2.ZooKeeper节点类型
持久节点(PERSISTENT)、临时节点(EPHEMERAL),以及时序节点(SEQUENTIAL),具体在节点创建过程中,一般是组合使用,可以生成以下4种节点类型。
持久节点(PERSISTENT)
所谓持久节点,是指在节点创建后,就一直存在,直到有删除操作来主动清除这个节点——不会因为创建该节点的客户端会话失效而消失。
持久顺序节点(PERSISTENT_SEQUENTIAL)
这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名。这个数字后缀的范围是整型的最大值。
临时节点(EPHEMERAL)
和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。
注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。
临时顺序节点(EPHEMERAL_SEQUENTIAL)
可以用来实现分布式锁
3.单机
------------------------------
安装/配置:
conf目录
复制zoo_sample.cfg文件,名称改为zoo.cfg,zookeeper启动时默认的配置文件名
参数说明:
tickTime: zookeeper中使用的基本时间单位, 毫秒值.
dataDir: 数据目录. 可以是任意目录.
dataLogDir: log目录, 同样可以是任意目录. 如果没有设置该参数, 将使用和dataDir相同的设置.
clientPort: 监听client连接的端口号.
启动(windows下):
bin目录
server:双击zkServer.cmd
client:zkCli.cmd
clent命令:
ls(查看当前节点的子节点),
ls2(查看当前子节点并能看到当前节点的日期、版本等信息) ,
create(创建一个节点) ,
get(得到一个节点,包含数据和更新次数等信息),
set(修改节点)
delete(删除一个节点)
4.java api
Zookeeper的使用主要是通过创建其jar包下的Zookeeper实例,并且调用其接口方法进行的,主要的操作就是对znode的增删改查操作,监听znode的变化以及处理。
maven引入jar包
注意:ZooKeeper创建连接时是异步的,可以使用CountDownLatch来保证创建好连接再使用(如下文的例子),
这里为方便测试,new ZooKeeper()创建连接后,Thread.sleep(2000)sleep一会再进行增删改查操作,否则可能报错
org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for
5.伪集群zk windows单机伪集群
zk windows单机伪集群
1.复制三份zk:
zookeeper-3.4.5-1
zookeeper-3.4.5-2
zookeeper-3.4.5-3
2.修改配置文件conf/zoo.cfg:
#数据文件和日志文件路径
dataDir=E:/testZk/data3 #(data1、data2、data3)
dataLogDir=E:/testZk/log3 #(log1、log2、log3)
#修改端口,三个分别是:
clientPort=3181
clientPort=3182
clientPort=3183
#集群服务器配置(添加)
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
server.A=B:C:D:
A是一个数字,表示这个是第几号服务器;
B是这个服务器的ip地址;
C表示的是这个服务器与集群中的Leader服务器交换信息的端口;
D表示的是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,
而这个端口就是用来执行选举时服务器相互通信的端口。
如果是伪集群的配置方式,由于B都是一样,所以不同的Zookeeper实例通信端口号不能一样,所以要给它们分配不同的端口号。
3.创建myid文件
在dataDir目录下创建一个myid文件,然后分别在myid文件中写入zoo.cfg文件的server.A中A的数值,在不同机器上的该文件中填写相应的值。
4.启动、测试
分别启动三个zk:
bin/zkServer.cmd 直接双击就行;
注意:cmd启动的时候,
zkServer.cmd 不要后面的“start”,否则会报错:
Invalid arguments, exiting abnormally
java.lang.NumberFormatException: For input string:
注意:启动前两个zk的时候,会报错,因为是集群,第三个还没启动,前两个会试着与第三个通讯,
都起来了就好了。
6.应用场景
配置管理
集群管理
分布式锁
参考:http://blackproof.iteye.com/blog/2039040
***********************************************************************************************************************
同步化的zk连接
zk节点数据为redis cluster的host port信息,redis增减机器时,会修改zk节点数据,
zk节点会通过DataWatcher修改ZKConnection.REDIS_HOST_LIST,
redis cluster创建redis连接时,连接url是ZKConnection.REDIS_HOST_LIST
zookeeper是一个为分布式应用提供一致性服务的软件
1.zookeeper的数据模型
其数据模型有些像操作系统的文件结构,结构如下图所示
(1)每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识,如/SERVER2节点的标识就为/APP3/SERVER2
(2)znode可以有子znode,并且znode里可以存数据,但是EPHEMERAL类型的节点不能有子节点
(3)znode中的数据可以有多个版本,比如某一个路径下存有多个数据版本,那么查询这个路径下的数据就需要带上版本号。
(4)znode可以是临时节点,一旦创建这个 znode 的客户端与服务器失去联系,这个 znode 也将自动删除,Zookeeper 的客户端和服务器通信采用长连接方式,
每个客户端和服务器通过心跳来保持连接,这个连接状态称为 session,如果 znode 是临时节点,这个 session 失效,znode 也就删除了
(5)znode的目录名可以自动编号,如 App1 已经存在,再创建的话,将会自动命名为 App2
(6)znode可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,
通过这个特性可以实现的功能包括配置的集中管理,集群管理,分布式锁等等。
2.ZooKeeper节点类型
持久节点(PERSISTENT)、临时节点(EPHEMERAL),以及时序节点(SEQUENTIAL),具体在节点创建过程中,一般是组合使用,可以生成以下4种节点类型。
持久节点(PERSISTENT)
所谓持久节点,是指在节点创建后,就一直存在,直到有删除操作来主动清除这个节点——不会因为创建该节点的客户端会话失效而消失。
持久顺序节点(PERSISTENT_SEQUENTIAL)
这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名。这个数字后缀的范围是整型的最大值。
临时节点(EPHEMERAL)
和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。
注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。
临时顺序节点(EPHEMERAL_SEQUENTIAL)
可以用来实现分布式锁
3.单机
------------------------------
安装/配置:
conf目录
复制zoo_sample.cfg文件,名称改为zoo.cfg,zookeeper启动时默认的配置文件名
参数说明:
tickTime: zookeeper中使用的基本时间单位, 毫秒值.
dataDir: 数据目录. 可以是任意目录.
dataLogDir: log目录, 同样可以是任意目录. 如果没有设置该参数, 将使用和dataDir相同的设置.
clientPort: 监听client连接的端口号.
启动(windows下):
bin目录
server:双击zkServer.cmd
client:zkCli.cmd
clent命令:
ls(查看当前节点的子节点),
ls2(查看当前子节点并能看到当前节点的日期、版本等信息) ,
create(创建一个节点) ,
get(得到一个节点,包含数据和更新次数等信息),
set(修改节点)
delete(删除一个节点)
4.java api
Zookeeper的使用主要是通过创建其jar包下的Zookeeper实例,并且调用其接口方法进行的,主要的操作就是对znode的增删改查操作,监听znode的变化以及处理。
maven引入jar包
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.6</version> </dependency>
//创建一个Zookeeper实例,第一个参数为目标服务器地址和端口,第二个参数为Session超时时间,第三个为节点变化时的回调方法 ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 500000,new Watcher() { // 监控所有被触发的事件 public void process(WatchedEvent event) { //dosomething } }); //创建一个节点root,数据是roodata,不进行ACL权限控制,节点为永久性的(即客户端shutdown了也不会消失) zk.create("/root", "roodata".getBytes(),Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); //在root下面创建一个childone znode,数据为childone,不进行ACL权限控制,节点为永久性的 zk.create("/root/childone","childone".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); //取得/root节点下的子节点名称,返回List<String> zk.getChildren("/root",true); //取得/root/childone节点下的数据,返回byte[] zk.getData("/root/childone", true, null); //修改节点/root/childone下的数据,第三个参数为版本,如果是-1,那会无视被修改的数据版本,直接改掉 zk.setData("/root/childone","childonemodify".getBytes(), -1); //删除/root/childone这个节点,第二个参数为版本,-1的话直接删除,无视版本 zk.delete("/root/childone", -1); //关闭session zk.close();
注意:ZooKeeper创建连接时是异步的,可以使用CountDownLatch来保证创建好连接再使用(如下文的例子),
这里为方便测试,new ZooKeeper()创建连接后,Thread.sleep(2000)sleep一会再进行增删改查操作,否则可能报错
org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for
5.伪集群zk windows单机伪集群
zk windows单机伪集群
1.复制三份zk:
zookeeper-3.4.5-1
zookeeper-3.4.5-2
zookeeper-3.4.5-3
2.修改配置文件conf/zoo.cfg:
#数据文件和日志文件路径
dataDir=E:/testZk/data3 #(data1、data2、data3)
dataLogDir=E:/testZk/log3 #(log1、log2、log3)
#修改端口,三个分别是:
clientPort=3181
clientPort=3182
clientPort=3183
#集群服务器配置(添加)
server.1=127.0.0.1:2888:3888
server.2=127.0.0.1:2889:3889
server.3=127.0.0.1:2890:3890
server.A=B:C:D:
A是一个数字,表示这个是第几号服务器;
B是这个服务器的ip地址;
C表示的是这个服务器与集群中的Leader服务器交换信息的端口;
D表示的是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,
而这个端口就是用来执行选举时服务器相互通信的端口。
如果是伪集群的配置方式,由于B都是一样,所以不同的Zookeeper实例通信端口号不能一样,所以要给它们分配不同的端口号。
3.创建myid文件
在dataDir目录下创建一个myid文件,然后分别在myid文件中写入zoo.cfg文件的server.A中A的数值,在不同机器上的该文件中填写相应的值。
4.启动、测试
分别启动三个zk:
bin/zkServer.cmd 直接双击就行;
注意:cmd启动的时候,
zkServer.cmd 不要后面的“start”,否则会报错:
Invalid arguments, exiting abnormally
java.lang.NumberFormatException: For input string:
注意:启动前两个zk的时候,会报错,因为是集群,第三个还没启动,前两个会试着与第三个通讯,
都起来了就好了。
public static void main(String[] args) throws Exception { ZooKeeper zk = new ZooKeeper("127.0.0.1:3181,127.0.0.1:3182,127.0.0.1:3183", 30000, null); Thread.sleep(3000); zk.create("/testccc", "2016-11-04 15:16:06".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); byte[] data = zk.getData("/testccc", null, null); System.out.println(new String(data)); zk.close(); }
6.应用场景
配置管理
集群管理
分布式锁
参考:http://blackproof.iteye.com/blog/2039040
***********************************************************************************************************************
同步化的zk连接
zk节点数据为redis cluster的host port信息,redis增减机器时,会修改zk节点数据,
zk节点会通过DataWatcher修改ZKConnection.REDIS_HOST_LIST,
redis cluster创建redis连接时,连接url是ZKConnection.REDIS_HOST_LIST
import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.ZooKeeper.States; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 同步化的zk连接 */ public class ZKConnection { private static final Logger LOG = LoggerFactory.getLogger(ZKConnection.class); private static volatile String REDIS_HOST_LIST_INIT = "localhost";//zk zk_node_pathname节点里的初始化数据 private static volatile String REDIS_HOST_LIST = "";//zk zk_node_pathname节点里的数据 private static ZooKeeper zk = null; public static final String zk_node_pathname = "/redis";//zk节点路径名 public static final String zk_url = "localhost";//zk hostinfo //test public static void main(String[] args) throws Exception { init(); ZooKeeper zk = ZKConnection.zk(); byte[] data = zk.getData(zk_node_pathname, null, null); System.out.println("getData:" + new String(data)); System.out.println("host_list:" + REDIS_HOST_LIST); } //项目启动时调用,初始化 public static void init() throws Exception { zk = ZKConnection.zk(); if(zk.exists(zk_node_pathname, false) == null){ zk.create(zk_node_pathname, REDIS_HOST_LIST_INIT.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } byte[] data = zk.getData(zk_node_pathname, new DataWatcher(), null); //设置redis的配置 setREDIS_HOST_LIST(new String(data)); } public static synchronized ZooKeeper zk() { if (zk==null || !zk.getState().isConnected()) { try { createConnection();//创建zk连接 } catch (Exception e) { return null; } } return zk; } /** * 创建zk连接 * @throws Exception */ private static void createConnection() throws Exception { //ZooKeeper创建连接时是异步的,这里使用CountDownLatch计数器保证获取到连接 CountDownLatch connectedLatch = new CountDownLatch(1); Watcher watcher = new ConnectedWatcher(connectedLatch); zk = new ZooKeeper(zk_url, 60000, watcher); //String auth = "zk_username:zk_password"; //zk.addAuthInfo("digest", auth.getBytes()); if(States.CONNECTING == zk.getState()){ connectedLatch.await(); } } //两个Watcher //Connected(zk连接) Watcher static class ConnectedWatcher implements Watcher { private CountDownLatch connectedLatch; ConnectedWatcher(CountDownLatch connectedLatch) { this.connectedLatch = connectedLatch; } @Override public void process(WatchedEvent event) { if (event.getState() == KeeperState.SyncConnected) { connectedLatch.countDown();//计数器减一 } else if (event.getState() == KeeperState.Expired) { // 处理断线重连问题 if(zk != null){ try { zk.close(); } catch (InterruptedException e) { LOG.error("Can't close the expired connection!", e); } } LOG.info("*******Expired reReloading********"); try { init(); } catch (Exception e) { LOG.error(e.getMessage()); } } } } //Data(节点值变化) Watcher static class DataWatcher implements Watcher { private Logger LOG = LoggerFactory.getLogger(DataWatcher.class); @Override public void process(WatchedEvent event) { try { if (event.getType() == Event.EventType.NodeDataChanged) { //<strong>this:Watcher通知是一次性的,当一次数据修改,通知客户端,客户端再次注册watch</strong> byte[] data = ZKConnection.zk().getData(event.getPath(), this, null); if (data!=null && data.length>0) { String result = new String(data); ZKConnection.setREDIS_HOST_LIST(result); LOG.info("Boot watcher has get the json: " + result); } } } catch (Exception e) { LOG.error(e.getMessage()); } } } public static void setREDIS_HOST_LIST(String redis_host_list){ synchronized (REDIS_HOST_LIST){ REDIS_HOST_LIST = redis_host_list; } } public static String getREDIS_HostList(){ return REDIS_HOST_LIST; } }
相关文章推荐
- Shell脚本实现自动安装zookeeper
- 基于Zookeeper的使用详解
- mesos + marathon + docker部署
- 基于zk的配置管理
- 搭建分布式架构4--ZooKeeper注册中心安装
- 搭建分布式架构5--ZooKeeper 集群的安装 3ff0
- Zookeeper注册中心安装
- SolrCloud4.9+zookeeper在CentOS上的搭建与安装
- 基于外部ZooKeeper的GlusterFS作为分布式文件系统的完全分布式HBase集群安装指南
- Storm集群的搭建
- Zookeeper配置项说明
- redis集群搭建
- 安装 zookeeper PHP 扩展
- 大数据实验室(大数据基础培训)——Zookeeper的安装、配置及基础使用
- 使用 RMI + ZooKeeper 实现远程调用框架
- 轻量级分布式 RPC 框架
- 整合Kafka到Spark Streaming——代码示例和挑战
- HBase 系统架构
- 使用zookeeper实现分布式共享锁
- 将Zookeeper集成到你的应用中