技术干货 | 大数据开发系列之Zookeeper

海文国际2018-11-09 06:40:57

一:ZooKeeper简介

1、背景

随着互联网技术的高速发展,对计算和存储能力要求越来越高。单纯依靠少量的高性能服务器完成计算任务,已经无法瞒住需求了。IT架构逐步从集中式向分布式过渡。然而,分布式系统涉及到复杂、不稳定的等问题。

2、简介

http://zookeeper.apache.org/

Zookeeper可以将这些复杂的、容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并提供一些列简单易用的接口给用户使用。

特点

1、源码开放。

2、分布式协调服务,解决分布式数据一致性问题。

3、高性能

4、通过调用Zookeeper提供的接口来解决一些分布式的问题。

3、应用场景

分布式系统,实现高效可靠常会有如下应用需求:

(1)数据发布和订阅

分布式系统数据一致性,通常是使用数据发布和订阅形式实现。

传统的发布订阅有:"推"和"拉"两种模式。”推”:服务器将数据推送给客户机。”拉”:客户机从服务器定时拉去信息。

Zookeeper可以实现两者结合的方式,实现分布式系统数据一致性。

(2)负载均衡

每个客户服务可以在Zookeeper上创建属于自己的节点,节点维护相关的信息,包括链接信息数,当某一个节点链接快慢的时候,将其切换到其他节点上,实现负责均衡。

(3)命名服务

ZooKeeper通过ID的形式,提供名称服务。一种是自增长,一种是UUID。

(4)心跳检查

上面提过客户服务在ZooKeeper上注册节点,Zookeeper只需要判断这些节点是否可用,从而实现心跳检查。

二:Zookeeper数据模型

Zookeeper本身提供和维护了一个有层次关系的数据结构,类似标准的文件系统,不同的是Zookeeper文件系统的每个节点znode,都可以存储数据,而znode目前有四种类型:临时节点、临时顺序编号节点、持久化节点及持久化顺序编号节点,那么接下来结合网络上的数据结构图说明:

A、 层次化的目录结构,命名符合常规文件系统规范。

B、 每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识。比如:NameService下的Server1,被唯一的标识为:/NameService/Server1。

C、 节点Znode可以包含数据和子节点。

D、 每个znode节点,都有版本的,也就是该节点的路径下,存放多份版本的数据。

E、 每个znode节点,都客户端应用可以在节点上设置监视器 。

F、 Znode有两种类型,短暂的(ephemeral)和持久的(persistent)。

G、 Znode的类型在创建时确定并且之后不能再修改。

H、 短暂znode的客户端会话结束时,zookeeper会将该短暂znode删除,短暂znode不可以有子节点。

I、 持久znode不依赖于客户端会话,只有当客户端明确要删除该持久znode时才会被删除。

三、 Zookeeper工作原理

1、核心概念

leader:是整个Zookeeper集群工作机制的核心。负责进行投票的发起和决议,更新系统状态。

Observer:同步leader的状态。

follower:由 leader分派,任务,接受客户端请求并想客户端返回结果,在选主过程中参与投票。

Watcher: 在 ZooKeeper 是一个核心功能,Watcher 可以监控目录节点的数据变化以及子目录的变化,一旦这些状态发生变化,服务器就会通知所有设置在这个目录节点上的 Watcher,从而每个客户端都很快知道它所关注的目录节点的状态发生变化,而做出相应的反应。

ACL:每个znode被创建时都会带有一个ACL,用于决定谁可以对它执行何种操作。

2、工作原理

A、Zookeeper服务核心是原子广播,它保证了各个参与的Server间同步,实现它协议为Zab协议,它分为恢复模式和广播模式。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

广播模式:数据同步模式。恢复模式:leader选举模式。

B、Zookeeper服务持续监听所有注册的znode节点,一旦节点的结构、数据发生变化时,leader节点会监控到变化并更新系统状态值,所有follower和observer节点会向leader节点的数据状态同步,这也是Zookeeper在分布式环境的核心作用。

C、所有的observer的znode节点,都可接收客户端的链接,也会从leader节点同步更新最新的数据版本,但其不参与leader的投票动作,会将客户端的写入数据请求转发给leader节点处理;

D、所有的follower的znode节点,都有资格参与leader的投票选择,也会自动从leader节点更新同步数据版本,也处理客户端的请求及返回结果;

3、设计理念

A、原子性,各个znode节点数据只有更新成功或失败,没有中间状态;

B、可靠性,如果一条消息被一台服务器接收,那么其它各个服务器都会接收,保证了数据的一致性;

C、实时性,Zookeeper可保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到最新的数据,如果需要最新数据,应该在读取数据之前调用sync()接口,来手动获取最新的数据版本;

D、等待无关性,无效的或是阻塞的客户端链接,不影响其它任务客户端链接,各个链接客户端彼此独立链接;

E、一致性,客户端不论连接到哪个服务器上,展示给它都是同一个视图,这是Zookeeper最重要的性能。

四、下载安装

1、下载地址

https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.4.6/

2、解压

tar -zxvf zookeeper-3.4.6.tar.gz

3、配置

$ZOOKEEPER/conf下配置zoo.cfg

mv zoo_sample.cfg zoo.cfg

initLimit=10

syncLimit=5

clientPort=2181

tickTime=2000

dataDir=/var/zookeeper

dataLogDir=/var/zookeeper

initLimit:启动时间

………………………………………………….单机安装,上面配置即可

server.1=192.168.1.112:2888:3888

server.2=192.168.1.111:2888:3888

server.3=192.168.1.115:2888:3888

配置详解:

syncLimit:leader监听到节点状态变化后,同步到leader及Listner节点时间

tickTime :这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔。

dataDir:顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里;

clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。当这些配置项配置好后,就可以启动 Zookeeper 了,启动后使用命令echo ruok | nc localhost 2181检查 Zookeeper 是否已经在服务

在(dataDir=/itcast/zookeeper-3.4.5/data)创建一个myid文件,里面内容是server.N中的N(server.2里面内容为2)echo "5" > myid

4、启动/关闭

启动:

分别在3台机器上启动ZooKeeper的Server:sh bin/zkServer.sh start;

关闭:

分别在3台机器上启动ZooKeeper的Server:sh bin/zkServer.sh stop;

查看:

jps

五、 客户端Shell操作

1、连接ZooKeeper服务

zkCli.sh -server host:port cmd args

eg:./zkCli.sh -server 192.168.8.130:2181

2、查看节点

ls /

3、创建节点并存储数据

create /app1 "this is app1"

持久带序号 create -s

持久不带序号 create

短暂带序号 create -s -e

短暂不带序号 create –e

4、获取节点内容

get  /app1

5、修改节点内容

set /lijie/test   66666

6、节点状态

stat  /node_5

六、 客户端Java操作

1、 ZooKeeper项目资源引入

2、基本开发模型

(1)同步通信模式开发

import java.io.IOException;

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.KeeperException;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooKeeper;

import org.apache.zookeeper.Watcher.Event.KeeperState;

import org.apache.zookeeper.ZooDefs.Ids;

public class CreateNodeSync implements Watcher{

private static ZooKeeper zooKeeper = null;

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

        zooKeeper = new ZooKeeper("192.168.8.130:2181",5000,new CreateNodeSync());

        System.out.println(zooKeeper.getState());

        Thread.sleep(Integer.MAX_VALUE);

    }

public void doSomething(){

try {

String info = zooKeeper.create("/node_4", "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);

System.out.println(info);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

 }

}

@Override

public void process(WatchedEvent event) {

System.out.println("接收到的信息是:"+event.getState());

if(event.getState()==KeeperState.SyncConnected){

doSomething();

}       

}

}

(2)异步通信模式开发

package com.haiwen.hadoop.zookeeper;

import java.io.IOException;

import org.apache.zookeeper.AsyncCallback;

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.KeeperException;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooKeeper;

import org.apache.zookeeper.Watcher.Event.KeeperState;

import org.apache.zookeeper.ZooDefs.Ids;

public class CreateNodeAsync implements Watcher{

private static ZooKeeper zooKeeper = null;

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

zooKeeper = new ZooKeeper("192.168.8.130:2181",5000,new CreateNodeAsync());

System.out.println(zooKeeper.getState());

Thread.sleep(Integer.MAX_VALUE);

}

public void doSomething(){

try {

zooKeeper.create("/node_5", "123".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT,new IStringCallBack(), "创建");

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

@Override

public void process(WatchedEvent event) {

System.out.println("接收到的信息是:"+event.getState());

if(event.getState()==KeeperState.SyncConnected){

doSomething();

}     

}

static class IStringCallBack implements AsyncCallback.StringCallback{

//rc-返回码,path-需要创建节点的完整路径,name-已经创建节点真实路径

 @Override

public void processResult(int rc, String path, Object ctx, String name) {

 // TODO Auto-generated method stub

System.out.println(rc);

 System.out.println(path);

System.out.println(ctx);

System.out.println(name);

}

}

}

%1、 Java API接口

String create(String path, byte[] data, List<ACL> acl, CreateMode createMode)

Stat exists(String path, boolean watch)

void delete(String path, int version)

List<String> getChildren(String path, boolean watch)

List<String> getChildren(String path, boolean watch)

创建一个给定的目录节点 path, 并给它设置数据;判断某个 path 是否存在,并设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper 实例时指定的 watcher,exists方法还有一个重载方法,可以指定特定的 watcher ;重载方法,这里给某个目录节点设置特定的 watcher;删除 path 对应的目录节点,version 为 -1 可以匹配任何版本,也就删除了这个目录节点所有数据 ;获取指定 path 下的所有子目录节点,同样 getChildren方法也有一个重载方法可以设置特定的 watcher 监控子节点的状态

Stat setData(String path, byte[] data, int version)

byte[] getData(String path, boolean watch, Stat stat)

void addAuthInfo(String scheme, byte[] auth)

Stat setACL(String path, List<ACL> acl, int version)

List<ACL> getACL(String path, Stat stat)

给 path 设置数据,可以指定这个数据的版本号,如果 version 为 -1 怎可以匹配任何版本;获取这个 path 对应的目录节点存储的数据,数据的版本等信息可以通过 stat 来指定,同时还可以设置是否监控这个目录节点数据的状态;客户端将自己的授权信息提交给服务器,服务器将根据这个授权信息验证客户端的访问权限;给某个目录节点重新设置访问权限,需要注意的是 Zookeeper 中的目录节点权限不具有传递性,父目录节点的权限不能传递给子目录节点。目录节点 ACL 由两部分组成:perms 和 id。Perms 有 ALL、READ、WRITE、CREATE、DELETE、ADMIN 几种 而 id 标识了访问目录节点的身份列表,默认情况下有以下两种:ANYONE_ID_UNSAFE = new Id(“world”, “anyone”) 和 AUTH_IDS = new Id(“auth”, “”) 分别表示任何人都可以访问和创建者拥有访问权限;获取某个目录节点的访问权限列表

学习最新热门IT技术

找一份自己满意的高薪工作

升职加薪就是它了

识别二维码

免费领取甲骨文内部学习资料


海文七月免费试听课预约

在这等你来试听哦~

【点击“阅读原文”预约报名海文7月免费试听课程。】

Copyright © 古田计算器虚拟社区@2017