一、集群自启动脚本

  1.关闭zk

[root@localhost bin]# jps
Jps
QuorumPeerMain
[root@localhost bin]# kill -

  //kill或者stop都是可以的

  2.远程执行命令

[root@localhost bin]# ssh 192.168.137.138 /opt/zookeeper/zookeeper-3.4./bin/zkServer.sh start
root@192.168.137.138's password:
JMX enabled by default
Using config: /opt/zookeeper/zookeeper-3.4./bin/../conf/zoo.cfg
Starting zookeeper ... /opt/zookeeper/zookeeper-3.4./bin/zkServer.sh: 第 行:[: /tmp/zookeeper: 期待二元表达式
STARTED

  出现以上中文的地方只需要修改一下zoo.cfg,把多余的配置注释即可!

  当然,这样还是无法启动!因为ssh过去是以一个bash的方式过去的(不会执行/etc/profile,而正常登录是会执行的,也可以打开相应的脚本进行查看),也就是PATH不在了,导致JAVA_HOME等找不到了!

  EXPORT所定义的变量对自己所在的shell以及子shell生效

  这里就需要用到之前说到的source命令了:https://www.cnblogs.com/pkufork/p/linux_source.html

ssh 192.168.137.138 "source /etc/profile&&/opt/zookeeper/zookeeper-3.4.5/bin/zkServer.sh start"

  //如果不使用引号,将会以空格作为命令的分割!

  3.配置免密登录

  在其中一台机器上(这里是192.168.137.128)

ssh-keygen

  //之后enter即可

ssh-copy-id 192.168.137.128
ssh-copy-id 192.168.137.138
ssh-copy-id 192.168.137.148

  4.一键启动脚本

cd /root
mkdir bin
cd bin
vim startZK.sh
#!/bin/bash
SERVERS="192.168.137.128 192.168.137.138 192.168.137.148"
echo "start zk..."
for SERVER in $SERVERS
do
ssh $SERVER "source /etc/profile&&/opt/zookeeper/zookeeper-3.4.5/bin/zkServer.sh start"
done
chmod +x startZK.sh 

  这样,通过startZK.sh就能一键启动了!(/root/bin默认在PATH中了!)

二、zk的Java客户端

  相关API入门可以参考:https://www.cnblogs.com/ggjucheng/p/3370359.html

  第三方的客户端:zkclient参考:https://www.cnblogs.com/f1194361820/p/5575206.html

  1.引入maven依赖

        <dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>

  2.测试程序是否能通

public class SimpleZK {
// 设置连接字符串(可以用逗号隔开多个),失败时会自动尝试多个
private static final String coonectString = "192.168.137.128:2181,192.168.137.138:2181,192.168.137.148:2181";
// 超时时间
private static final int sessionTimeout = 2000;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
ZooKeeper zkClient = new ZooKeeper(coonectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
// 收到通知事件后的回调函数
System.out.println(watchedEvent.getType()+"---"+watchedEvent.getPath());
}
});
// zk的增删改查(这里使用最底层的原生操作,zkclient的待补充)
String node = zkClient.create("/app2", "hellozk".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } }

  完美:

    

  3.增删改查实例

