第七天 - HDFS概述、命令操作 - JAVA操作HDFS - 集群间时间同步、手动修复

第七天 - HDFS概述、命令操作 - JAVA操作HDFS - 集群间时间同步、手动修复

一、HDFS概述

HDFS概述

hdfs源于Google的GFS论文,是GFS的克隆版译为易于扩展的分布式文件系统,可以运行在大量的普通廉价机器上。hadoop,离线计算框架,数据很少会发生变化。当数据发生变化时,通过操作hdfs的方式进行数据同步,在hadoop中提供数据存储服务,具备数据管理功能/数据不丢失(冗余存储)。

hadoop进行数据运算时是以分布式的方式进行:任务分发 -> 资源调配 -> 结果同步,所以在对小数据量的处理时,从主观来看会感觉使用分布式计算反而比单机计算更慢,这是因为时间花费在了任务分发、结果同步上,;然而,当数据量足够大时,就能体现出分布式计算的优势了。

hdfs可以使得在数据计算时,数据的读取变得高效,提高计算的效率,同时可以作为多个数据计算框架数据存储支持,例如hive、hbase等。

HDFS优缺点
  • 优点
    • 高可靠性:存储和处理数据的能力
    • 高扩展性:可以在可用的计算机集群间分配数据来完成计算任务,并可以扩展到数以千计的节点中
    • 高效性:能够在各个节点之间动态移动数据,保证各个节点的动态平衡以提升速度
    • 高容错性:能够自动保存数据的多个副本,并能够将失败的任务重新分配
  • 缺点
    • 不适合低延迟的数据访问
    • 无法高效存储大量的小文件
    • 不支持多用户写入及修改文件
HDFS核心思想及作用
  • 分而治之:将大文件、大批量文件,分布式存放在大量服务器上,可以快速高效的对海量数据进行运算分析
  • 可以为各类的分布式运算框架(MapReduce,Spark等)提供数据存储服务
  • 本质上是一个分布式文件系统,用于存储和管理文件,由多台服务器联合起来实现分布式的功能,在每个服务器上可以负责不同的工作内容

如果一个集群中有100台节点:40台做数据存储,60台做数据运算

40台用于数据存储提升数据稳定性,例如使用商用固态硬盘/弹性块存储等高性能存储设备

60台应用于数据运算,需要提升提升CPU、内存性能

这100台节点都需要保证足够的带宽,否则带宽将会是这个集群分布式计算的瓶颈

重要特性
  • HDFS在物理上是分块存储,块的大小可以通过配置文件来指定,在2.x版本中是128M
  • HDFS文件系统会给客户端提供一个统一的抽象目录树,通过hdfs协议的路径来访问文件或文件夹
  • 由namenode节点来管理目录结构及文件分块信息(元数据),也是集群的主节点,负责维护整个文件系统的目录树以及每一个路径所对应的block信息
  • 由datanode节点来管理文件的block存储,也是集群的从(子)节点,每一个block都可以在多个datanode上存储多个副本

二、HDFS工作原理

概述

1536043721824

  • NameNode负责管理整个文件系统的元数据
  • DataNode负责管理用户存储文件的数据块
  • 文件会按照预先指定的块大小被切成若干块后分布式存储在若干台DataNode上
  • 每一个文件快可以有多个副本,并存放在不同的DataNode上
  • DataNode会定期向NameNode汇报自身保存的文件block信息,NameNode负责保持文件的副本数量
  • 在用户使用时不需要关心HDFS的内部工作步骤,直接通过一个地址进行操作

使用流修改文件内容时,首先打开一个流,不断的读取文件信息,定位修改,通常不会直接修改

通常是以文件导入的方式将数据导入HDFS,将计算得到的数据(小数据量)进行读取,结果的展示

数据读取过程

1536043936017

  1. 客户端通过命令或调用FileSystem对象的open方法打开需要读取的文件
  2. NameNode接收指令后,确定文件的block的基本信息
  3. DataNode进行排序,如果客户端就是在一台DataNode上执行则直接从本地读取数据。
  4. 确定数据节点后会返回一个FSDataInputStream对象,从中读取数据
  5. 使用read方法以流的方式从文件中读取数据
  6. 当达到block文件末尾时,FSDataInputStream会关闭当前连接,继续读取下一个block文件
  7. 循环读取过程,直至读取整个文件,关闭FSDataInputStream
数据写入过程

