Zookeeper

标题Zookeeper@[toc]

Zookeeper

1. 简介

Apache ZooKeeper是Apache软件基金会的一个软件项目,它为大型[分布式计算]提供[开源]的分布式配置服务、同步服务和命名注册。

简言:ZK就是一个管理多个服务的集群管理者+文件系统

核心解决问题:

  1. 同步配置集群配置信息(文件系统)
  2. 监听服务器的上下线,同时可以做出反应。(监听器)

2. Zookeeper场景需求

需求1:(监听器)

在这里插入图片描述

需求2:(文件系统)

在这里插入图片描述

需求分析3

在这里插入图片描述

3.Zookeeper作用

# 核心解决问题:
1. 文件管理者:同步配置集群配置信息到所有节点(文件系统)
2. 监听服务器的上下线,同时可以做出反应。(监听器即集群管理者)
# zookeeper
	1. 存数据,所有zk节点同步数据。
	2. 监听器,服务器和数据变化,事件发生可以做出反应(执行代码)
	3. zk集群本身 稳定性  数据可靠性  非常高。
补充:
	zookeeper以后的客户端实际上是zk要管理的集群服务器(软件程序)。

4. 特点

  1. 1主(Leader)多从(Follower),一旦故障就能立刻选出新的主机,继续提供服务。 自身稳定性No单点故障

  2. 集群中只要有半数以上zk节点存活,zk集群就能正常使用。 服务节点可靠性

  3. 选主的操作,使用投票机制服务的高效性、可靠性、操作的可靠性

  4. 任何一台zk主机添加的数据,都会同步到所有所有zk主机。 全局数据同步

  5. zk数据更新要么全部成功,要么全部失败。事务性,数据一致性

5. 集群角色简介

在这里插入图片描述

leader(主机)是zookeeper集群的核心。

​ 1.zookeeper集群工作的核心。

​ 2.事务操作的老大(增删改操作得让他点头)

follower(从机)

​ 1.承担非事务性操作,读操作。

​ 2.参与leader选举的投票

observer(观察者,了解)

​ 1.承担非事务性操作,读操作
​ 2.不能参与leader选举的投票

6.投票选主流程

主机不固定,动态选举,保证主机的可靠性,选举过程中主从之间有通信

# 假设有5台服务器,编号1,2,3,4,5。
服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于(选举状态)。
服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是(选举状态)
服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
服务器4启动,已经有老大,服务器4只能成为小弟。
服务器5启动,后面的逻辑同服务器4成为小弟。

Zookeeper的安装与使用

1. 集群规划

在这里插入图片描述

# 关键工作
1. 安装开始未启动,zk集群中谁是leader,不确定
2. 每个zkServer有一个myid,当前zkserver的一个编号,唯一。
	(myid的值是ip地址)
3.  心跳:
	 follower从机,会定时向主机发送心跳。让主机实时掌握从机状态信息。
    投票:
     启动和有zkServer挂掉,zkServer需要接受投票信息选主。
4. 数据同步
	zkServer会自动同步集群中的数据。
5. zkServer中的数据:
	保存在内存中。(数据量少,访问频率高)
	硬盘空间(data文件夹)

