zookeeper -- 大数据面试

第一小节 zookeeper入门

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

zookeepr的工作机制

zookeeper 从设计模式角度来理解:是一个基于观察者模式的分布式服务管理框架,它负责存付和管理大家关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,zookeeper就将负责通知在zookeeper上注册的那些观察者做出相应的反应。

主要步骤:

1、服务器启动时去注册信息(创建都是临时节点)。

2、获取到当前在线服务器列表,并且注册监听。

3、服务器节点下线。

4、服务器节点下线事件通知。

第二小节 特点

1)zookeeper:一个领导者(leader),多个根随者(flollwer)组成集群。

2)集群中只要有半数以上节点存活,zookeeper集群就能正常服务。

3)全局数据一致:每个Server保存一份相同的数据副本,client无论连接到哪个server,数据者是一致的。

4)更新请求顺序进行:来自同一个client的更新请求按其发送顺序依次执行。

5)数据更新原子性,一次数据要么成功,要么失败。

6)实时性,在一定时间范围内,client能读到最新数据。

第三小节 数据结构

数据结构:zookeeper数据模型的结构与unix文件系统很类似,整体上可以看作一个棵树,每个节点称做一个znode。每个znode默认能够存储1MB数据,每个znode都可以通过其路径唯一标识。

第四小节 应用场景

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

统一命名服务:在分布式环境经常需要对应用/服务进行统一命名,便于识别。

例如:IP不容易记住,而域名容易记住。

统一配置管理:分布式环境下,配置同步非常常见。

一般要求一个集群中,所有节点的配置信息是一致的,比如kafka集群。

对配置文件修改后,希望能够快速同步到各个节点上。

配置管理可交由zookeeper实现:可将配置信息写入zookeeper上的一个znode。各个客户端服务器监听这个znode。一旦znode中的数据被修改,zookeeper将通知各个客户端服务器。

统一集群管理:分布式环境中,实时掌握每个节点的状态是必要的。可根据节点实时状态做出一些调整。zookeeper可以实理实时监控节点的状态变化。

(1)可将节点信息写入zookeeper上的一个znode.(2)监听这个znode可获取它的实时状态变化。

服务器动态上下线:

客户端能实时洞察到服务器上下线的变化。

1、服务端启动时去注册信息(创建都是临时节点)

2、获取当前在线服务器列表,并且注册监听。

3、服务器节点下线

4、服务器节点上下线事件通知,重新再去获取 服各器列表,并注册监听。

软负载均衡:在zookeeper中记录每台服务器的访问数,让访问数是最少的服务器去处理最新的客户端请求。

第五小节 zookeeper安装:

1、下载jdk包和zookeeper包

2、解包配置环境变量,配置相关参数 修改dataDir=目录为实际数据目录

3、启动及验证

#启动zookeeper
bin/zkServer.sh start 
#查看进程是否启动
jps
#查看状态
bin/zkServer.sh status 
#启动客户端
bin/zkCli.sh 
#退出客户端
quit
#停止zookeeper
bin/zkServer.sh stop 

第六小节 配置参数解读

 zookeeper中的配置文件zoo.cfg的参数含义解读如下:

1、tickTime=2000:通信息心跳数,zookeeper服务器与客户端心跳时间,单位毫秒

zookeeper使用的基本时间,服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳,时间为毫秒。

它用于心跳机制,并且设置最小的Session超时时间为两倍心跳时间(session的最小超时时间j2*tickTIme)

2、initLimit=10:主节点与从节点初始通信时限

集群中的follower跟随者服务器与leader领导者之间的初始连接时能容忍的最多心跳数,用它来限定集群中的zookeeper服务器连接到leader的时限。

3、syncLimit=5:主节点与从节点同步通信时限

集群中leader和follwer之间的最大晌应时间单位,例如响应超时syncLimit*tickTime,Leader认为foller死掉,从服务器列表中删除follwer.

4、dataDir:数据文件目录+数据持久化路径

主要用于保存zookeeper中的数据

5、clientPort=2181 客户连接端口

第七小节 分布式安装部署

1、集群规划

在每个节点部署zookeper

2、解压安装

(1)解压zookeeper安装包到

(2)每个节点都需要安装相应的包

3、配置服务器编号

创建相关目录zkData 

