第1章 Zookeeper入门

1.1 概述

Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。

1.2 特点

1.3 数据结构

1.4 应用场景

提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。

第2章 Zookeeper下载

第3章 Zookeeper内部原理

3.1 选举机制

1)半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。

2)Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。

3)以一个简单的例子来说明整个选举的过程。

假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么,如图5-8所示。

                        图5-8Zookeeper的选举机制

(1)服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING状态。

(2)服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。

(3)服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。

(4)服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。

(5)服务器5启动,同4一样当小弟。

3.2节点类型

3.3 Stat结构体

1)czxid-创建节点的事务zxid

每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。

事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。

2)ctime - znode被创建的毫秒数(从1970年开始)

3)mzxid - znode最后更新的事务zxid

4)mtime - znode最后修改的毫秒数(从1970年开始)

5)pZxid-znode最后更新的子节点zxid

6)cversion - znode子节点变化号,znode子节点修改次数

7)dataversion - znode数据变化号

8)aclVersion - znode访问控制列表的变化号

9)ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。

10)dataLength- znode的数据长度

11)numChildren - znode子节点数量

3.4 监听器原理(面试重点)

3.5 写数据流程

第4章 Zookeeper实战(开发重点)

4.1 分布式安装部署

1.集群规划

在hadoop102、hadoop103和hadoop104三个节点上部署Zookeeper。

2.解压安装

(1)解压Zookeeper安装包到/opt/module/目录下

tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/module/

(2)同步/opt/module/zookeeper-3.4.10目录内容到hadoop103、hadoop104

xsync zookeeper-3.4.10/

3.配置服务器编号

(1)在/opt/module/zookeeper-3.4.10/这个目录下创建zkData

mkdir -p zkData

(2)在/opt/module/zookeeper-3.4.10/zkData目录下创建一个myid的文件

touch myid

添加myid文件,注意一定要在linux里面创建,在notepad++里面很可能乱码

(3)编辑myid文件

vi myid

在文件中添加与server对应的编号:

2

(4)拷贝配置好的zookeeper到其他机器上

xsync myid

并分别在hadoop102、hadoop103上修改myid文件中内容为3、4

4.配置zoo.cfg文件

(1)重命名/opt/module/zookeeper-3.4.10/conf这个目录下的zoo_sample.cfg为zoo.cfg

mv zoo_sample.cfg zoo.cfg

(2)打开zoo.cfg文件

vim zoo.cfg

修改数据存储路径配置

dataDir=/opt/module/zookeeper-3.4.10/zkData

增加如下配置

#######################cluster##########################

server.2=hadoop102:2888:3888

server.3=hadoop103:2888:3888

server.4=hadoop104:2888:3888

(3)同步zoo.cfg配置文件

xsync zoo.cfg

(4)配置参数解读

server.A=B:C:D。

A是一个数字,表示这个是第几号服务器;

集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。

B是这个服务器的ip地址;

C是这个服务器与集群中的Leader服务器交换信息的端口;

D是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。

4.集群操作

(1)分别启动Zookeeper

bin/zkServer.sh start

bin/zkServer.sh start

bin/zkServer.sh start

(2)查看状态

#bin/zkServer.sh status

JMX enabled by default

Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg

Mode: follower

# bin/zkServer.sh status

JMX enabled by default

Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg

Mode: leader

# bin/zkServer.sh status

JMX enabled by default

Using config: /opt/module/zookeeper-3.4.10/bin/../conf/zoo.cfg

Mode: follower

4.2 客户端命令行操作

表5-1

命令基本语法

功能描述

help

显示所有操作命令

ls path [watch]

使用 ls 命令来查看当前znode中所包含的内容

ls2 path [watch]

查看当前节点数据并能看到更新次数等数据

create

普通创建

-s  含有序列

-e  临时(重启或者超时消失)

get path [watch]

获得节点的值

set

设置节点的具体值

stat

查看节点状态

delete

删除节点

rmr

递归删除节点

1.启动客户端

bin/zkCli.sh

2.显示所有操作命令

help

3.查看当前znode中所包含的内容

ls /

[zookeeper]

4.查看当前节点详细数据

ls2 /

[zookeeper]

cZxid = 0x0

ctime = Thu Jan 01 08:00:00 CST 1970

mZxid = 0x0

mtime = Thu Jan 01 08:00:00 CST 1970

pZxid = 0x0

cversion = -1

dataVersion = 0

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 0

numChildren = 1

5.分别创建2个普通节点

create /sanguo "jinlian"

Created /sanguo

create /sanguo/shuguo "liubei"

Created /sanguo/shuguo

6.获得节点的值

get /sanguo

jinlian

cZxid = 0x100000003