2.安装

  • 准备机器3台

    1. 设置ip
    2. 安装jdk
    3. 配置java环境变量
    4. 关闭防火墙
    5. 设置hostname
    6. 设置hosts(3台彼此之间集群互通)
    
  • 解压

    tar zxvf zookeeper-3.4.14.tar.gz -C /opt/installs

  • 配置path环境变量

    export PATH=$PATH:$JAVA_HOME/bin:/opt/installs/zookeeper3.4.14/bin
    

    source /etc/profile

  • 初始化配置

    1. 在zookeeper下创建data文件夹

    2. 在conf目录下通过拷贝的方式创建zoo.cfg文件

    (cp zoo_sample.cfg zoo.cfg)

    1. 配置zookeeper的文件存放位置
    dataDir=/opt/install/zookeeper3.4.14/data
    
  • 标记zk的主机号(为当前zk节点定义编号)

    在zk的data文件下创建myid文件,并指定一个zk主机编号,一般用ip为编号。

    20
    
  • 配置zk集群的所有节点信息

    编辑zoo.cfg配置文件

    server.20=192.168.153.20:2888:3888
    server.21=192.168.153.21:2888:3888
    server.22=192.168.153.22:2888:3888
    

    说明:
    在这里插入图片描述

  • 同步配置到所有zk在的宿主机上

    scp -r ./zookeeper root@ip:/opt/installs/

  • 修改每个机器上的myid

  • 管理zk

    1. 启动

    ./zkServer.sh start

    1. 查看状态

    ./zkServer.sh status(包括名称)

    1. 停止

    ./zkServer.sh stop

    1. 客户端

    ./zkCli.sh 登录本机的zk

    ./zkCli.sh -server ip:2181 登录指定ip的zk主机

  • zookeeper进程
    在这里插入图片描述

  • zookeeper主从
    在这里插入图片描述

3. ZKshell

文件系统
  • 文件系统结构

    • 特点

      1. 每个节点就是一个文件
      2. 每个节点都有一个名字一个
      3. 每个节点即可以是文件又可以是文件夹,下面可以继续挂节点。

    • 在这里插入图片描述

    1.客户端使用基本命令
    	1. 进入客户端
    		zkCli.sh
    	2. 查看帮助命令
    		[zk: localhost:2181(CONNECTED) 1] help
    	3. 退出客户端
    		[zk: localhost:2181(CONNECTED) 1] quit
    
    2.数据管理命令
    # 1. 浏览某个节点下的子节点(的名字)
    ls /
    # 2. 创建节点,并指定他的值。
    [zk: localhost:2181(CONNECTED) 8] create /lihao "李昊"
    Created /lihao
    # 3. 查看节点的值
    [zk: localhost:2181(CONNECTED) 10] get /lihao
    李昊 # 数据
    cZxid = 0x200000005 
    ctime = Fri Apr 10 17:55:04 CST 2020 # 创建时间
    mZxid = 0x200000005 
    mtime = Fri Apr 10 17:55:04 CST 2020
    pZxid = 0x200000005 
    cversion = 0
    dataVersion = 0 # 节点数据的更新次数【只要执行set就更新】
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 10 # 节点数据的字节,最大值1M
    numChildren = 0 # 直接子节点的个数
    # 4. 修改节点的值
    [zk: localhost:2181(CONNECTED) 45] set /lihao "新值"
    # 5. 删除节点
    [zk: localhost:2181(CONNECTED) 53] delete /lihao
    # 6. 删除节点及其子节点(递归删除)
    [zk: localhost:2181(CONNECTED) 53] rmr /lihao
    
    命令含义
    ls /浏览某个节点下的子节点(的名字)
    create /节点 “节点值”创建节点,并指定他的值。
    get /节点查看节点的值
    set /节点 “新值”修改节点的值
    delete /节点删除某个节点
    rmr /节点删除该节点,并递归删除内部所有节点。
  • 节点类型(文件类型)

    # 节点类型
    zookeeper可以将节点设置不同的类型
    1. 持久化节点
    	节点只要不删除,会一致存在。
    2. 顺序编号节点
    	每次对相同节点,重复创建,会自动对znode名称进行编号
    3. 临时节点
    	客户端断开,则节点消失。
    
    节点名称中文含义
    PERSISTENT持久化节点客户端与zookeeper断开连接后,该节点依旧存在
    PERSISTENT_SEQUENTIAL持久化顺序编号节点客户端与zookeeper断开连接后,该节点依旧存在,
    只是Zookeeper给该节点名称进行顺序编号
    EPHEMERAL临时节点客户端与zookeeper断开连接后,该节点被删除
    EPHEMERAL_SEQUENTIAL临时顺序编号节点客户端与zookeeper断开连接后,该节点被删除,
    只是Zookeeper给该节点名称进行顺序编号
    命令含义
    create /节点 “节点值”持久化节点
    create -s /节点 “节点值”持久化节点+顺序编号节点
    create -e /节点 “节点值”临时节点,客户端断开连接则失效。
    create -s -e /节点 “节点值”顺序编号节点+临时节点