在创建zkData目录下创建一个myid的文件

编辑myid文件

在文件中写上对应的编号 

注意每个节点都应该有唯一id

相比较与本地模式,需要注意增加如下配置

server.2=hadoop102:2888:3888

server.3=hadoop103:2888:3888

server.4=hadoop104:2888:3888

同步zoo.cfg

配置参数解读

zoo.cfg 

server.A=B:C:D

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

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

B是这个服务器的地址

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

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

启动命令不变,状态需要使用bin/zkServer.sh status 

第八小节 客户端命令行操作

命令基本操作功能描述
help显示所有操作命令
ls path[watch]使用ls命令来查看znode中所包含的内容
ls2 path[watch]查看当前节点数据并能看到更新次数等数据
crate 

普通创建

-s 含有序列

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

get path[watch] 获取节点的值
set 设置节点的具体的值
stat查看节点状态查看节点状态
delete删除节点
rmr递归删除节点

1、启动客户端

bin/zkCli.sh 

2、显示所有操作命令

help

3、查看当前znod中所包含的内容

ls /

4、查看当前znode详细数据

ls2 /

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

create /test2jj  "jinlina"

create /test3jj 'liubei'

6、获取节点

get /test3jj 

7、创建短暂节点

create -e /test4jj "fdsa"

8、在当前客户端是能查看到的

ls /test4jj 

9、退出当前客户端然后再重启客户端

quit

bin/zkCli.sh 

 

zookeeper 3.6版本shell命令行

新增命令
语法:create [-s] [-e] [-c] [-t ttl] path [data] [acl]
参数:使用[]包含的是可选参数。
[-s] : 创建有序节点。
[-e] : 创建临时节点。
[-c] : 创建一个容器节点。
[t ttl] : 创建一个TTL节点, -t 时间(单位毫秒)。
path: 路径 ,因为没有中括号,所以是必须参数。
[data]:节点的数据,可选,如果不使用时,节点数据就为null。
[acl] :权限相关,后面文章讲。
例子:
创建持久化节点:

create /node1  "123456789"
1
创建持久化有序节点:

create -s /node2  "123456789"
1
创建临时节点

create -e /node3 "123456879"
1
创建临时有序节点

create -e -s /node3 "123456879"
1
创建容器节点

create -c /node3 "123456879"
1
创建TTL节点

create -t 2000 /node3 "123456879"
1
创建有序节点时,Zookeeper会在我们知道的节点名称后面补一个有序的,唯一的递增数字后缀。


查看命令
get [-s] [-w] path
查看节点数据,我用的是3.6.1的版本,只会打印节点数据,之前的某个版本及之前是查看节点数据加节点元信息的。如果现在要返回节点数据加节点元信息可以使用-s参数。
[-s] :查看节点数据加元信息。
[-w] : 查看节点并为节点添加一个监听,当节点被修改时,该客户端会收到一个回调。之前版本是在path 后面加一个watch实现:get path watch 。


stat [-w] path //查看节点元信息。
[-w] :查看节点并为节点添加一个监听,当节点被修改时,该客户端会收到一个回调。之前版本是在path 后面加一个watch实现:stat path watch 。

ls [-s] [-w] [-R] path //查看某一节点下的子节点。
[-s] : 查看某一节点下的子节点加当前节点的元信息,相当于之前版本的ls2命令。
[-w] :查看节点并为节点添加一个监听,当节点被修改时,该客户端会收到一个回调。之前版本是在path 后面加一个watch实现:ls path watch 。
[-R]: 返回当前节点路径,当前节点的子节点,当前节点的子节点的子节点(递归)。


ls2 path //返回子节点加当前节点的信息。 之前某个版本有,但是在3.6.1该命令被删除了。以参数形式集成到ls中。

history ://查看该客户端登录以来使用的最进执行的11个命令。

redo cmdno //再执行一次指定的历史命令。cmdno 是执行history命令时显示命令左边的index。

version :查看Zookeeper版本。


getAllChildrenNumber path :获取指定节点的所有子节点个数,包括子节点的子节点递归。getAllChildrenNumber / 代表获取Zookeeper所有节点的个数(/节点除外)。

getEphemerals path :获取该客户端会话创建的、指定节点下的所有临时子节点列表,包括持久子节点下的临时子节点递归。


