Hadoop原理汇总(一)——HDFS

原文章链接: https://blog.csdn.net/u010255818/article/details/72730864

摘要:本文主要对hadoop的原理性知识进行汇总,包括核心组件、HDFS存储原理、HDFS shell命令、HDFS Java端API、MapReduce基本原理、shuffle基本原理、sort过程等。


1 Hadoop核心组件

  1. 生态系统图 
    这里写图片描述

  2. HDFS文件系统 
    它是一个高度容错的系统,能检测和应对硬件故障,用于在低成本的通用硬件上运行。HDFS简化了文件的一致性模型,通过流式数据访问,提供高吞吐量应用程序数据访问功能,适合带有大型数据集的应用程序。 
    这里写图片描述 
    ● Client:切分文件;与NameNode交互,获取文件位置信息;与DataNode交互,读取和写入数据。 
    ● NameNode:管理HDFS的文件命名空间,处理客户端请求。 
    ● DataNode:存储实际的数据,汇报存储信息给NameNode。 
    ● Secondary NameNode:定期合并NameNode的fsImage(文件镜像)和fsEdits(操作日志),推送给NameNode;可辅助恢复NameNode。

  3. MapReduce分布式计算框架 
    Map对数据集上的独立元素进行指定的操作,生成键-值对形式中间结果。Reduce则对中间结果中相同 “键”的所有“值”进行规约,以得到最终结果。 
    这里写图片描述 
    JobTracker:管理所有作业,将任务分解成一系列任务,并分派给TaskTracker。 
    TaskTracker:运行Map Task和Reduce Task;并与JobTracker交互,汇报任务状态。 
    Map Task:解析每条数据记录,传递给用户编写的map(),将输出结果写入本地磁盘。 
    Reducer Task:从Map Task的执行结果中,远程读取输入数据,对数据进行排序,将数据按照分组传递给用户编写的reduce函数执行。 
    这里写图片描述

  4. Hive数据仓库 
    Hive定义了一种类似SQL的查询语言(HQL),将SQL转化为MapReduce任务在Hadoop上执行。通常用于离线分析 
    这里写图片描述

  5. HBase数据库 
    HBase 是一个面向列的动态模式数据库,键由行关键字、列关键字和时间戳构成。HBase提供了对大规模数据的随机、实时读写访问,HBase中保存的数据可以使用MapReduce来处理,它将数据存储和并行计算完美地结合在一起。 
    数据模型:Schema-->Table-->Column Family-->Column-->RowKey-->TimeStamp-->Value 
    这里写图片描述

  6. zookeeper分布式协作服务 
    解决分布式环境下的数据管理问题:统一命名,状态同步,集群管理,配置同步等

  7. sqoop数据同步工具 
    Sqoop是SQL-to-Hadoop的缩写,主要用于传统数据库和Hadoop之前传输数据。 
    数据的导入和导出本质上是Mapreduce程序,充分利用了MR的并行化和容错性。

  8. pig数据流系统 
    设计动机是提供一种基于MapReduce的ad-hoc(计算在query时发生)数据分析工具 
    定义了一种数据流语言—Pig Latin,将脚本转换为MapReduce任务在Hadoop上执行。 
    通常用于进行离线分析

  9. Mahout数据挖掘算法库 
    Mahout 的主要目标是创建一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序。Mahout现在已经包含了聚类、分类、推 荐引擎(协同过滤)和频繁集挖掘等广泛使用的数据挖掘方法。除了算法,Mahout还包含数据的输入/输出工具、与其他存储系统(如数据库、 MongoDB 或Cassandra)集成等数据挖掘支持架构。

  10. Flume日志收集工具 
    将数据从产生、传输、处理并最终写入目标的路径的过程抽象为数据流。在具体的数据流中,数据源支持在Flume中定制数据发送方,从而支持收集各种不同协议数据。同时,Flume数据流提供对日志数据进行简单处理的能力,如过滤、 格式转换等。此外,Flume还具有能够将日志写往各种数据目标(可定制)的能力。

2 HDFS存储原理

2.1 HDFS整体结构

这里写图片描述

(1)NameNode 
  管理数据节点和文件块的映射关系;处理客户端对数据的读写请求。 
  NameNode保存了两个核心的数据结构FsImage和EditLog。FsImage用于维护文件系统树以及元数据;EditLog记录了文件的操作。NameNode不持久化Block与DataNode的映射信息,而是在系统每次启动时扫描所有DataNode来重构这些信息。

(2)DataNode 
  负责数据的存储和读取;向NameNode定期发送自己的存储块信息;周期性地向NameNode发送心跳信息报告自己的状态。 
  HDFS集群中只有一个NameNode,负责所有元数据的管理;有若干DataNode,每个DataNode运行在一个独立节点上。