监听通知
  • 监听机制

    1. 如果监听某个节点值,get方式,如果该值发生变化,则监听者会接收到zk的通知。
    2. 监听某个节点下所有节点,ls方式,如果节点下任意节点发生变化,则监听者会受到zk的通知。
    命令含义
    get /节点1/节点2 watch查看节点内容,并监听该值的变化(修改、失效等)
    ls /节点 watch查看某个节点下的所有节点信息,并监听下节点的变化(添加删除子节点)

4. zkShell命令

命令含义
help帮助
ls /节点显示指定节点下的所有节点
ls /节点 watch查看某个节点下的所有节点信息,并监听下节点的变化
create /节点 “节点值”创建节点,并指定值。
create -e /节点 “节点值”创建节点,-e是指定为临时节点,客户端断开连接或者重启则失效。
create -s /节点 “节点值”创建有序节点(数据库集群中id生成器)多次创建该节点,节点名字序号自增
get /节点1/节点2获得指定节点的内容值。
get /节点1/节点2 watch查看节点内容,并监听该值的变化(修改、删除、失效等)
set /节点 “新值”修改节点的值
delete /节点删除某个节点
rmr /节点删除该节点,并递归删除内部所有节点。

Java访问Zookeeper

在这里插入图片描述

1. 依赖导入

导入依赖
<dependency>
  <groupId>com.101tec</groupId>
  <artifactId>zkclient</artifactId>
  <version>0.10</version>
</dependency>

导入log4j.properties

2. 连接zookeeper

//1. 准备参数
String zkClusters = "192.168.199.40:2181,192.168.199.41:2181,192.168.199.42:2181";
//2. 创建zk客户端
zkClient zk = new ZkClient(zkClusters);
//

3. 文件系统相关

1. 获得子节点
	public void test1() {
        //1.创建zkClient客户端
        String zkcluster = "192.168.153.20:2181,192.168.153.21:2181,192.168.153.22:2181";
        ZkClient zk = new ZkClient(zkcluster);
        //2.获得子节点
        List<String> children = zk.getChildren("/");
        for (String child : children) {
            System.out.println(child);
        }
    }
2.获得某个节点下以及所有孙子节点
 public void test2() {
        //1.创建zkClient客户端
        String zkcluster = "192.168.153.20:2181,192.168.153.21:2181,192.168.153.22:2181";
        ZkClient zk = new ZkClient(zkcluster);
        //2.获得子节点
        List<String> children = zk.getChildren("/");
        for (String child : children) {
            List<String> sunzi = zk.getChildren("/" + child);
            for (String s : sunzi) {
                System.out.println(s);
            }
        }
    }
3. 添加
	public void test3() {
        //1.创建zkClient客户端
        String zkcluster = "192.168.153.20:2181,192.168.153.21:2181,192.168.153.22:2181";
        ZkClient zk = new ZkClient(zkcluster);
        //2.创建
        String s = zk.create("/zookeeper/lihao/haha", "哈哈", CreateMode.PERSISTENT);
        System.out.println(s);

    }
4.读取(查看节点的值)
	public void test4() {
        //1.创建zkClient客户端
        String zkcluster = "192.168.153.20:2181,192.168.153.21:2181,192.168.153.22:2181";
        ZkClient zk = new ZkClient(zkcluster);
        //2.读取节点的值
        Object o = zk.readData("/zookeeper/lihao/haha");
        System.out.println((String)o);
    }
5.判断节点是否存在
// 判断节点是否存在
boolean exists = zkClient.exists("/zookeeper/lihao");