修改命令
set [-s] [-v version] path data 修改节点数据,默认没有返回信息。
[-s] :返回修改后节点的元信息。
[-v version] :指定数据的版本,版本不符合时修改失败,类似关系型数据库的乐观锁。
path :修改节点路径。
data :修改的数据。

删除命令
delete [-v version] path //删除节点,删除的节点必须没有任何子节点,否则会删除失败。
[-v version] :指定数据的版本,版本不符合时删除失败,类似关系型数据库的乐观锁。

deleteall path // 递归节点。会递归删除该节点及其所有子节点。之前版本是rmr path。

其他命令
close 关闭客户端连接,把连接设置为关闭状态,实质关闭Socket连接,关闭之后发送命令就会报错。

connect host:port 连接其他Zookeeper服务器。

printwatches on|off 是否开启watch机制,如果设置为off,则该客户端监听的节点事件都不会生效、默认on。

removewatches path 删除在某节点上设置的监听。

sync path //把当前Zookeeper服务器的指定节点同步到主从集群中的其他Zookeeper服务器上。
 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>MapreduceDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.source>8</maven.compiler.source>
    </properties>

    <dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>2.6.5</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.30</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>compile</scope>
    </dependency>

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
        </dependency>
    </dependencies>



</project>

 log4j

# Define some default values that can be overridden by system properties
hbase.root.logger=INFO,console
hbase.security.logger=DEBUG,console
hbase.log.dir=.
hbase.log.file=hbase.log

# Define the root logger to the system property "hbase.root.logger".
log4j.rootLogger=${hbase.root.logger}

# Logging Threshold
log4j.threshold=ALL

#
# Daily Rolling File Appender
#
log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DRFA.File=${hbase.log.dir}/${hbase.log.file}

# Rollver at midnight
log4j.appender.DRFA.DatePattern=.yyyy-MM-dd

# 30-day backup
#log4j.appender.DRFA.MaxBackupIndex=30
log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout

# Pattern format: Date LogLevel LoggerName LogMessage
log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2}: %m%n

# Rolling File Appender properties
hbase.log.maxfilesize=256MB
hbase.log.maxbackupindex=20

# Rolling File Appender
log4j.appender.RFA=org.apache.log4j.RollingFileAppender
log4j.appender.RFA.File=${hbase.log.dir}/${hbase.log.file}

log4j.appender.RFA.MaxFileSize=${hbase.log.maxfilesize}
log4j.appender.RFA.MaxBackupIndex=${hbase.log.maxbackupindex}

log4j.appender.RFA.layout=org.apache.log4j.PatternLayout
log4j.appender.RFA.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2}: %m%n

#
# Security audit appender
#
hbase.security.log.file=hbase-audit.log
hbase.security.log.maxfilesize=256MB
hbase.security.log.maxbackupindex=20
log4j.appender.RFAS=org.apache.log4j.RollingFileAppender
log4j.appender.RFAS.File=${hbase.log.dir}/${hbase.security.log.file}
log4j.appender.RFAS.MaxFileSize=${hbase.security.log.maxfilesize}
log4j.appender.RFAS.MaxBackupIndex=${hbase.security.log.maxbackupindex}
log4j.appender.RFAS.layout=org.apache.log4j.PatternLayout
log4j.appender.RFAS.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n
log4j.category.SecurityLogger=${hbase.security.logger}
log4j.additivity.SecurityLogger=false
#log4j.logger.SecurityLogger.org.apache.hadoop.hbase.security.access.AccessController=TRACE

#
# Null Appender
#
log4j.appender.NullAppender=org.apache.log4j.varia.NullAppender

#
# console
# Add "console" to rootlogger above if you want to use this 
#
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2}: %m%n

# Custom Logging levels

log4j.logger.org.apache.zookeeper=INFO
#log4j.logger.org.apache.hadoop.fs.FSNamesystem=DEBUG
log4j.logger.org.apache.hadoop.hbase=INFO
# Make these two classes DEBUG-level. Make them DEBUG to see more zk debug.
log4j.logger.org.apache.hadoop.hbase.zookeeper.ZKUtil=INFO
log4j.logger.org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher=INFO
#log4j.logger.org.apache.hadoop.dfs=DEBUG
# Set this class to log DEBUG only otherwise its OTT
# Enable this to get detailed connection error/retry logging.
# log4j.logger.org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation=TRACE