(3)SecondaryNameNode 
  对NameNode进行备份。周期性地从NameNode下载EditLog与FsImage,将EditLog与FsImage合并得到FsImage.ckpt,将合并后的FsImage.ckpt上传到NameNode,更新NameNode的EditLog与FsImage。

(4)读写过程 
  客户端向HDFS写文件时,先请求NameNode节点获取分配的存储位置,然后根据存储位置直接把数据写入DataNode;客户端向HDFS读数据时,先请求NameNode获取文件块和数据节点的映射关系,然后直接到数据节点访问相应位置的文件块

2.2 关于Block大小

(1)HDFS默认文件块Block大小为64MB,如果一个文件小于Block,则它并不占用整个Block空间大小。

(2)Block不宜过大,MapReduce的Map任务一次只能处理一个Block的数据,Block过大会使启动的Map数量过少,影响并行处理速度。

(3)HDFS无法高效存储大量小文件

检索效率:HDFS中NameNode的元数据保存在内存中,过多的小文件需要大量内存空间,降低数据检索效率; 
寻址开销:访问大量小文件,需要不断从一个DataNode跳到另一个DataNode,寻址开销增大; 
线程开销:MapReduce处理大量小文件时会产生过多的Map任务,线程管理开销会大大增加;

2.3 HDFS数据存取策略

(1)数据存放 
  HDFS默认冗余参数是3,一个Block会保存在3个地方。两份副本存放在同一机架的不同机器上,第三个副本存放在不同机架的机器上,即保证高可靠性,又提高读写性能。 
(2)数据读取 
  客户端从名称节点获取不同副本的存放位置列表,当发现有数据副本的机架与客户端机架相同时,优先选择该副本;否则,随机选取一个副本。 
(3)数据复制 
  采用流水线复制策略。Client向HDFS写文件时,先将文件写到本地,并切分成若干块,每个块都向NameNode发送写请求。Client根据DataNode的使用情况,返回一个节点列表给客户端。客户端把数据首先写入第一个DataNode,同时把节点列表传给第一个DataNode;当第一个DataNode接收4KB数据时,写入本地,并向列表的第二个DataNode发起连接,把接收到的4KB数据和节点列表传给第二个DataNode;依次列推,列表中的多个数据节点形成一条数据复制流水线。当文件写完时,数据复制也同时完成。

2.4 数据错误与恢复

NameNode出错:利用SecondaryNode中的FsImage与EditLog数据进行恢复

DataNode出错:DataNode定期向NameNode发送心跳信息报告自己的状态,超时未收到心跳信息会被标记为宕机,该DataNode不再可用。NameNode一旦发现某个Block的副本数量小于冗余因子,则对数据进行冗余复制。

数据出错:网络传输与磁盘错误等因素均会造成数据错误。读取数据时,客户端会采用MD5和shal对数据块进行校验;写数据时,将文件块的信息摘录写入同一路径的隐藏文件,在读取时进行校验,如果校验失败则请求读取另一副本,并报告NameNode。

3 HDFS的Shell操作

HDFS的shell操作中部分基于hadoop工具的操作已经被hdfs工具替代,但仍有一些基于hadoop工具的操作未被替代。 
(1)hdfs工具 
这里写图片描述

(2)hadoop工具 
这里写图片描述

(3)主要命令

hdfs namenode -format                           格式化DFS文件系统
hdfs [namenode | secondaryNameNode | datanode]  启动命令
hdfs dfsadmin -safemode [enter | leave]         进入或退出安全模式

这里写图片描述

hdfs balancer                                   手动负载均衡
hdfs getconf [-namenodes | -secondaryNameNodes | -backupNodes | -nnRpcAddresses]    获取配置信息

hadoop 
hadoop jar <xx.jar> <mainClass> [args, args]        运行jar文件
hadoop fs                                   运行通用文件系统用户客户端
hdfs dfs                                        运行hadoop支持的文件系统命令

hadoop fs命令参数与hdfs dfs命令参数完全一致,HDFS中hdfs dfs工具替代了hadoop fs工具: 
这里写图片描述

4 HDFS Java端API

(1)Configuration类

public class Configuration extends Object implements Iterable<Map.Entry<String,String>>, Writable {
// 提供配置参数,如果没有具体指明,hadoop从core-site.xml中获取配置信息
    //构造方法
    public Configuration() {}
    public Configuration(Configuration conf) {}
    public Configuration(boolean loadDefaults) {}//是否从默认文件core-site.xml中读取配置信息

    //set与get
    public String get(String name) {}//根据属性名获取值,属性不存在时返回null
    public String get(String name, String defaultValue){}
    public void set(String name, String value) {}

    //迭代遍历
    public Iterator<Map.Entry<String,String>> iterator(){}
}