// 删除节点
boolean delete = zkClient.delete("/zookeeper/lihao/haha");
//递归删除,适合删除文件夹类节点
boolean delete = zkClient.deleteRecursive("/zookeeper/lihao");
private ZkClient zkClient;
	 @Before  /**  此注解和Test经常一起使用  在Test执行前先执行一下
    public void before() {
        String zkcluster = "192.168.153.20:2181,192.168.153.21:2181,192.168.153.22:2181";
        zkClient = new ZkClient(zkcluster);
    }
   
   /**
     * 判断是否存在  和删除
     */
    @Test
    public void test5() {
        boolean b = zkClient.exists("/cyf");
        System.out.println(b);
    }
    /**
     * 判断是否存在 /root_id,不存在就创建,如果存在就打印该节点的信息值
     */
    @Test
    public void test6() {
        boolean b = zkClient.exists("/root_id");
        if(b){
            Object o = zkClient.readData("/root_id");
            System.out.println(o);
        }else{
            zkClient.create("/root_id","new created",CreateMode.PERSISTENT);
        }
    }
6.修改节点数据
    /**
     * 修改 /zookeeper/lihao/haha  的值
     */
    @Test
    public void test7() {
        zkClient.writeData("/zookeeper/lihao/haha","123456");
    }

 /**
     * 修改 /zookeeper/lihao/haha  的值
     */
    @Test
    public void test7() {
       //zkClient.writeData("/zookeeper/lihao/haha","123456");
        Stat stat = zkClient.writeDataReturnStat("/zookeeper/lihao/haha", "654321",-1);
        int version = stat.getVersion();
        System.out.println(version);
    }
7. 删除节点与递归删除
   /**
     * 删除
     */
    @Test
    public void test8() {
        boolean delete = zkClient.delete("/zookeeper/lihao/haha");
        //递归删除
        //zkClient.deleteRecursive("/zookeeper/lihao/haha");
        System.out.println(delete);
    }
8. 创建不同节点类型
//创建持久性节点
String path = zkClient.create("/cluster", "tomcat集群", CreateMode.PERSISTENT);
//创建临时节点
zkClient.create("/eznode", "", CreateMode.EPHEMERAL);
//创建临时有序节点
//客户端断开连接:zkClient.close() 和超时30都算
String path = zkClient.create("/cluster", "tomcat集群", CreateMode.EPHEMERAL_SEQUENTIAL);
//创建持久有序节点
zkClient.create("/pe","ID",CreateMode.PERSISTENT_SEQUENTIAL);

4. 监听服务相关

  • 工作机制
    在这里插入图片描述
1. 监听单节点

监听删除和修改

public class ZnodeListener {
    /**
     * 监听  /conf/db 的值的变化
     *      ls|get  watch
     */
    @Test
    public void test1() throws InterruptedException {
        //1.创建zkClient客户端
        String zkcluster = "192.168.153.20:2181,192.168.153.21:2181,192.168.153.22:2181";
        ZkClient zk = new ZkClient(zkcluster);
        //监听
        zk.subscribeDataChanges("/conf/db", new IZkDataListener() {
           //一旦该值发生了变化,会调用该方法

            /**
             *
             * @param s  被监听的节点
             * @param o  修改后的新值
             * @throws Exception
             */
            @Override
            public void handleDataChange(String s, Object o) throws Exception {
                System.out.println("节点"+s);
                System.out.println("新值"+o);
            }
            //如果节点被删除了  调用此方法
            @Override
            public void handleDataDeleted(String s) throws Exception {
                System.out.println(s+"被删除了");
            }
        });
        Thread.sleep(120000);
    }
}
2. 监听子节点(添加和删除)

监听子节点的添加和删除

public void test2() throws InterruptedException {
        //1.创建zkClient客户端
        String zkcluster = "192.168.153.20:2181,192.168.153.21:2181,192.168.153.22:2181";
        ZkClient zk = new ZkClient(zkcluster);
        //监听子节点的添加和删除
        zk.subscribeChildChanges("/conf", new IZkChildListener() {
            /**
             * 当子节点发生变化 (添加  删除)的时候,会调用
             * @param s  被监听的节点
             * @param list  变化后的所有子节点
             * @throws Exception
             */
            @Override
            public void handleChildChange(String s, List<String> list) throws Exception {
                System.out.println("监听节点"+s);
                System.out.println("所有子节点"+list);
            }
        });

        Thread.sleep(120000);
    }

应用场景案例