package com.zk;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test; import java.io.IOException;
import java.util.List; /**
* 测试zk的Java客户端
*
* @author zcc ON 2018/1/17
**/
public class SimpleZK {
// 设置连接字符串(可以用逗号隔开多个),失败时会自动尝试多个
private static final String coonectString = "192.168.137.128:2181,192.168.137.138:2181,192.168.137.148:2181";
// 超时时间
private static final int sessionTimeout = 2000;
// 初始变量
ZooKeeper zkClient = null; /**
* 初始化方法
* @throws IOException
*/
@Before
public void init() throws IOException {
zkClient = new ZooKeeper(coonectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
// 收到通知事件后的回调函数
System.out.println(watchedEvent.getType()+"---"+watchedEvent.getPath());
// 开启循环监听(监听调用此方法,此方法又开启监听)
try {
zkClient.getChildren("/", true);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
} /**
* 创建
*/
public void testCreate() throws IOException, KeeperException, InterruptedException {
String node = zkClient.create("/app2", "hellozk".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
} /**
* 判断是否存在节点
* @throws KeeperException
* @throws InterruptedException
*/
public void testExists() throws KeeperException, InterruptedException {
// stat就是zk中那一堆数据(null则不存在)
Stat stat = zkClient.exists("/", false);
}
/**
* 取得子节点
*/
@Test
public void testGetChildren() throws KeeperException, InterruptedException {
List<String> children = zkClient.getChildren("/", true);
for (String child : children) {
System.out.println(child);
}
} /**
* 获取数据
*/
@Test
public void testGetData() throws KeeperException, InterruptedException {
// 分别是路径,是否监听以及状态版本(null就OK了,取最新)
byte[] data = zkClient.getData("/app2", false, null);
System.out.println(new String(data));
} /**
* 删除数据
*/
@Test
public void testDeleteZnode() throws KeeperException, InterruptedException {
// -1作为版本号参数表示删除所有版本(上层的API是不用传这些参数的)
zkClient.delete("/app2",-1);
} /**
* 修改数据
*/
public void testSetData() throws KeeperException, InterruptedException {
zkClient.setData("/app2", "hellozkCli".getBytes(), -1);
}
}

三、应用实例

  1.分布式服务器动态上下线感知(主节点HA)

  大致原理:

    

  大致流程比较清晰,当服务器启动时就去注册信息(例如给出主机与id等信息),给出一个短暂的带序列号的临时节点,这样服务器下线的时候节点便被删除了;而客户端则是去zk获取子节点信息,得到服务器列表并且注册监听,这样当有节点发生改变时变可以感知变化了!

  2.Java代码

    IDEA中给main方法添加参数,参考:http://blog.csdn.net/u013713294/article/details/53020293

  服务都端:

package com.zk;

import org.apache.zookeeper.*;

import java.io.IOException;

/**
* 分布式服务器动态感知——服务端
*
* @author zcc ON 2018/1/17
**/
public class DistributedServer { private static final String coonectString = "192.168.137.128:2181,192.168.137.138:2181,192.168.137.148:2181";
private static final int sessionTimeout = 2000;
private static final String parentNode = "/servers"; private ZooKeeper zk = null; /**
* 获得连接
* @throws IOException
*/
public void getConn() throws IOException {
zk = new ZooKeeper(coonectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
// 收到通知事件后的回调函数
System.out.println(watchedEvent.getType()+"---"+watchedEvent.getPath());
// 开启循环监听(监听调用此方法,此方法又开启监听)
try {
zk.getChildren("/", true);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
} /**
* 注册服务器
*/
public void registServer(String hostname) throws KeeperException, InterruptedException {
// 临时有编号的节点,可以重名
String znode = zk.create(parentNode + "/server", hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname+" is online..."+znode);
} /**
* 业务逻辑
*/
public void handleBI(String hostname) throws InterruptedException {
System.out.println(hostname+" start working...");
// 模拟保持不关闭状态
Thread.sleep(Long.MAX_VALUE);
} public static void main(String[] args) throws Exception {
// 获取zk连接
DistributedServer servers = new DistributedServer();
servers.getConn();
// 注册服务器
servers.registServer(args[0]);
// 业务逻辑
servers.handleBI(args[0]);
}
}

  客户端:

package com.zk;

import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; /**
* 分布式服务器动态感知——客户端
*
* @author zcc ON 2018/1/17
**/
public class DistributedClient {
private static final String coonectString = "192.168.137.128:2181,192.168.137.138:2181,192.168.137.148:2181";
private static final int sessionTimeout = 2000;
private static final String parentNode = "/servers";
// 注意volatile的使用意义(使每个线程都得到最新值)
private volatile List<String> serverList; private ZooKeeper zk = null; /**
* 获得连接
* @throws IOException
*/
public void getConn() throws IOException {
zk = new ZooKeeper(coonectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
try {
// 回调事件重新更新服务器列表并注册监听
getServerList();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
} /**
* 业务逻辑
*/
public void handleBI() throws InterruptedException {
System.out.println("client working...");
// 模拟保持不关闭状态
Thread.sleep(Long.MAX_VALUE);
}
public void getServerList() throws KeeperException, InterruptedException {
// 获取服务器子节点信息,并且对父节点监听
List<String> children = zk.getChildren(parentNode, true);
// 用于存放服务器列表的List
List<String> servers = new ArrayList<>();
for (String child : children) {
// 获取数据(这里无需监听,因为连接上了不需要更换连接了)
byte[] data = zk.getData(parentNode + "/" + child, false, null);
servers.add(new String(data));
}
// 更新到成员变量,供业务线程使用
serverList = servers;
// 打印服务器列表
System.out.println(serverList);
} public static void main(String[] args) throws Exception {
// 获取连接
DistributedClient client = new DistributedClient();
client.getConn();
// 获取子节点信息,并监听
client.getServerList();
// 启动业务功能
client.handleBI();
}
}

大数据入门第二天——基础部分之zookeeper(下)的更多相关文章

  1. 大数据入门第二天——基础部分之zookeeper(上)

    一.概述 1.是什么? 根据凡技术必登其官网的原则,我们先去官网瞅一瞅:http://zookeeper.apache.org/ Apache ZooKeeper is an effort to de ...

  2. 大数据入门第一天——基础部分之Linux基础(环境准备与先导知识)

    一.Linux环境安装 1.VM的安装 参考Linux环境搭建随笔:http://www.cnblogs.com/jiangbei/p/7248054.html 2.CentOS的安装 同参考上述随笔 ...

  3. 大数据入门第二十二天——spark(一)入门与安装

    一.概述 1.什么是spark 从官网http://spark.apache.org/可以得知: Apache Spark™ is a fast and general engine for larg ...

  4. 大数据入门第二十五天——elasticsearch入门

    一.概述 推荐路神的ES权威指南翻译:https://es.xiaoleilu.com/010_Intro/00_README.html 官网:https://www.elastic.co/cn/pr ...

  5. 大数据入门第二十二天——spark(二)RDD算子(1)

    一.RDD概述 1.什么是RDD RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行计算的 ...

  6. 大数据入门第二十五天——logstash入门

    一.概述 1.logstash是什么 根据官网介绍: Logstash 是开源的服务器端数据处理管道,能够同时 从多个来源采集数据.转换数据,然后将数据发送到您最喜欢的 “存储库” 中.(我们的存储库 ...

  7. 大数据入门第二十四天——SparkStreaming(一)入门与示例

    一.概述 1.什么是spark streaming Spark Streaming is an extension of the core Spark API that enables scalabl ...

  8. 大数据入门第二十二天——spark(三)自定义分区、排序与查找

    一.自定义分区 1.概述 默认的是Hash的分区策略,这点和Hadoop是类似的,具体的分区介绍,参见:https://blog.csdn.net/high2011/article/details/6 ...

  9. 大数据入门第二十四天——SparkStreaming(二)与flume、kafka整合

    前一篇中数据源采用的是从一个socket中拿数据,有点属于“旁门左道”,正经的是从kafka等消息队列中拿数据! 主要支持的source,由官网得知如下: 获取数据的形式包括推送push和拉取pull ...

随机推荐

  1. SVN合并时报错:Merge tracking not allowed with missing subtrees; try restoring these items

    使用的是TortoiseSVN; Merge tracking not allowed with missing subtrees; try restoring these items 下面会有跟着几 ...

  2. 为什么mysql要做主从复制?

    为什么MySQL要做主从复制(读写分离)? 通俗来讲,如果对数据库的读和写都在同一个数据库服务器中操作,业务系统性能会降低. 为了提升业务系统性能,优化用户体验,可以通过做主从复制(读写分离)来减轻主 ...

  3. 内置函数 sorted

    内置函数 sorted 语法: sorted(iterable,key = None,reverse= false)iterable: 可迭代的对象key:排序规则(排序函数),在sorted内部将& ...

  4. 【转】【Flex】FLEX 学习网站分享

    [转:http://hi.baidu.com/tanghecaiyu/item/d662fbd7f5fbe02c38f6f764 ] FLEX 学习网站分享 http://blog.minidx.co ...

  5. 【名称解释】#001 IIS名词解释

    关于[名称解释]类型的文章,会慢慢更新. 2015.02.06 更 应用程序池: 应用程序池是将一个或多个应用程序链接到一个或多个工作进程集合的配置. 因为应用程序池中的应用程序与其他应用程序被工作进 ...

  6. PHP设计模式系列 - 工厂模式

    工厂模式 提供获取某个对象实例的一个接口,同时使调用代码避免确定实例化基类的步骤. 工厂模式 实际上就是建立一个统一的类实例化的函数接口.统一调用,统一控制. 工厂模式是php项目开发中,最常用的设计 ...

  7. 转 oracle的热备份和冷备份

    一.冷备份介绍:    冷备份数据库是将数据库关闭之后备份所有的关键性文件包括数据文件.控制文件.联机REDO LOG文件,将其拷贝到另外的位置.此外冷备份也可以包含对参数文件和口令文件的备份,但是这 ...

  8. swift直接赋值与引用赋值都会触发willSet

    class baseGoo{ var isScannerRunning = false { willSet{ print(newValue) } } var desp:String = "& ...

  9. 经验总结13--EF配置

    EF配置,开发前的准备及步骤. 使用V22013和EF6.1. 1.使用VS新建MVC项目. 2.创建实体类. 3.配置web.config的数据库链接字符串. <connectionStrin ...

  10. luogu P3391 【模板】文艺平衡树(Splay)

    嘟嘟嘟 突然觉得splay挺有意思的-- 这道题只有一个任务:区间翻转. 首先应该知道的是,splay和线段树一样,都可以打标记,然后走到每一个节点之前先下传. 那怎么打标记呢?还应该有"区 ...