原文章链接: https://blog.csdn.net/u010255818/article/details/72730864
摘要:本文主要对hadoop的原理性知识进行汇总,包括核心组件、HDFS存储原理、HDFS shell命令、HDFS Java端API、MapReduce基本原理、shuffle基本原理、sort过程等。
1 Hadoop核心组件
-
生态系统图
-
HDFS文件系统
它是一个高度容错的系统,能检测和应对硬件故障,用于在低成本的通用硬件上运行。HDFS简化了文件的一致性模型,通过流式数据访问,提供高吞吐量应用程序数据访问功能,适合带有大型数据集的应用程序。
● Client:切分文件;与NameNode交互,获取文件位置信息;与DataNode交互,读取和写入数据。
● NameNode:管理HDFS的文件命名空间,处理客户端请求。
● DataNode:存储实际的数据,汇报存储信息给NameNode。
● Secondary NameNode:定期合并NameNode的fsImage(文件镜像)和fsEdits(操作日志),推送给NameNode;可辅助恢复NameNode。 -
MapReduce分布式计算框架
Map对数据集上的独立元素进行指定的操作,生成键-值对形式中间结果。Reduce则对中间结果中相同 “键”的所有“值”进行规约,以得到最终结果。
JobTracker:管理所有作业,将任务分解成一系列任务,并分派给TaskTracker。
TaskTracker:运行Map Task和Reduce Task;并与JobTracker交互,汇报任务状态。
Map Task:解析每条数据记录,传递给用户编写的map(),将输出结果写入本地磁盘。
Reducer Task:从Map Task的执行结果中,远程读取输入数据,对数据进行排序,将数据按照分组传递给用户编写的reduce函数执行。 -
Hive数据仓库
Hive定义了一种类似SQL的查询语言(HQL),将SQL转化为MapReduce任务在Hadoop上执行。通常用于离线分析 -
HBase数据库
HBase 是一个面向列的动态模式数据库,键由行关键字、列关键字和时间戳构成。HBase提供了对大规模数据的随机、实时读写访问,HBase中保存的数据可以使用MapReduce来处理,它将数据存储和并行计算完美地结合在一起。
数据模型:Schema-->Table-->Column Family-->Column-->RowKey-->TimeStamp-->Value
-
zookeeper分布式协作服务
解决分布式环境下的数据管理问题:统一命名,状态同步,集群管理,配置同步等 -
sqoop数据同步工具
Sqoop是SQL-to-Hadoop的缩写,主要用于传统数据库和Hadoop之前传输数据。
数据的导入和导出本质上是Mapreduce程序,充分利用了MR的并行化和容错性。 -
pig数据流系统
设计动机是提供一种基于MapReduce的ad-hoc(计算在query时发生)数据分析工具
定义了一种数据流语言—Pig Latin,将脚本转换为MapReduce任务在Hadoop上执行。
通常用于进行离线分析 -
Mahout数据挖掘算法库
Mahout 的主要目标是创建一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序。Mahout现在已经包含了聚类、分类、推 荐引擎(协同过滤)和频繁集挖掘等广泛使用的数据挖掘方法。除了算法,Mahout还包含数据的输入/输出工具、与其他存储系统(如数据库、 MongoDB 或Cassandra)集成等数据挖掘支持架构。 -
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);
}