1. 分布式ID生成器

在这里插入图片描述

package demo3;

import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

public class GlobalIDGenerator {
    private String zkCluster;
    private String rootPath;
    private String tablename;
    private ZkClient zk;

    /**
     * 1.第一次使用时候,创建GlobalIDGenerator对象
     * @param zkCluster
     * @param rootPath
     * @param tablename
     */
    public GlobalIDGenerator(String zkCluster, String rootPath, String tablename) {
        this.zkCluster = zkCluster;
        //初始化zkClient
        zk = new ZkClient(zkCluster);
        this.rootPath = rootPath;
        this.tablename = tablename;
    }
    /**
     * 2.第一次使用该对象的生成id方法,初始化(节点信息)
     */
    public void init(){
        //判断是否已经存在了rootPath节点,不存在则创建
        boolean exists = zk.exists(rootPath);
        if (!exists){
            zk.create(rootPath,"idGenerator随意", CreateMode.PERSISTENT);
        }
        //判断"/user_id_generator"节点是否存在,不存在则创建
        boolean exists1 = zk.exists(rootPath + "/" + tablename + "_id_generator");
        if (!exists1){
            zk.create(rootPath+"/"+tablename+"_id_generator","随意",CreateMode.PERSISTENT);
        }
    }
    /**
     * 3.每次获得id,调用
     * @return
     */
    public int generateId() {
        //修改id_generator的值
        Stat stat = zk.writeDataReturnStat(rootPath + "/"+tablename+"_id_generator","", -1);
        return stat.getVersion();
    }
}


package demo3;

public class DistributedIDGenerator {
    public static void main(String[] args) {
        //像oeder表添加数据,获得order的id生成器的id值
        //1.为order表创建一个id生成器对象
        GlobalIDGenerator orderId = new GlobalIDGenerator("192.168.153.20:2181,192.168.153.21:2181,192.168.153.22:2181", "/root_id", "order");
        //2.初始化节点
        orderId.init();
        //3.每次获得id,generateId()
        for (int i = 0; i < 300; i++) {
            int id = orderId.generateId();
            System.out.println(id);
            //order.setId(id)  设置值
            //XxxDao.insert(order)  //插入表中
        }
    }
}

2. Zookeeper的集群zkServer服务个数

2N+1个

原因:3台zkServer的稳定性要大于4台。

​ 1台的稳定性大于2台的稳定性。

3.注册中心

  • 配置信息类

    @AllArgsConstructor
    @NoArgsConstructor
    @Getter
    @Setter
    @ToString
    public class DbConfigure implements Serializable {
        private String url;
        private String username;
        private String password;
        private String driverClassName;
    }
    
  • 配置信息同步类

    public class DBConfigWatcher implements Runnable {
        private String dbConfigNode = "/confs/datasource";
        private String cluster="192.168.199.40:2181,192.168.199.41:2181,192.168.199.42:2181";
        private ZkClient zkClient;
        private DbConfigure dbConfigure;
        public void run() {
            //1. 启动zookeeper的配置文件监听服务。
            zkClient = new ZkClient(cluster);
            zkClient.subscribeDataChanges(dbConfigNode,new IZkDataListener(){
                public void handleDataChange(String s, Object o) throws Exception {
                    //修改值。
                    dbConfigure  = zkClient.readData(dbConfigNode);
                    System.out.println(dbConfigure);
                    System.out.println("刷新配置文件");
                }
    
                public void handleDataDeleted(String s) throws Exception {
                    //删除节点
                    System.out.println("配置信息被删除");
                }
            });
            //2. 监听配置文件节点,如果修改,则修改配置文件信息。
        }
    }
    

4. 集群管理

监听服务器上下线,和服务器替换

public class ServerStateWatcher implements Runnable{
    private String serversNode = "/servers";
    private String cluster="192.168.199.40:2181,192.168.199.41:2181,192.168.199.42:2181";
    private ZkClient zkClient = new ZkClient(cluster);

