一、认识hadoop
学习hadoop首先我们要认识它是什么,简而言之,hadoop是一个分布式开发框架,通过它可以对海量数据进行高效的运算和存储,比如说淘宝每天产生的海量数据如果用普通的数据库存储计算是不现实的,而hadoop集群通过将海量数据分块存储到几百台,几千台机器上就非常适用了。
hadoop的前身可以说是谷歌的一款MapReduce编程模型包,MapReduce会把一个应用程序分解为许多的并行计算指令,跨大量的计算节点运行非常巨大的数据集。使用该框架的典型例子就是在网络数据上运行的搜索算法。也就是说hadoop是一个能够对海量数据进行分布式存储与计算的软件框架。相比于传统方式具有可靠、高效、易伸缩、可扩展等优点。可靠性是因为hadoop确保数据安全,数据存储时某个节点出现故障,它会重新安排新的节点对数据进行存储与处理。高效是因为他是以并行的工作方式来处理数据,效率提升很大。伸缩性体现在hadoop可以处理PB级的数据。另外hadoop是在可用的计算机集簇间分配数据并完成计算任务所以可以方便的扩展到数以千计的节点中。
二、hadoop架构
在这里说下hadoop的两个核心架构HDFS和MapReduce。
HDFS全称Hadoop Distributed File System,从英文上我们就能了解它是hadoop的分布文件系统,通过hadoop集群的安装我们可以将数据存储在这个分布式文件系统上。HDFS具有高容错性、高吞吐量,并且可以部署在廉价的机器上运行。HDFS的储存单元是Block(块),是一个逻辑单元,一个文件可以包含多个块,一个块也可以包含多个文件,这些取决于文件的大小和块大小的参数配置。一般block设置为128M,设置过大可能导致Map运行较慢,设置过小也会导致Map个数较多,所以要设置适当。
MapReduce是一个并行运算的编程模型、计算框架,整个计算过程主要可以分为五部分
首先我们给一个输入,比如一个包含多个单词的txt文件,这个输入在mapreduce框架中首先会经历split过程,即切片处理,这里说切片并不是真正的把文件切开,而是逻辑上的切片,即记录从哪里开始到哪里结束作为一个切片,默认的切片大小是128兆,我们可以通过hadoop文件里的dfs.block.size来设置合适的参数。一个切片对应一个map过程,在map里给每个单词配一个value值1,以方便后续的处理。从map进入到shuffle过程,在这里是对单词进行sort,combine,partition等处理,在这里数据会根据key把value放入一个list集合里,通过这些处理后reducing会对这些数据进行合并,比如将key都为Bear的合并,即输出一个(Bear,2)的键值对,最后结果变出来了。
三、通过一个简单的实例来认识mapreduce作业。
map过程:
public
class Map
extends Mapper<LongWritable, Text, Text, IntWritable>{
@Override
protected
void map(LongWritable
key, Text
value,Context
context)
throwsIOException, InterruptedException {
String
line=value.toString();
String[]
arr=
line.split(
" ");
for(String
word:
arr){
context.write(
newText(
word),
new IntWritable(1));
}
}
}
reduce过程:
public
class Reduce
extends Reducer<Text, IntWritable, Text, IntWritable>{
@Override
protected
void reduce(Text
key, Iterable<IntWritable>
value,
Context
context)
throws IOException, InterruptedException {
int
sum=0;
for(IntWritable
values:
value){
sum+=
values.get();
}
context.write(
key,
new IntWritable(
sum));
}
}
main方法:
public
class Main {
public
static
void main(String[]
args)
throws IOException, ClassNotFoundException, InterruptedException {
Configuration
conf=
newConfiguration();
Job
job=Job.
getInstance(
conf);
job.setMapperClass(Map.
class);
job.setReducerClass(Reduce.
class);
job.setMapOutputKeyClass(Text.
class);
job.setMapOutputValueClass(IntWritable.
class);
job.setOutputKeyClass(Text.
class);
job.setOutputValueClass(IntWritable.
class);
FileInputFormat.
setInputPaths(
job,
newPath(
"hdfs://192.168.66.666:9000/root/test/word.txt"));
FileOutputFormat.
setOutputPath(
job,
newPath(
"hdfs://192.168.66.666:9000/root/test/out.txt"));
boolean
res=
job.waitForCompletion(
true);
System.
exit(
res?0:1);
}
}
通过这样一个简单的wordcount大家应该可以清晰的理解mapreduce作业了。
四、集群进程解读:
在linux上输入指令jps后我们会看到下面几个进程。
ResourceManager:资源管理进程,负责接受任务然后分配工作资源。
NameNode:名称节点,负责与DataNode的沟通,存储文件相关的元数据。
DataNode:数据节点,负责存储文件
NodeManager:节点管理进程,主要是监视节点的健康状况
SecondaryNameNode:该进程负责镜像文件与日志的合并传递给NameNode。
也许大家看了上面的简介还会有所疑惑,无妨,我们下面举个栗子:
有一天,八戒想读一本西游记,这本西游记呢有90章,hdfs将三国演义分为3个block,每个block有30章内容,这3个block分布在三个数据节点DataNode上,八戒作为客户端会告诉NameNode他要读西游记,然后NameNode会去查看西游记存在哪里,通过查询存储的元数据信息知道是他们三个节点每个节点存了30章的内容,然后将这些信息给八戒,八戒知道后根据这些信息直接找这三个DataNode要数据。然后他就去睡觉了。
相反的,写数据就是NameNode将数据安排到节点上,然后把怎么存储的这些信息作为元数据保持到自己这里。
五、优化
虽然hadoop作为一个优秀的分布式开发框架有很多优点,但也难免会有一些需要优化改进的地方,可以通过下面几种方法让我们用起hadoop更加得心应手:
1、减少reduce数量、解决数据倾斜问题
2、自定义分区
3、jvm调优
4、Yarn-site.xml任务占用内存等参数的设置
5、压缩优化(hadoop默认的优化算法是GZIP,我们也可以使用LZO,可以减少存储磁盘空间,降低单节点的IO)