# Uncomment this line to enable tracing on _every_ RPC call (this can be a lot of output)
#log4j.logger.org.apache.hadoop.ipc.HBaseServer.trace=DEBUG

# Uncomment the below if you want to remove logging of client region caching'
# and scan of .META. messages
log4j.logger.org.apache.hadoop.hbase.client.HConnectionManager$HConnectionImplementation=INFO
log4j.logger.org.apache.hadoop.hbase.client.MetaScanner=INFO
package com.wjj.zookeeper.zkcli;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class zkCLitest {
    private static String connectString = "docloud001:2181,docloud002:2181,docloud003:2181";
    private static int sessionTimeOut = 200;
    private ZooKeeper zkCliet = null;

    @Before
    public void init() throws IOException {
        zkCliet = new ZooKeeper(connectString, sessionTimeOut, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println(watchedEvent.getType() + "--" + watchedEvent.getPath());
                try {
                    zkCliet.getChildren("/", true);
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //创建字节点
    @Test
    public void create() throws  Exception{
        String nodeCreated = zkCliet.create("/wjj","helloworld".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);

    }

    @Test
    public  void getChildren() throws KeeperException, InterruptedException {
        List<String> children = zkCliet.getChildren("/", true);
        for (String child : children) {
            System.out.println(child);
        }
        Thread.sleep(Long.MAX_VALUE);
    }

    //判断znode是否存在
    @Test
    public void exist() throws KeeperException, InterruptedException {
        Stat stat = zkCliet.exists("/etc",false);
        System.out.println(stat==null?"not exist":"exist");
    }


    @After
    public void closeSession() throws InterruptedException {
        zkCliet.close();
    }
}

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

1、需求,

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

package com.wjj.zookeeper.zkcli;

import org.apache.zookeeper.*;

import java.io.IOException;

public class DistributeServer {
    private static String connectString = "docloud001:2181,docloud002:2181,docloud003:2181";
    private static int sessionTimeOut = 200;
    private ZooKeeper zkCliet = null;
    private String parentNode = "/servers";
    public void getConnect() throws IOException {
        zkCliet = new ZooKeeper(connectString, sessionTimeOut, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println(watchedEvent.getState());
            }
        });
    }

    public void registServer(String hostname) throws KeeperException, InterruptedException {
        String create = zkCliet.create(parentNode + "/server",
                hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println(hostname+"is online"+create);
    }

    //业务功能
    public void business(String hostname) throws InterruptedException {
        System.out.println(hostname+"is working~~~");
        Thread.sleep(Long.MAX_VALUE);
    }

    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        DistributeServer server = new DistributeServer();
        server.getConnect();
        server.registServer("1123");
        server.business("1123");
    }
}
package com.wjj.zookeeper.zkcli;

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.Arrays;
import java.util.List;

public class DistributeClient {
    private static String connectString = "docloud001:2181,docloud002:2181,docloud003:2181";
    private static int sessionTimeOut = 200;
    private ZooKeeper zkCliet = null;
    private String parentNode = "/servers";

    public void getConnect() throws IOException {
        zkCliet = new ZooKeeper(connectString, sessionTimeOut, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                try {
                    getServerList();
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public void business( ) throws InterruptedException {
        System.out.println( "client is working~~~");
        Thread.sleep(Long.MAX_VALUE);
    }

    public void getServerList() throws KeeperException, InterruptedException {
        List<String> children = zkCliet.getChildren(parentNode, true);
        ArrayList<String> servers = new ArrayList<>();
        for (String child : children) {
            byte[] data = zkCliet.getData(parentNode+"/"+child,false,null);
            servers.add(new String(data));
        }
        System.out.println(Arrays.asList(servers));
    }

    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        DistributeClient client = new DistributeClient();
        client.getConnect();
        client.getServerList();
        client.business();

    }


}

zookeeper内部原理

节点类型

持事件进行久:客户端和服务断开连接后,创建节点不删除

短暂:客户端和服务断开连接后,创建节点自已删除

说明创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护

注意,在分布式系统中,顺序号可以被用于为所有事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序。

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 子节点数量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值