ctime = Wed Aug 29 00:03:23 CST 2018

mZxid = 0x100000003

mtime = Wed Aug 29 00:03:23 CST 2018

pZxid = 0x100000004

cversion = 1

dataVersion = 0

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 7

numChildren = 1

[zk: localhost:2181(CONNECTED) 6]

[zk: localhost:2181(CONNECTED) 6] get /sanguo/shuguo

liubei

cZxid = 0x100000004

ctime = Wed Aug 29 00:04:35 CST 2018

mZxid = 0x100000004

mtime = Wed Aug 29 00:04:35 CST 2018

pZxid = 0x100000004

cversion = 0

dataVersion = 0

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 6

numChildren = 0

7.创建短暂节点

[zk: localhost:2181(CONNECTED) 7] create -e /sanguo/wuguo "zhouyu"

Created /sanguo/wuguo

(1)在当前客户端是能查看到的

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

[wuguo, shuguo]

(2)退出当前客户端然后再重启客户端

[zk: localhost:2181(CONNECTED) 12] quit

[atguigu@hadoop104 zookeeper-3.4.10]$ bin/zkCli.sh

(3)再次查看根目录下短暂节点已经删除

[zk: localhost:2181(CONNECTED) 0] ls /sanguo

[shuguo]

8.创建带序号的节点

(1)先创建一个普通的根节点/sanguo/weiguo

[zk: localhost:2181(CONNECTED) 1] create /sanguo/weiguo "caocao"

Created /sanguo/weiguo

(2)创建带序号的节点

[zk: localhost:2181(CONNECTED) 2] create -s /sanguo/weiguo/xiaoqiao "jinlian"

Created /sanguo/weiguo/xiaoqiao0000000000

[zk: localhost:2181(CONNECTED) 3] create -s /sanguo/weiguo/daqiao "jinlian"

Created /sanguo/weiguo/daqiao0000000001

[zk: localhost:2181(CONNECTED) 4] create -s /sanguo/weiguo/diaocan "jinlian"

Created /sanguo/weiguo/diaocan0000000002

如果原来没有序号节点,序号从0开始依次递增。如果原节点下已有2个节点,则再排序时从2开始,以此类推。

9.修改节点数据值

[zk: localhost:2181(CONNECTED) 6] set /sanguo/weiguo "simayi"

10.节点的值变化监听

(1)在hadoop104主机上注册监听/sanguo节点数据变化

[zk: localhost:2181(CONNECTED) 26] [zk: localhost:2181(CONNECTED) 8] get /sanguo watch

(2)在hadoop103主机上修改/sanguo节点的数据

[zk: localhost:2181(CONNECTED) 1] set /sanguo "xisi"

(3)观察hadoop104主机收到数据变化的监听

WATCHER::

WatchedEvent state:SyncConnected type:NodeDataChanged path:/sanguo

11.节点的子节点变化监听(路径变化)

(1)在hadoop104主机上注册监听/sanguo节点的子节点变化

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

[aa0000000001, server101]

(2)在hadoop103主机/sanguo节点上创建子节点

[zk: localhost:2181(CONNECTED) 2] create /sanguo/jin "simayi"

Created /sanguo/jin

(3)观察hadoop104主机收到子节点变化的监听

WATCHER::

WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/sanguo

12.删除节点

[zk: localhost:2181(CONNECTED) 4] delete /sanguo/jin

13.递归删除节点

[zk: localhost:2181(CONNECTED) 15] rmr /sanguo/shuguo

14.查看节点状态

[zk: localhost:2181(CONNECTED) 17] stat /sanguo

cZxid = 0x100000003

ctime = Wed Aug 29 00:03:23 CST 2018

mZxid = 0x100000011

mtime = Wed Aug 29 00:21:23 CST 2018

pZxid = 0x100000014

cversion = 9

dataVersion = 1

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 4

numChildren = 1

4.3 API应用

4.3.1 Eclipse环境搭建

1.创建一个Maven工程

2.添加pom文件

<dependencies>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>RELEASE</version>

</dependency>

<dependency>

<groupId>org.apache.logging.log4j</groupId>

<artifactId>log4j-core</artifactId>

<version>2.8.2</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->

<dependency>

<groupId>org.apache.zookeeper</groupId>

<artifactId>zookeeper</artifactId>

<version>3.4.10</version>

</dependency>

</dependencies>

3.拷贝log4j.properties文件到项目根目录

需要在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。

log4j.rootLogger=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

log4j.appender.logfile=org.apache.log4j.FileAppender

log4j.appender.logfile.File=target/spring.log

log4j.appender.logfile.layout=org.apache.log4j.PatternLayout

log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

4.3.2 创建ZooKeeper客户端

