一、集群自启动脚本

  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. Django ORM字段类型 单表增删改查 万能的双下划线

    1.ORM三种模型 模型之间的三种关系:一对一,一对多,多对多. 一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性: 一 ...

  2. 读书笔记week1——涂涵越

    这次读书笔记主要是就<程序员修炼之道>这本书的前半部分做一些总结以及发表一些自己的看法. 本书前面的一部分主要是一些程序员应该在工作中时刻注意的事情,一些关键的信息如下: 1.处理问题的态 ...

  3. mysql常用语句备忘

    1.连接本地数据库 mysql -h localhost -u root -p123 2.连接远程数据库 mysql -h 192.168.0.201 -P 3306 -u root -p123 3. ...

  4. log4j配置详解(非常详细)

    Log4J的配置文件(Configuration File)就是用来设置记录器的级别.存放器和布局的,它可接key=value格式的设置或xml格式的设置信息.通过配置,可以创建出Log4J的运行环境 ...

  5. javascript中return的作用

    这里面的return含有一些细节知识: 例如:onClick='return add_onclick()'与 onClick='add_onclick()'的区别 JAVASCRIPT在事件中调用函数 ...

  6. css3实现border渐变色

    案例1 .box{ width: 100px; height: 100px; border:10px solid #ddd; border-image: -webkit-linear-gradient ...

  7. Hadoop HBase概念学习系列之HBase里的时间戳(二十六)

    HBase集群要求每个节点的时间必须同步.HBase对于节点的时间扭曲(time skew)容忍度很低(这和HDFS是不一样的). 这主要是因为HBase需要使用系统时间来产生时间戳.如果系统时间不同 ...

  8. November 6th 2016 Week 46th Sunday

    The starting point of all achievements is desire. 成功的第一步是渴望. Those who make great achievements are o ...

  9. NCE3

    Lesson1  A puma at large Pumas are large, cat-like animals which are found in America. When reports ...

  10. python3: 字符串和文本(3)

    11. 删除字符串中不需要的字符  strip() 方法能用于删除开始或结尾的字符: lstrip() 和 rstrip() 分别从左和从右执行删除操作 >>> s = ' hell ...