    /**
     * 添加服务
     */
    public void regist(String address){
        //创建临时有序节点,如果,客户端断开。则
        zkClient.create("/servers/server",address, CreateMode.EPHEMERAL_SEQUENTIAL);
    }
    /**
     * 服务器下线
     *
     */
    public void release(){
        zkClient.close();
    }
    /**
     * 监控线程.
     */
    public void run() {
        //监控服务子节点的增删
        zkClient.subscribeChildChanges(serversNode, new IZkChildListener() {
            public void handleChildChange(String s, List<String> list) throws Exception {
                System.out.println("服务器列表变更目前服务器列表:"+list);
            }
        });
    }
}

底层原理

1. 监听通知工作机制

a.流程

在这里插入图片描述

b.机制

在这里插入图片描述

2. zk读写数据工作流程

a.读写操作(create、set、delete和读取)

在这里插入图片描述

b.流程

在这里插入图片描述

3.启动(新集群)zkServer投票选主流程(了解)

选主结果:

1:启动顺序.

2:myid(权重,级别,级别高能够获得到级别低的zk机器的投票)

3: 每个机器启动,会给自己投票。

主机不固定,动态选举,保证主机的可靠性,选举过程中主从之间有通信

# 假设有5台服务器,编号1,2,3,4,5。
服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于(选举状态)。
服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是(选举状态)
服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
服务器4启动,已经有老大,服务器4只能成为小弟。
服务器5启动,后面的逻辑同服务器4成为小弟。

HadoopHA(高可用)集群搭建

规避 数据|服务器 单点故障的问题。(即HA)

# 目前hadoop分布式集群的问题
1. editslog无法做到100%持久化,如果namenode宕机会有少量数据就丢失了。
2. 一旦NameNode宕机,整个hadoop集群还是会停止服务。
3. 如果启动2个NameNode,缺乏自动切换,就算namenode自动切换,客户端访问的ip地址也无法访问(需要虚拟IP包含主备的IP)

Hadoop1.x存在问题及解决办法

在这里插入图片描述

HAHadoop架构规划总结以及zkfc的工作补充说明

在这里插入图片描述

# HAHadoop集群架构设计
QJM(Quorum Journal Manager)是Hadoop专门为Namenode共享存储基于zookeeper开发的组件
	1: 引入了监控Namenode状态的ZookeeperFailController(ZKFC),ZKFC一般运行在Namenode的宿主机器上,与Zookeeper集群协作完成故障的自动转移
	2: 提供了Journal Node,每个QJN暴露一个RPC接口(远程调用),可以接受NameNode(主机)写入editslog的请求,也可以接受NameNode(备机)读取editslog的请求。
		而且写入数据,也遵循了zk投票机制,安全可靠。
NameNode(备机)
	还充当了SecondaryNameNode的职责,完成checkpoint,Fsimage数据的合并的职责。

Hadoop-Zookeeper工作机制

在这里插入图片描述

Hadoop(HA)搭建

# 集群规划--搭建思路

在这里插入图片描述

准备主机(4台)

ip、防火墙、hostname、hosts

安装必备软件
# 1.安装必备软件
1. 解压jdk
[root@centos8 modules]# tar zxvf jdk-8u221-linux-x64.tar.gz -C /opt/installs/
2. 解压hadoop
[root@centos8 modules]# tar zxvf hadoop-2.9.2.tar.gz -C /opt/installs/
3. 解压zookeeper
[root@centos8 modules]# tar zxvf zookeeper-3.4.14.tar.gz -C /opt/installs/
4. 安装psmisc
[root@centos8 modules]# yum install -y psmisc
# 2.统一配置如上的环境变量
1. ----------------/etc/profile-----------------------------
#JAVA
export JAVA_HOME=/opt/installs/jdk1.8
export PATH=$PATH:$JAVA_HOME/bin
# HADOOP
export HADOOP_HOME=/opt/installs/hadoop2.9.2/
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
# zookeeper
export PATH=$PATH:/opt/installs/zookeeper3.4.14/bin/
2. 加载配置文件
source /etc/profile
# 3. 同步4台主机的其他配置
0. 设置ip
1. 远程拷贝安装软件
2. 加载配置文件 /etc/profile
3. 设置hostname(4个主机)
hostnamectl set-hostname xxxx
4. 设置hosts映射
192.168.153.30 hadoop30
192.168.153.31 hadoop31
192.168.153.32 hadoop32
192.168.153.33 hadoop33
5. 配置免密登录
# 生成密钥
[root@hadoop30 ~]# ssh-keygen
[root@hadoop31 ~]# ssh-keygen
# 发送公钥(所有NameNode节点都要发送)
[root@hadoop30 ~]# ssh-copy-id hadoop30
[root@hadoop30 ~]# ssh-copy-id hadoop31
[root@hadoop30 ~]# ssh-copy-id hadoop32
[root@hadoop30 ~]# ssh-copy-id hadoop33