private static String connectString =

"hadoop102:2181,hadoop103:2181,hadoop104:2181";

private static int sessionTimeout = 2000;

private ZooKeeper zkClient = null;

@Before

public void init() throws Exception {

zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {

@Override

public void process(WatchedEvent event) {

// 收到事件通知后的回调函数(用户的业务逻辑)

System.out.println(event.getType() + "--" + event.getPath());

// 再次启动监听

try {

zkClient.getChildren("/", true);

} catch (Exception e) {

e.printStackTrace();

}

}

});

}

4.3.3 创建子节点

// 创建子节点

@Test

public void create() throws Exception {

// 参数1:要创建的节点的路径;参数2:节点数据;参数3:节点权限;参数4:节点的类型

String nodeCreated = zkClient.create("/atguigu", "jinlian".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);

}

4.3.4 获取子节点并监听节点变化

// 获取子节点

@Test

public void getChildren() throws Exception {

List<String> children = zkClient.getChildren("/", true);

for (String child : children) {

System.out.println(child);

}

// 延时阻塞

Thread.sleep(Long.MAX_VALUE);

}

4.3.5 判断Znode是否存在

// 判断znode是否存在

@Test

public void exist() throws Exception {

Stat stat = zkClient.exists("/eclipse", false);

System.out.println(stat == null ? "not exist" : "exist");

}

4.4监听服务器节点动态上下线案例

1.需求

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

2.需求分析,如图5-12所示

3.具体实现

(0)先在集群上创建/servers节点

[zk: localhost:2181(CONNECTED) 10] create /servers "servers"

Created /servers

(1)服务器端向Zookeeper注册代码

package com.zkcase;

import java.io.IOException;

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooKeeper;

import org.apache.zookeeper.ZooDefs.Ids;

public class DistributeServer {

private static String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";

private static int sessionTimeout = 2000;

private ZooKeeper zk = null;

private String parentNode = "/servers";

// 创建到zk的客户端连接

public void getConnect() throws IOException{

zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {

@Override

public void process(WatchedEvent event) {

}

});

}

// 注册服务器

public void registServer(String hostname) throws Exception{

String create = zk.create(parentNode + "/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

System.out.println(hostname +" is online "+ create);

}

// 业务功能

public void business(String hostname) throws Exception{

System.out.println(hostname+" is working ...");

Thread.sleep(Long.MAX_VALUE);

}

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

// 1获取zk连接

DistributeServer server = new DistributeServer();

server.getConnect();

// 2 利用zk连接注册服务器信息

server.registServer(args[0]);

// 3 启动业务功能

server.business(args[0]);

}

}

(2)客户端代码

package com.zkcase;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooKeeper;

public class DistributeClient {

private static String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";

private static int sessionTimeout = 2000;

private ZooKeeper zk = null;

private String parentNode = "/servers";

// 创建到zk的客户端连接

public void getConnect() throws IOException {

zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {

@Override

public void process(WatchedEvent event) {

// 再次启动监听

try {

getServerList();

} catch (Exception e) {

e.printStackTrace();

}

}

});

}

// 获取服务器列表信息

public void getServerList() throws Exception {

// 1获取服务器子节点信息,并且对父节点进行监听

List<String> children = zk.getChildren(parentNode, true);

// 2存储服务器信息列表

ArrayList<String> servers = new ArrayList<>();

// 3遍历所有节点,获取节点中的主机名称信息

for (String child : children) {

byte[] data = zk.getData(parentNode + "/" + child, false, null);

servers.add(new String(data));

}

// 4打印服务器列表信息

System.out.println(servers);

}

// 业务功能

public void business() throws Exception{

System.out.println("client is working ...");

Thread.sleep(Long.MAX_VALUE);

}

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

// 1获取zk连接

DistributeClient client = new DistributeClient();

client.getConnect();

// 2获取servers的子节点信息,从中获取服务器信息列表

client.getServerList();

// 3业务进程启动

client.business();

}

}

