工作中经常用到hadoop,对于底层原理却不甚清楚,这里深入追究一下。
Hadoop是一个分布式系统基础架构,由许多元素构成。如下图,它最核心的包括并行计算模型Map/Reduce,分布式文件系统HDFS,以及分布式数据库Hbase。
HDFS(Hadoop分布式文件系统)
一个高度容错的分布式存储系统,能检测和应对硬件故障。存储在 HDFS 中的文件被分成块(块大小通常为 64MB),这些块复制到多个本次磁盘中(DataNode)。(一般复制3个,第1、2个块存储在同一集群的不同节点上,第3个块存储在不同集群的节点上)。块的大小和复制的块数量在创建文件时由客户机决定。NameNode 可以控制所有文件操作。HDFS内部通信都基于 TCP/IP 协议。
Client:切分文件;访问HDFS;与NameNode交互,获取文件位置信息;与DataNode交互,读取和写入数据。
NameNode:Master节点,在hadoop低版本中只有一个,管理HDFS的文件名称空间和数据块映射信息,配置副本策略,处理客户端请求。
DataNode:Slave节点,存储实际的数据,响应来自 NameNode 的创建、删除和复制块的命令。定期发送心跳(heartbeat)消息给NameNode 验证块映射和其他文件系统元数据。如果 DataNode 不能发送心跳消息,NameNode 默认采取修复措施,重新复制在该节点上丢失的块。
Secondary NameNode:单独运行在另一台机器上,辅助NameNode,分担其工作量;定期合并fsimage和fsedits,推送给NameNode;紧急情况下,可辅助恢复NameNode,但Secondary NameNode并非NameNode的热备。
MapReduce并行计算模型
一种并行计算模型,用于大数据量的计算。Map对数据集上的独立元素进行指定的操作,生成key-value的中间结果。Reduce对相同key的所有value进行规约,得到最终结果。
JobTracker:Master节点,只有一个,管理所有作业,作业/任务的监控、错误处理等;将任务分解成一系列任务,并分派给TaskTracker。
TaskTracker:Slave节点,运行Map Task和Reduce Task;发送heartbeat与JobTracker交互,汇报任务状态。
Map Task:解析每条数据记录,传给用户编写的map函数执行,将输出结果写入本地磁盘(如果为map-only作业,直接写入HDFS)。
Reducer Task:远程读取Map Task的执行结果,对数据进行排序,将数据按照分组传给用户编写的reduce函数执行。
以统计词频wordCount为例,MapReduce的流程如下:
结合hdfs,这里再详细解释下MapReduce工作流程:
1 客户端启动一个作业job
2 向JobTracker请求一个Job ID
3 job需要的资源文件复制到HDFS上名为Job ID的文件夹,包括MapReduce程序打包的JAR文件、配置文件和客户端计算的输入划分信息。JAR文件默认有10个副本(mapred.submit.replication属性控制);输入划分信息告诉JobTracker应为这个作业启动多少个map任务等信息。
4.JobTracker收到作业后,将其放在一个作业队列里,等待作业调度器调度。调度器根据输入划分信息为每个划分创建一个map任务,并将map任务分配给TaskTracker执行。map任务分配给含有map要处理数据块的TaskTracker上(数据本地化Data-Local),同时将程序JAR包复制到该TaskTracker上来运行(运算移动,数据不移动)。而分配reduce任务时并不考虑Data-Local。
5.TaskTracker每隔一段时间给JobTracker发送一个HeartBeat,告诉JobTracker它依然在运行,同时携带着很多信息,比如当前map任务完成进度等。当JobTracker收到作业的最后一个任务完成信息时,便把该作业设置成“success”状态。
再详细一点,考虑Map Task 和Reduce Task都做了什么。
Map端:
1.每个输入分片会由一个map任务来处理,以HDFS一个块(默认为64M)为一个分片。map任务输出的结果会暂且放在一个环形内存缓冲区中(默认100M,由io.sort.mb属性控制),如果该缓冲区快要溢出时(默认缓冲区大小的80%,由io.sort.spill.percent属性控制),会在本地文件创建一个溢出文件,将该缓冲区中的数据写入该文件。
2.在写入磁盘之前,线程首先将数据hash到和reduce任务数相同数量的分区,一个reduce任务对应一个分区的数据,然后对每个分区中的数据进行排序,如果此时设置了Combiner,将排序后的结果进行Combia操作,目的是让尽可能少的数据写入到磁盘。
3.当map任务输出最后一个记录时,可能会有很多的溢出文件,需要将这些文件合并。合并的过程中会不断地进行排序和combia操作,目的有两个:1.尽量减少每次写入磁盘的数据量;2.尽量减少下一复制阶段网络传输的数据量。最后合并成了一个已分区且已排序的文件。为了减少网络传输的数据量,这里可以将数据压缩,只要将mapred.compress.map.out设置为true就可以了。
4.将分区中的数据拷贝给相对应的reduce任务。有人可能会问:分区中的数据怎么知道它对应的reduce是哪个呢?其实map任务一直和其父TaskTracker保持联系,而TaskTracker又一直和JobTracker保持心跳。所以JobTracker中保存了整个集群中的宏观信息。只要reduce任务向JobTracker获取对应的map输出位置就ok了哦。
Shuffle的中文意思是“洗牌”,map产生的数据,结果通过hash过程分区却分配给了不同的reduce任务。
Reduce端:
1.Reduce会接收到不同map任务传来的数据,并且每个map传来的数据都是有序的。如果reduce端接受的数据量相当小,则直接存储在内存中(缓冲区大小由mapred.job.shuffle.input.buffer.percent属性控制,表示用作此用途的堆空间的百分比),如果数据量超过了该缓冲区大小的一定比例(由mapred.job.shuffle.merge.percent决定),则对数据合并后溢写到磁盘中。
2.随着溢写文件的增多,后台线程会将它们合并成一个更大的有序的文件,这样做是为了给后面的合并节省时间。其实不管在map端还是reduce端,MapReduce都是反复地执行排序,合并操作。
3.合并的过程中会产生许多的中间文件(写入磁盘了),但MapReduce会让写入磁盘的数据尽可能地少,并且最后一次合并的结果并没有写入磁盘,而是直接输入到reduce函数。
Hive(基于Hadoop的数据仓库)
Hive定义了一种类似SQL的查询语言(HQL),将HQL转化为MapReduce任务在Hadoop上执行。通常用于离线分析。
Hbase(分布式列存数据库)
HBase是一个针对结构化数据的可伸缩、高可靠、高性能、分布式和面向列的动态模式数据库。和传统关系数据库不同,HBase采用了BigTable的数据模型:增强的稀疏排序映射表(Key/Value),其中,键由行关键字、列关键字和时间戳构成。HBase提供了对大规模数据的随机、实时读写访问,同时,HBase中保存的数据可以使用MapReduce来处理,它将数据存储和并行计算完美地结合在一起。
数据模型:
Schema–>Table–>ColumnFamily–>Column–>RowKey–>TimeStamp–>Value
Zookeeper(分布式协作服务)
解决分布式环境下的数据管理问题:统一命名,状态同步,集群管理,配置同步等。
Sqoop(数据同步工具)
Sqoop是SQL-to-Hadoop的缩写,主要用于传统数据库和Hadoop之前传输数据。
数据的导入和导出本质上是Mapreduce程序,充分利用了MR的并行化和容错性。
Pig(基于Hadoop的数据流系统)
设计动机是提供一种基于MapReduce的ad-hoc(计算在query时发生)数据分析工具。
定义了一种数据流语言—Pig Latin,将脚本转换为MapReduce任务在Hadoop上执行。通常用于进行离线分析。
Mahout(数据挖掘算法库)
Mahout的主要目标是创建一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序。Mahout现在已经包含了聚类、分类、推荐引擎(协同过滤)和频繁集挖掘等广泛使用的数据挖掘方法。除了算法,Mahout还包含数据的输入/输出工具、与其他存储系统(如数据库、MongoDB 或Cassandra)集成等数据挖掘支持架构。
Flume(日志收集工具)
Cloudera开源的日志收集系统,具有分布式、高可靠、高容错、易于定制和扩展的特点。它将数据从产生、传输、处理并最终写入目标的路径的过程抽象为数据流,在具体的数据流中,数据源支持在Flume中定制数据发送方,从而支持收集各种不同协议数据。
同时,Flume数据流提供对日志数据进行简单处理的能力,如过滤、格式转换等。此外,Flume还具有能够将日志写往各种数据目标(可定制)的能力。总的来说,Flume是一个可扩展、适合复杂环境的海量日志收集系统。