1536044027682

  1. 客户端通过调用create()方法来请求创建文件
  2. NameNode会对该操作进行校验,包括文件系统中是否已经存在该文件,以及是否有相应的权限进行创建
  3. 如果校验通过,NameNode会记录该文件信息,返回一个FSDataOutputStream对象,用于数据写入
  4. FSDataOutputStream会把要写入的数据分成包的形式,写入到中间队列
  5. DataStreamer用于将数据包中的数据分别写入到各个DataNode中
  6. 在FSDataOutputStream中维护了一个packets队列,其中存放了等待被每个DataNode确认的packets信息
  7. 一个packets信息被移出本队列当且仅当所有的DataNode都确认无误
  8. 当数据完成后会调用close方法,会flush残留的packets,通知NameNode等待确认信息
Hadoop增删节点
  • 静态添加

    停止集群,修改节点配置文件(slaves),启动集群

    • 优点:操作简单,改动较少
    • 缺点:去要重启集群
    • 应用场景:每天有固定的重启时间
  • 动态添加

    在集群运行过程中进行变更,在新机器上配置好环境,同步各集群的hosts文件和slaves文件

    在新节点中使用如下命令进行启动

    sbin/hadoop-daemon.sh start datanode

    sbin/yarn-daemon.sh start nodemanager

    • 优点:不需要重启集群
    • 缺点:改动量较大时比较繁琐
    • 应用场景:需要持续不断的提供服务
NameNode详解

负责处理客户端的请求,元数据的查询和修改

  • 启动过程

    • 首先将fsimage(镜像载入内存),并执行和editlog相关的各项操作
    • 在内存中建立元数据映射,则创建一个新的fsimage文件和一个空的editlog
    • 在安全模式下,DataNode会向NameNode发送块列表的最新情况
    • 在安全模式中,文件系统对于客户端是只读的
    • 完成以上操作后开启监听RPC和HTTP请求,并退出安全模式

    1536045831654

  • 元数据管理

    • NameNode的两个重要文件:fsimage-元数据镜像文件,edits-元数据操作日志
    • 元数据镜像:内存中为最新的=fsimage+edits
    • 定期合并fsimage和edits:由SecondaryNameNode,保证稳定运行以及NameNode重启速度

    1536045885009

  • 安全模式

    一个新创建的集群不会进入安全模式,重新启动一个已有的集群,通常会有短暂的安全模式时间,用于完成合并和初始化的操作

    • 查询当前是否处于安全模式

    hadoop dfsadmin -safemode get

    • 等待安全模式关闭

    hadoop dfsadmin -safemode wait

    • 退出安全模式

    hadoop dfsadmin -safemode leave

    • 启用安全模式

    hadoop dfsadmin -safemode enter

三、HDFS命令操作

Web监控

浏览器中输入地址SZ01:50070

1536046367579

可以在这个网页中查看集群信息等,也可以在上图的位置找到查看hdfs文件系统的页面,可以将hdfs中的文件下载至Windows本地;

在浏览器中直接下载文件时,传输数据的datanode是随机的,通常需要对每一台每一台机器配置hosts映射(Windows下),当机器数量较多时,可以手动修改主机名为IP,再重新发送请求。

1536031988636

使用命令操作HDFS

两种命令格式:

hadoop fs -command path

hdfs dfs -command path

command为操作命令,上传、下载、删除、查看、移动、复制文件等,命令与Linux下的命令几乎相同

path为操作路径,hdfs根路径为hdfs://host:8020/,使用时可直接简写为/

hdfs也有绝对路径和相对路径,但一般使用时使用绝对路径,即从/开始

  • 查看hdfs系统中存在的文件的命令:ls

    hdfs dfs -ls path:查看path路径下的文件

    hdfs dfs -lsr path = hdfs dfs -ls -R path:递归查看path路径下的文件

  • 上传文件至hdfs命令:put(copyFromLocal)

    hdfs dfs -put src(Linux文件系统) dest(HDFS文件系统)

    hdfs dfs -put .bash_profile /

    1536031895401

    1536031906227

  • 查看hdfs中文件内容:cat

    hdfs dfs -cat file

    hdfs dfs -cat /.bash_profile

    1536032184637

  • 从hdfs下载文件命令:get(copyToLocal)

    hdfs dfs -get src(HDFS文件系统) dest(Linux文件系统)

    hdfs dfs -get /.bash_profile /tmp

    1536032724810

    1536032740739

  • 删除hdfs中文件、文件夹命令:rm rmdir

    hdfs dfs -rm file:删除文件

    hdfs dfs -rmdir emptyDir:删除空文件夹

    hdfs dfs -rm -r notEmptyDir:删除非空文件夹

    在hdfs-site.xml中配置了删除文件时并不是立即删除,而是现将文件移至某一文件夹,60分钟后彻底删除

    hdfs dfs -rm /.bash_profile

    1536041268231

    1536041341464

  • 创建文件夹:mkdir

    hdfs dfs -mkdir dirPathName:指定路径和名字创建文件夹

    hdfs dfs -mkdir /input

    hdfs dfs -mkdir /output

    hdfs dfs -mkdir test

    1536041440710

    1536041471272

  • 移动文件(夹):mv

    hdfs dfs -mv src(源) dest(目标)

    hdfs dfs -mv /test.txt /s1/

    1536053365475

  • 复制文件(夹):cp

    hdfs dfs -cp src(源) dest(目标)

    hdfs dfs -cp /s1/test.txt /s1/s2/

    1536053502927

  • 更改文件(夹)权限:chmod

    hdfs dfs -chmod [-R] xxx file(dir)

    hdfs dfs -chmod 777 /s1/test.txt

    1536053621122