[root@hadoop31 ~]# ssh-copy-id hadoop30
[root@hadoop31 ~]# ssh-copy-id hadoop31
[root@hadoop31 ~]# ssh-copy-id hadoop32
[root@hadoop31 ~]# ssh-copy-id hadoop33
zookeeper配置(3台)
# 1. 新建data文件夹
	data下myid给分配不同值
# 2. 配置conf下的zoo.cfg配置文件
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/opt/installs/zookeeper3.4.14/data #data文件目录
clientPort=2181
server.30=192.168.153.30:2888:3888 # zk主机信息
server.31=192.168.153.31:2888:3888 # zk主机信息
server.32=192.168.153.32:2888:3888 # zk主机信息
# 3. 拷贝配置信息到其他主机
[root@hadoop30 conf]# scp zoo.cfg root@hadoop31:/opt/installs/zookeeper3.4.14/conf/
[root@hadoop10 conf]# scp zoo.cfg root@hadoop32:/opt/installs/zookeeper3.4.14/conf/
# 4. 修改每个主机的myid
# 5. 启动zkServer验证是否成功。
1. 启动3台zk主机
zkServer.sh start
2. 查看状态
zkServer.sh status
3. 关闭zkServer
HAHadoop配置(HDFS)
# 0. data文件夹
1. 如果新安装的hadoop需要创建data文件夹
2. 如果是已经安装过的,之前旧的,需要删除data文件夹下的文件。
# 1. 配置hadoop-env.sh 
export JAVA_HOME=/opt/install/jdk1.8/
# 2. 配置core-site.xml
<configuration>
    <!--hdfs入口,设置虚拟地址,具体地址后面配置-->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://ns</value>
    </property>
    <!--hdfs集群的文件位置-->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/install/hadoop2.9.2/data</value>
    </property>
    <!--hdfs要访问zookeeper集群-->
    <property>
        <name>ha.zookeeper.quorum</name>
        <value>hadoop30:2181,hadoop31:2181,hadoop32:2181</value>
    </property>
</configuration>
# 3. 配置hdfs-site.xml
<configuration>
    <!-- 副本数 -->
    <property>
        <name>dfs.replication</name>
        <value>3</value>
    </property>
    <!-- 定义hdfs入口的命名服务 -->
    <property>
        <name>dfs.nameservices</name>
        <value>ns</value>
    </property>
    <!-- 定义hdfs入口的命名服务下虚拟ip-->
    <property>
        <name>dfs.ha.namenodes.ns</name>
        <value>nn1,nn2</value>
    </property>
    <!-- 虚拟ip地址1 RPC入口 -->
    <property>
        <name>dfs.namenode.rpc-address.ns.nn1</name>
        <value>hadoop30:9000</value>
    </property>
    <!-- 虚拟ip地址1 HTTP入口 -->
    <property>
        <name>dfs.namenode.http-address.ns.nn1</name>
        <value>hadoop30:50070</value>
    </property>
    <!-- 虚拟ip地址2 PRC入口 -->
    <property>
        <name>dfs.namenode.rpc-address.ns.nn2</name>
        <value>hadoop31:9000</value>
    </property>
    <!-- 虚拟ip地址1 HTTP入口 -->
    <property>
        <name>dfs.namenode.http-address.ns.nn2</name>
        <value>hadoop31:50070</value>
    </property>
    <!-- namenode要向zk的QJN写入editslog,所以要明确入口地址 -->
    <property>
        <name>dfs.namenode.shared.edits.dir</name>
        <value>qjournal://hadoop30:8485;hadoop31:8485;hadoop32:8485/ns</value>
    </property>
    <!-- 配置ZKFC故障切换 -->
    1.开启ZKFC
    2.要使用的zkfc故障切换的代码类
    3.故障切换杀死进程使用的方式
    4.指定免密登录的私钥地址
    <!-- 是否开启故障切换 -->
    <property>
        <name>dfs.ha.automatic-failover.enabled</name>
        <value>true</value>
    </property>
    <!-- 基于zookeeper的故障切换的代码类 -->
    <property>
        <name>dfs.client.failover.proxy.provider.ns</name>
        <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    </property>
    <!-- 远程杀死namenode方式(防止namenode假死,导致双主出现) -->
    <property>
        <name>dfs.ha.fencing.methods</name>
        <value>sshfence</value>
    </property>
    <!-- 指定私钥的文件目录,使用免密登录杀死NN进程 -->
    <property>
        <name>dfs.ha.fencing.ssh.private-key-files</name>
        <value>/root/.ssh/id_rsa</value>
    </property>