zookeeper从入门到放弃的更多相关文章

  1. CYQ.Data 从入门到放弃ORM系列:开篇:自动化框架编程思维

    前言: 随着CYQ.Data 开始回归免费使用之后,发现用户的情绪越来越激动,为了保持这持续的激动性,让我有了开源的念头. 同时,由于框架经过这5-6年来的不断演进,以前发的早期教程已经太落后了,包括 ...

  2. [精品书单] C#/.NET 学习之路——从入门到放弃

    C#/.NET 学习之路--从入门到放弃 此系列只包含 C#/CLR 学习,不包含应用框架(ASP.NET , WPF , WCF 等)及架构设计学习书籍和资料. C# 入门 <C# 本质论&g ...

  3. OpenStack从入门到放弃

    OpenStack从入门到放弃 目录: 为何选择云计算/云计算之前遇到的问题 什么是云计算 云服务模式 云应用形式 传统应用与云感知应用 openstack及其相关组件介绍 flat/vlan/gre ...

  4. 绕过校园网的共享限制 win10搭建VPN服务器实现--从入门到放弃

    一.开篇立论= =.. 上次说到博主在电脑上搭建了代理服务器来绕过天翼客户端的共享限制,然而经过实际测试还不够完美,所以本着生命不息,折腾不止的精神,我又开始研究搭建vpn服务器= =... (上次的 ...

  5. 《区块链:从入门到放弃》之obc安装步骤

    obc安装步骤 朋友们可能会好奇,厨师不研究菜谱怎么改研究兵法了,哈哈,我原本是app出身,最近被安排去预研区块链和比特币技术,2个月下来,颇有斩获.期间得到IBM的CC同学指导我一步一步安装obc的 ...

  6. win10搭建代理服务器实现绕过校园网的共享限制--从入门到放弃

    博主所在学校特别坑爹,校园网被电信一家垄断了,而且最恶心的还是电信要求一条网线只能供一台电脑上网,不许接路由器共享网络= =- (还有电信2M价格是380+每年,20m是500每年,而且网速都很慢= ...

  7. WPF从入门到放弃系列第二章 XAML

    本文是作者学习WPF从入门到放弃过程中的一些总结,主要内容都是对学习过程中拜读的文章的整理归纳. 参考资料 XAML 概述 (WPF):https://msdn.microsoft.com/zh-cn ...

  8. Android -- 带你从源码角度领悟Dagger2入门到放弃

    1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了. 2,接入项目 在项目的G ...

  9. Android -- 带你从源码角度领悟Dagger2入门到放弃(二)

    1,接着我们上一篇继续介绍,在上一篇我们介绍了简单的@Inject和@Component的结合使用,现在我们继续以老师和学生的例子,我们知道学生上课的时候都会有书籍来辅助听课,先来看看我们之前的Stu ...

随机推荐

  1. ThreadLocal = 本地线程?

    一.定义 ThreadLocal是JDK包提供的,从名字来看,ThreadLocal意思就是本地线程的意思. 1.1 是什么? 要想知道他是个啥,我们看看ThreadLocal的源码(基于JDK 1. ...

  2. 有哪些让人相见恨晚的Python库(一)

    对于我这个经常用python倒腾数据的人来说,下面这个库是真·相见恨晚 记得有一次我在服务器上处理数据时,为了解决Pandas读取超过2000W条数据就内存爆炸的问题,整整用了两天时间来优化.最后通过 ...

  3. 理解 SQL 开窗函数

    一次面试被问到开窗函数,懵逼了,赶紧补补总结一下.... 开窗函数也是函数,所以 比如在原来的查询上添加一个总数列 create table ztest( id int identity, c1 in ...

  4. 搭建个人OpenAPI

    简介 OpenAPI Open API 即开放 API,也称开放平台. 所谓的开放 API(OpenAPI)是服务型网站常见的一种应用,网站的服务商将自己的网站服务封装成一系列 API(Applica ...

  5. 在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

    在很多时候,我们做一些非常规化的界面的时候,往往需要创建一些用户控件,在其中绘制好一些基础的界面块,作为后续重复使用的一个单元,用户控件同时也可以封装处理一些简单的逻辑.在开发Winform各种类型项 ...

  6. 执行sql中的 函数,function

    CREATE FUNCTION [dbo].[GetWeight] ( ,)--重量/体积重 ) ,) as begin --顺丰重量/体积重以0.5kg为单位向上取值(小数点后两位4舍5入) ,) ...

  7. 大叔 Frameworks.Entity.Core 3 Predicate

    Frameworks.Entity.Core\Commons\Predicate\ 1LinqEntity.cs /// IQueryable扩展方法:条件过滤与排序功能    /// Modify ...

  8. 演示共享布局 Demonstrating Shared Layouts 精通ASP-NET-MVC-5-弗瑞曼 Listing 5-10

  9. Windows7只能设置纯色背景解决方法

    解决设置设置纯色图片,不能设置其他背景图片的方法. 比如这样的. 首先找到这个目录 C:\Users\(这个位置填写你的电脑用户名)\AppData\Roaming\Microsoft\Windows ...

  10. WebAPI接口开发实践

    背景 在团队两年多陆续负责了几个项目的开发上线已经代码的review,特别是对老项目的重构过程中,发现之前的API设计是没有任何规范和约定的,不同的开发同学有不同的习惯,因此需要一套规范去约定,现在分 ...