四、JAVA操作HDFS

在Windows下通过java操作服务器中的hdfs时,需要进行安装hadoop,配置环境变量,在项目中引入所需jar包,解决环境问题等操作

JUnit单元测试工具

此工具可以直接执行某一个方法:不能有参数,不能有返回值

原理:调用无参的构造方法,再去调用声明测试的方法

使用方法:添加库,在要测试的方法前引入@Test注释,右键运行时选择JUnit Test

通常测试时只会指定一个方法进行测试

使用步骤:右键项目,build Path,configure Build Path,切换至Library,add Library,Junit

1536047495447

  • 检验JUnit原理测试代码:

1536047648327

@Test
    public void getHomeDir() {
    //输出当前家目录
        System.out.println(fs.getHomeDirectory());
    }

1536047666276

准备
  • Windows下配置hadoop

    1. 将hadoop-2.7.2.tar.gz通过解压缩软件解压至目录(一般解压至软件安装目录)

    2. 右键此电脑 -> 高级系统设置 -> 环境变量,在系统变量一栏选择新建

      1536054044335

    3. 变量名为HADOOP_HOME,变量值为第1步中解压的路径

      1536054068038

  • 解决运行MapReduce时因环境而报错(为之后编写MapReduce代码做准备)

    1. 新建包org.apache.hadoop.io.nativeio

    2. 将修改后的NativeIO.java粘贴到包内

      1536058841992

    3. 此时import有报错,原因是eclipse默认设置将禁止的引用进行报错,需要进行处理

      1536050096457

    4. 将禁止的引用改成警告,如下图进行设置:

      1536050149046

eclipse编写代码
解决环境问题

编写代码前,先将winutil.exe和hadoop.dll等文件拷贝至$HADOOP_HOME/bin目录下,并且将hadoop.dll拷贝至System32及SysWOW64目录下。双击运行winutil.exe,如果没报错即成功,如果报错,则需使用类库修复工具修复(具体可百度方法),完成后重启电脑

压缩包可从点击此处下载

1536044658231

编写代码前的准备
  1. 新建java项目,在项目下新建文件夹lib

  2. 在hadoop解压目录下拷贝以下jar包粘贴至项目的lib文件夹中

    $HADOOP_HOME/share/hadoop/common/hadoop-common-2.7.2.jar和hadoop-nfs-2.7.2.jar1536042465447

    $HADOOP_HOME/share/hadoop/common/lib中全部jar包$HADOOP_HOME/share/hadoop/hdfs/hadoop-hdfs-2.7.2.jar和hadoop-hdfs-nfs-2.7.2.jar1536042488968$HADOOP_HOME/share/hadoop/hdfs/lib中全部jar包

  3. 在eclipse中全选lib目录下的jar包,右键选择Build Path -> Add to Build Path(添加至构建路径)

  4. 将$HADOOP_HOME/etc/hadoop/log4j.properties拷贝至src根目录下

    将第18行中hadoop.root.logger=INFO改成DEBUG,这样在运行项目后输出的信息会以debug信息输出,否则有些报错信息未能输出,不利于调试

    1536045303877

编写第一个测试代码,测试连接是否成功
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;

public class Test01 {
    // 初始化配置对象
    private static Configuration conf = new Configuration();
    // 声明需要访问的集群地址
    private final static String URI = "hdfs://SZ01:8020/";
    // 声明操作文件系统的类
    private static FileSystem fs;

    static {
        try {
            // 从制定集群中读取配置
            FileSystem.setDefaultUri(conf, URI);
            // 使用读取到的配置实例化fs
            fs = FileSystem.get(conf);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // TODO 使用Java操作HDFS
        // 输出默认的block块大小
        System.out.println(fs.getDefaultBlockSize());
    }
}

运行成功后输出结果为:

1536043286129