(2)FileSystem 
第一个无参构造方法返回默认文件系统,即core-site.xml中fs.defaultFS项,若未设置则默认返回本地文件系统;其他带URI参数的构造方法通过URI参数指定文件系统。

public abstract class FileSystem extends Configured implements Closeable {
//通用文件系统的抽象基类
    //工厂模式,获取实例
    public static FileSystem get(Configuration conf) throws IOException {}
    public static FileSystem get(URI uri, Configuration conf, String user) throws IOException
    public static FileSystem get(URI uri, Configuration conf) throws IOException {}
    public static LocalFileSystem getLocal(Configuration conf) throws IOException {}
    public static FileSystem newInstance(URI uri, Configuration conf) throws IOException

    //创建输出/输入流对象
    public FSDataOutputStream create(Path f, boolean overwrite, int bufferSize) throws IOException
    public FSDataInputStream open(Path f) throws IOException
    public FSDataOutputStream append(Path f, int bufferSize) throws IOException
    public void concat(Path trg, Path[] psrcs) throws IOException{} //Concat existing files together

    //文件移动
    public void moveFromLocalFile(Path src, Path dst) throws IOException{} //从本地向HDFS移动文件
    public void moveToLocalFile(Path src, Path dst) throws IOException{} //从HDFS向本地移动文件
    public void copyFromLocalFile(boolean delSrc, boolean overwrite, Path src, Path dst) throws IOException{} //从本地向HDFS复制文件
    public void copyToLocalFile(boolean delSrc, Path src, Path dst) throws IOException{} //从HDFS向本地复制文件
    public abstract boolean rename(Path src, Path dst) throws IOException{} //在本地磁盘间或HDFS之间移动文件,即重命名

    //判断方法
    public boolean exists(Path f) throws IOException{} //判断文件或目录是否存在
    public boolean isDirectory(Path f) throws IOException{}
    public boolean isFile(Path f) throws IOException{}

    //创建目录
    public boolean mkdirs(Path f) throws IOException{}

    //删除文件或目录
    public abstract boolean delete(Path f, boolean recursive) throws IOException

    //获取文件统计信息
    public FsStatus getStatus(Path p) throws IOException
    public FileStatus[] listStatus(Path f, PathFilter filter) throws FileNotFoundException, IOException

    //关闭
    public void close() throws IOException{}
}

(3)FSDataInputStream,继承自java.io.DataInputStream

public class FSDataInputStream extends DataInputStream implements...{
    //构造方法
    public FSDataInputStream(InputStream in) {}

    //读指针相关方法
    public void seek(long desired) throws IOException{}
    public long getPos() throws IOException{}

    //读操作
    public int read(long position, byte[] buffer, int offset, int length) throws IOException
    public void readFully(long position, byte[] buffer, int offset, int length) throws IOException
    /*read(byte[] b)方法实质是读取流上的字节直到流上没有字节为止,如果当声明的字节数组长度大于流上的数据长度时就提前返回,
    而readFully(byte[] b)方法是读取流上指定长度的字节数组,也就是说如果声明了长度为len的字节数组,
    readFully(byte[] b)方法只有读取len长度个字节的时候才返回,否则阻塞等待,如果超时,则会抛出异常 EOFException*/
}

(4)FSDataOutputStream,继承自java.io.DataOutputStream

public class FSDataOutputStream extends DataOutputStream implements...{
//写方法全部继承自父类
}

(5)FileStatus

public class FileStatus{
    //构造方法
    public FileStatus(){}

    //判断方法
    public boolean isFile(){};
    public boolean isDirectory(){};

    //get方法
    public long getLen(){};
    public long getBlockSize(){};
    public short getReplication(){};
    public String getOwner(){};

    public Path getPath(){};

    //set方法
    public void setPath(Path p){};
    protected void setOwner(String owner){};
}

(6)Path

public class Path extends Object implements Comparable {
    //构造方法
    public Path(String parent, String child){}
    public Path(URI uri){}

    //合并路径
    public static Path mergePaths(Path path1, Path path2) {}

    public URI toUri(){};

    //get方法
    public FileSystem getFileSystem(Configuration conf) throws IOException {}
    //该方法可获取fs对象,在输出路径存在的情况下删除输出路径

    public String getName(){} //Returns the final component of this path
    public Path getParent(){} //Returns the parent of a path or null if at root

    //判断方法
    public boolean isAbsolute(){};
    public boolean isRoot(){};
}
  • (7)URI,java.net.URI
public final class URI extends Object implements Comparable<URI>, Serializable {
    //构造方法
    public URI(String str) {};
    public URI(String scheme, String host, String path, String fragment) {};
}

(8)PathFilter

public interface PathFilter{
    boolean accept(Path path);
}

猜你喜欢

转载自blog.csdn.net/weixin_42486549/article/details/82222871