</configuration>
# 4. 配置slaves
hadoop31
hadoop32
hadoop33
# 5. 同步配置到其他主机上
[root@hadoop30 etc]# scp -r hadoop/ root@hadoop31:/opt/install/hadoop2.9.2/etc/
[root@hadoop30 etc]# scp -r hadoop/ root@hadoop32:/opt/install/hadoop2.9.2/etc/
[root@hadoop30 etc]# scp -r hadoop/ root@hadoop33:/opt/install/hadoop2.9.2/etc/
HAHadoop启动

先启动Zookeeper(30、31、32),再启动HDFS

启动顺序:zkServer—hdfs

# 1. 启动zookeeper(3台)
[root@hadoop30 etc]# zkServer.sh start
[root@hadoop31 etc]# zkServer.sh start
[root@hadoop32 etc]# zkServer.sh start
# 2. 初始化ZKFS故障切换进程(在namenode主节点)【第一次启动需要做】
[root@hadoop30 etc]# hdfs zkfc -formatZK
# 3. 启动qjournalnode进程。(3台)
	启动后可以查看journalenode节点进程
[root@hadoop30 etc]# hadoop-daemon.sh start journalnode
[root@hadoop31 etc]# hadoop-daemon.sh start journalnode
[root@hadoop32 etc]# hadoop-daemon.sh start journalnode
# 4. 格式化hdfs主机namenode(在namenode主节点)【第一次启动需要做】
hdfs namenode -format ns
# 5. 启动hdfs集群(namenode主节点)
# 因为配置了HA HDFS的zkfc,所以,会自动启动zkfc故障切换进程
start-dfs.sh
# 6. 格式化hdfs的namenode备机(namenode standby备节点)【第一次启动需要做】
[root@hadoop31 ~]# hdfs namenode -bootstrapStandby
# 7. 启动hdfs的namenode备机(namenode standby备节点)
[root@hadoop31 ~]# hadoop-daemon.sh start namenode
进程图如下

在这里插入图片描述

验证
# 1. 查看两个namenode状态
	一个active一个standby
# 2. kill掉active
	active失效,standby转为active
# 3. 重启namenode,发现启动后变成standby
	hadoop-daemon.sh start namenode
# 4. namenode主机添加文件后,杀死,看另一个namenode也有数据,高可用实现。
Java程序访问
package demo4;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;

public class HDFSHaTest {
    public static void main(String[] args) throws IOException {
        Configuration conf = new Configuration();
        conf.addResource("/core-site.xml");
        conf.addResource("/hdfs-site.xml");
        FileSystem fs = FileSystem.get(conf);
        FileStatus[] files = fs.listStatus(new Path("/hdfs"));
        for (FileStatus file : files) {
            System.out.println(file.getPath());
            System.out.println(file);
        }
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值