  • 下图中的设置为查看源码时使用反编译工具

1536047051652

创建多级目录
    // 同时创建多级目录
    public void mkdirs() {
        try {
            fs.mkdirs(new Path("t1/t2"));
            fs.mkdirs(new Path("/s1/s2"));
        } catch (IllegalArgumentException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }

1536048052209

上传本地文件至hdfs

上传文件通常是客户端通过web应用进行上传操作,将文件上传到linux本地磁盘,再上传至hdfs(指定删除源文件,指定不覆盖目标文件)

// 上传本地文件至hdfs
    public void upLoad() {
        try {
            // 两个参数:本地文件路径和hdfs目录
            fs.copyFromLocalFile(new Path("G://test/test.txt"), new Path("/"));
        } catch (IllegalArgumentException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }

1536048266786

从hdfs下载文件至本地
// 从hdfs下载文件至本地
    public void downLoad() {
        try {

            fs.copyToLocalFile(false, new Path("/text.txt"), new Path("E://"), true);
        } catch (IllegalArgumentException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        } catch (IOException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }

1536048721556

HDFSUtil工具类的封装
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class HDFSUtil {

    /**
     * 初始化工具类,指定需要操作的集群
     * @param hostName
     */
    public HDFSUtil(String hostName) {
        URI = "hdfs://" + hostName + ":8020";
        try {
            // 将URI信息记录到配置项中
            FileSystem.setDefaultUri(conf, URI);
            // 使用读取到的配置实例化fs
            fs = FileSystem.get(conf);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 初始化配置对象
    private static Configuration conf = new Configuration();
    // 声明需要访问的集群地址
    private static String URI = "";
    // 声明操作文件系统的类
    private static FileSystem fs;

    /**
     * 返回当前用户的家目录
     * @return
     */
    public String getHomeDir() {
        // 当前用户的家目录
        return fs.getHomeDirectory().toString();
    }

    /**
     * 创建文件夹
     * @param path 完整路径,不需要添加斜杠
     * @param useHomeDir 是否在用户家目录中创建
     */
    public void mkdirs(String path, boolean useHomeDir) {
        // 同时创建多级目录
        try {
            if (useHomeDir) {
                fs.mkdirs(new Path(path));
            } else {
                fs.mkdirs(new Path("/" + path));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件上传
     * @param delSrc 是否删除源文件
     * @param overwrite 是否覆盖目标文件
     * @param srcs 源文件路径,可以指定多个路径
     * @param dest 目标路径
     */
    public void upLoad(boolean delSrc, boolean overwrite, String[] srcs, String dest) {
        try {
            // fs.copyFromLocalFile(false, src, dst);
            // 四个参数,是否删除源文件,是否覆盖目标文件,源路径,目标路径,声明不覆盖时抛出异常(不会发生覆盖)
            // fs.copyFromLocalFile(false, false, new Path("E://test.txt"), new Path("/"));
            // 上传单个文件时,直接上传
            if (srcs.length == 1) {
                fs.copyFromLocalFile(delSrc, overwrite, new Path(srcs[0]), new Path("/"));
            } else {
                // 上传多个文件时,生成所需的Path数组
                Path[] paths = new Path[srcs.length];
                for (int i = 0; i < srcs.length; i++) {
                    paths[i] = new Path(srcs[i]);
                }
                fs.copyFromLocalFile(delSrc, overwrite, paths, new Path("/"));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件下载
     * @param delSrc 是否删除源文件
     * @param src 源文件路径
     * @param dest 目标路径
     */
    public void downLoad(boolean delSrc,String src,String dest) {
        try {
            // 四个参数,是否删除源文件,源路径,目标路径,是否使用原生的系统文件系统
            fs.copyToLocalFile(delSrc, new Path(src), new Path(dest), true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

五、还原快照后的处理

在集群中单台机器出现了误操作后导致系统不能正常运行,此时需要还原快照,如果没有快照则需重装系统。

还原快照后需要对三台机器的时间进行同步,否则hadoop集群无法进行正常工作。

同步时间的步骤:

  1. 所有机器切换至root用户

    su - root

  2. 打开Xshell的发送键输入到所有会话的功能,输入以下命令

    date -s ‘201x-xx-xx xx:xx:xx’

    时间同步完成后,重启hadoop进程,即执行以下两步命令

stop-all.sh

start-all.sh

重启hadoop进程成功后,hadoop会对恢复快照的机器尝试自动检测和修复。

如果hadoop自动修复失败,即恢复快照的机器访问hdfs文件系统时跟其他机器访问hdfs所得到的结果不同,则需进行手动修复。

手动修复步骤:

  1. 损坏机器与正常机器都进入配置的datanode文件夹

    cd hadoop/data/dfs/dn/current/BP-1387956734-192.168.128.121-1535966538843/current/finalized/subdir0/subdir0/

  2. 对比损坏机器与正常机器该目录下的文件情况,将正常机器多出来的文件复制到损坏的机器上,复制方式可以通过scp发送,或者Xftp先下载至本地再上传

手动修复后需要重启hadoop进程,此时修复完成。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值