一、什么是Zookeeper、
zookeeper相当于是一个“数据库”,用来存放信息;是一个分布式协调的框架,实现HA的功能;是一个分布式锁的管理框架,实现秒杀。
二、提供的功能
1、选举功能
2、数据同步(端口:2888)、选举机制(通过投票的方式、端口:3888)
3、监听机制
4、分布式锁
其中,选举机制与数据同步,在集群中就能体现出来。
2888是集群之间信息同步用的
3888是自动选举用的
2181是给提供客户端服务用的
三、搭建单节点zookeeper(运行standalone)
1、解压:tar -zxvf zookeeper包名 解压到 /usr/local/zookeeper
2、设置环境变量 vi ~/.bash_profile (~/表示用户目录 ./ 当前目录 …/ 上级目录)
ZOOKEEPER_HOME=/usr/local/zookeeper/zookeeper-3.4.10
export ZOOKEEPER_HOME
PATH=$ZOOKEEPER_HOME/bin:$PATH
export PATH
#这一行不加可能会拒绝运行
export ZOO_LOG_DIR=/usr/local/zookeeper/zookeeper-3.4.10/log
3、生效环境变量:
source ~/.bash_profile
之后可以控制台 输入:zk 然后按两次tab键 ,进行测试环境变量是否弄好
4、核心配置文件:
usr/local/zookeeper/conf/zoo.cfg 默认是没有zoo.cfg,我们需要拷贝一下zoo_sample.cfg
执行命令 :
cp zoo_sample.cfg zoo.cfg
5、配置zoo.cfg
5.1修改dataDir路径,默认是Linux的/temp目录,但是当Linux重新启动时,这个目录里的东西会清空的
dataDir=/usr/local/zookeeper/zookeeper-3.4.10/temp
5.2 指定zookeeper中的节点
server.1=IP地址:2888:3888
2888是集群之间信息同步用的
3888是自动选举用的
2181是给提供客户端服务用的
5.3 在dataDir=/usr/local/zookeeper/zookeeper-3.4.10/temp 创建一个文件 :myid
并且在第一行输入 1 , 这个1对应server.1=IP地址:2888:3888中的1
测试:
zkServer.sh start
zkServer.sh status
standalone 是单节点的模式
zkServer.sh stop 停止服务
四、搭建集群
1、配置环境变量,和单节点一样,只不过每个主机上都要配置
2、核心配置文件:
usr/local/zookeeper/conf/zoo.cfg 默认是没有zoo.cfg,我们需要拷贝一下zoo_sample.cfg
执行命令 :
cp zoo_sample.cfg zoo.cfg
3、配置zoo.cfg
3.1修改dataDir路径,默认是Linux的/temp目录,但是当Linux重新启动时,这个目录里的东西会清空的
dataDir=/usr/local/zookeeper/zookeeper-3.4.10/temp
3.2 指定zookeeper中的节点
server.1=IP地址1:2888:3888
server.2=IP地址2:2888:3888
server.3=IP地址3:2888:3888
3.3 在dataDir=/usr/local/zookeeper/zookeeper-3.4.10/temp 创建一个文件 :myid
并且在第一行输入 1 , 这个1对应server.1=IP地址:2888:3888中的1
3.4、在安装好zookeeper目录后,复制到其他的节点
scp -r zookeeper-3.1.10/ root@IP地址2:/usr/local/zookeeper
scp -r zookeeper-3.1.10/ root@IP地址3:/usr/local/zookeeper
3.5、修改IP地址2余IP地址3上的myid文件。
五、操作ZooKeeper
1、JAVA API 操作zookeeper
创建节点主要分为三种情况(从字面意思理解):
- 持久化节点Persistent
- 顺序节点 SEQUENTIAL
- 临时节点 ephemeral,当服务退出时,创建的节点就会自动删除。
public static void main(String[] args) throws Exception {
//定义重试策略
RetryPolicy policy = new ExponentialBackoffRetry(1000 , 10);
//创建节点
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("192.168.92.111:2181")
.retryPolicy(policy)
.build();
//启动client
client.start();
//进行操作,创建节点
// 节点持久化节点
client.create().forPath("/mynode1");
// 持久化顺序节点
client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/nodePersist-");
client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/nodePersist-");
client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/nodePersist-");
client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/nodePersist-");
//临时节点
client.create().withMode(CreateMode.EPHEMERAL).forPath("/ephemeral");
// 临时节点 順序节点 EPHEMERAL 汉语:瞬时的
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/node-");
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/node-");
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/node-");
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/node-");
Thread.sleep(10000);
//关闭client
client.close();
}
2、zookeeper监听机制
zookeeper的监听机制通俗的说就是,当监听的目录发生任何的变化,zookeeper就会启动对应的措施。Java代码实现如下:
public static void main(String[] args) throws Exception {
RetryPolicy policy = new ExponentialBackoffRetry(1000,10);
//获得连接
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("192.168.92.111:2181")
.retryPolicy(policy).build();
//启动连接
client.start();
//定义目录
client.create().forPath("/parentNode");
//要想监听这个目录,是不是首先拿到这个子目录的缓存目录
PathChildrenCache pathChildrenCache = new PathChildrenCache(client,"/parentNode",true);
//拿到缓存目录后,去监听器,添加监听器
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener(){
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()){
case CHILD_ADDED:
System.out.println("添加子目录 "+ event.getData().getPath());
break;
case CHILD_UPDATED:
System.out.println("修改数据"+ event.getData().getPath());
break;
case CHILD_REMOVED:
System.out.println("删除数据"+ event.getData().getPath());
break;
default:
break;
}
}
});
//启动监听器
pathChildrenCache.start();
//添加子目录
Thread.sleep(1000);
client.create().forPath("/parentNode/children");
//修改子目录
Thread.sleep(1000);
client.setData().forPath("/parentNode/children","hello world".getBytes());
//删除子目录
Thread.sleep(1000);
client.delete().forPath("/parentNode/children");
//关闭连接
client.close();
}
3、升入理解监听机制
目标:理解zookeeper 监听机制在主从架构中的作用。以Hbase进行举例。
为了解决单点故障问题,我们启动多台主节点进行启动,当启动集群的时候,主节点就会在zookeeper的对应目录下面创建一个临时节点。加入主节点进行荡机,是不是对应的临时节点就会删除,这时会触发zookeeper的监听机制,进而执行对应的操作,进行选举操作。
六、zookeeper的分布式锁
在请求资源的时候,我们先去zookeeper取一个锁,获得访问权限。请求锁的时候,用的临时节点!这一点要注意一下。
JAVA案例代码实现如下
public class TestZookeeperLock {
//定义一个资源
private static int NUMBER =10;
//业务方法,进行取资源
public static void doBussiness(){
System.out.println("************开始执行业务方法!************");
System.out.println("当前资源:"+ NUMBER);
NUMBER--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("************结束调用!************");
}
public static void main(String[] args) {
RetryPolicy policy = new ExponentialBackoffRetry(1000 ,10);
//获得连接
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("192.168.92.111:2181")
.retryPolicy(policy)
.build();
client.start();
//定义锁 (节点、目录)
final InterProcessMutex lock = new InterProcessMutex(client,"/mylock");
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
public void run() {
//获取锁
try {
lock.acquire();
doBussiness();
} catch (Exception e) {
e.printStackTrace();
}
//释放锁
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}
注意:当获取这把锁的时候,会在/mylock创建临时信息,释放锁的时候,/mylock下面的临时信息就会清空。也就是说,当/mylock下为空的时候,才可以去抢占这把锁。