最早起源于Nutch,Nutch的设计目标是构建一个大型的全网搜索引擎,遇到了严重的可扩展性问题——如何解决数十亿网页的存储和索引问题。
Hadoop是apache旗下一套开源软件平台,利用服务器集群,根据用户自定义的业务逻辑,对海量数据进行分布式处理。
Hadoop的核心组件:
HDFS:(分布式文件存储系统)–>GFS(分布式文件系统)
YARN:(运算资源调度系统)
MAPREDUCE(分布式运算编程框架)–>MAPREDUCE(分布式计算框架)
广义上来说,Hadoop通常是指一个更广泛的概念,–Hadoop生态圈
分布式系统
该软件系统会划分成多个子系统或模块,各自运行在不同的机器上,子系统或模块之间通过网络通信进行协作,实现最终的整体功能。
总结:利用多个节点共同协作完成一项或多项具体业务功能的系统就是分布式系统。
重点组件:
HDFS:分布式文件存储系统,数据被保存在计算机集群上,数据写入一次,读取多次。HDFS为HBase等工具提供了基础。
MAPREDUCE:分布式运算程序开发框架,MapReduce把任务分为map(映射)阶段和reduce(化简)。开发人员使用存储在HDFS中数据(可实现快速存储), 编写Hadoop的MapReduce任务。由于MapReduce工作原理的特性,Hadoop能以并行的方式访问数据,从而实现快速访问数据。
HIVE:基于大数据技术(文件系统+运算框架)的SQL数据仓库工具,Hive类似于SQL高级语言,用于运行存储在Hadoop上的查询语句,Hive让不熟悉MapReduce开发人员也能编写数据查询语句,然后这些语句被翻译为Hadoop上面的MapReduce任务。
HBASE:基于HADOOP的分布式海量数据库,HBase是一个建立在HDFS之上,面向列的NoSQL数据库,用于快速读/写大量数据。HBase使用Zookeeper进行管理,确保所有组件都正常运行。
ZOOKEEPER:分布式协调服务基础组件,用于Hadoop的分布式协调服务。Hadoop的许多组件依赖于Zookeeper,它运行在计算机集群上面,用于管理Hadoop操作。
Mahout:基于mapreduce、spark、flink等分布式运算框架的机器学习算法库,它提供的MapReduce包含很多实现,包括聚类算法、回归测试、统计建模。通过使用 Apache Hadoop 库,可以将Mahout有效地扩展到云中。
Oozie:工作流调度框架,Oozie是一个可扩展的工作体系,集成于Hadoop的堆栈,用于协调多个MapReduce作业的执行。它能够管理一个复杂的系统,基于外部事件来执行,外部事件包括数据的定时和数据的出现。
Sqoop:数据导入导出工具,用于在关系数据库、数据仓库和Hadoop之间转移数据。Sqoop利用数据库技术描述架构,进行数据的导入/导出;利用MapReduce实现并行化运行和容错技术。
Flume:日志数据采集框架,提供了分布式、可靠、高效的服务,用于收集、汇总大数据,并将单台计算机的大量数据转移到HDFS。它基于一个简单而灵活的架构,并提供了数据流的流。它利用简单的可扩展的数据模型,将企业中多台计算机上的数据转移到Hadoop。
Hadoop集群:
HDFS集群和YARN集群,两者逻辑上分离,物理上在一起
HDFS集群:负责海量数据存储,集群上主要角色有NameNode/DataNode
YARN集群:负责海量数据运算时的资源调度,集群中主要角色ResourceManager/NodeManager
1.添加hadoop用户
2.为hadoop用户分配sudoer权限
3.同步时间
4.设置主机名 cdh min min2
5.配置内网域名映射:
192.168.x.x cdh
192.168.x.x min
192.168.x.x min2
6.配置ssh免密登录
7.配置防火墙
配置文件设置:
hadoop-env.sh
# The java implementation to use.
export JAVA_HOME=/home/hadoop/apps/jdk1.7.0_51
core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://cdh:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/local/apps/hadoop-2.6.1/tmp</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<property>
<name>dfs.namenode.name.dir</name>
<value>/home/hadoop/data/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/home/hadoop/data/data</value>
</property>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.secondary.http.address</name>
<value>hdp-node-01:50090</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>cdh</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>
salves
cdh
min
min2
启动集群:
初始化HDFS:bin/hadoop namenode -format
启动HDFS:sbin/start-dfs.sh
启动YARN:sbin/start-yarn.sh
启动HDFS+YRAN:start-all.sh
操作:
1.上传文件到HDFS:
hadoop fs -mkdir -p /wordcount/input
hadoop fs -put /home/word.txt /wordcount/input
运行一个mapreduce程序
hadoop jar mapredcue-example-2.6.1.jar wordcount /wordcount/input /wordcount/output
HDFS使用
1.查看集群状态
hdfs dfsadmin –report
2.查看HDFS中的目录信息
hadoop fs –ls /
3.从HDFS下载文件
hadoop fs -get /yarn-site.xml
Demo开发mapreduce(wordcount)
map阶段
1.从HDFS的源数据文件中逐行读取数据
2.将每一行数据切分出单词
3.为每一个单词构造一个键值对(单词,1)
4.将键值对发送给reduce
reduce阶段
1.接收map阶段输出的单词键值对
2.将相同单词的键值对汇聚成一组
3.对每一组,遍历组中的所有“值”,累加求和,即得到每一个单词的总次数
4.将(单词,总次数)输出到HDFS的文件中
代码实现
mapper类
//首先要定义四个泛型的类型
//keyin: LongWritable valuein: Text
//keyout: Text valueout:IntWritable
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
//map方法的生命周期: 框架每传一行数据就被调用一次
//key : 这一行的起始点在文件中的偏移量
//value: 这一行的内容
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//拿到一行数据转换为string
String line = value.toString();
//将这一行切分出各个单词
String[] words = line.split(" ");
//遍历数组,输出<单词,1>
for(String word:words){
context.write(new Text(word), new IntWritable(1));
}
}
}
reduce类
//生命周期:框架每传递进来一个kv 组,reduce方法被调用一次
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//定义一个计数器
int count = 0;
//遍历这一组kv的所有v,累加到count中
for(IntWritable value:values){
count += value.get();
}
context.write(key, new IntWritable(count));
}
定义一个主类,用来描述job并提交job
public class WordCountRunner {
//把业务逻辑相关的信息(哪个是mapper,哪个是reducer,要处理的数据在哪里,输出的结果放哪里。。。。。。)描述成一个job对象
//把这个描述好的job提交给集群去运行
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job wcjob = Job.getInstance(conf);
//指定我这个job所在的jar包
//wcjob.setJar("/home/hadoop/wordcount.jar");
wcjob.setJarByClass(WordCountRunner.class);
wcjob.setMapperClass(WordCountMapper.class);
wcjob.setReducerClass(WordCountReducer.class);
//设置我们的业务逻辑Mapper类的输出key和value的数据类型
wcjob.setMapOutputKeyClass(Text.class);
wcjob.setMapOutputValueClass(IntWritable.class);
//设置我们的业务逻辑Reducer类的输出key和value的数据类型
wcjob.setOutputKeyClass(Text.class);
wcjob.setOutputValueClass(IntWritable.class);
//指定要处理的数据所在的位置
FileInputFormat.setInputPaths(wcjob, "hdfs://hdp-server01:9000/wordcount/data/big.txt");
//指定处理完成之后的结果所保存的位置
FileOutputFormat.setOutputPath(wcjob, new Path("hdfs://hdp-server01:9000/wordcount/output/"));
//向yarn集群提交这个job
boolean res = wcjob.waitForCompletion(true);
System.exit(res?0:1);
}
}
程序打包运行
hadoop jar wordcount.jar com.aimuti.WordCountDriver /wordcount/input /wordcount/out
hadoop共享数据(全局变量)
hadoop不支持全局变量,也不建议使用全局变量,这是因为hadoop具有map类和reducer类,
并且不同的task一般执行的是不同的map或reduce。所以全局变量是无法传递的
解决方案
1.在MapReduce框架中,Map Task和Reduce Task都运行在Hadoop集群的节点上,
所以Map和Reduce Task、甚至不同的Job都可以通过读写HDFS中预定好的同一文件来实现全局共享数据
具体实现是利用Hadoop的Java API来完成,需要注意的是,多个Map或Reduce的写操作会产生冲突,覆盖原有数据
这种方法的优点是能够实现读写,也比较直观,但是缺点是需要共享一些很小的全局数据也需要使用IO,
这将占用系统资源,增加作业完成的资源消耗,并在高并发的mapreduce中容易出现数据同步问题,风险较高,不推荐使用
扩展1:我们同样可以使用Hbase替代Hdfs,做为全局变量的存储介质
扩展2:或者使用redis等内存数据库,提高读写速度
代码实现
public void reduce(Text key, Iterable<NullWritable> values, Context context)
throws IOException, InterruptedException {
String countPath = "/overall/count.txt";
HdfsUtil hdfsUtil = new HdfsUtilImpl();
List<String> list = hdfsUtil.readFile(countPath);
int count = 0;
if(list!=null&&list.size()>0){
String tempStr = list.get(0);
count = Integer.valueOf(tempStr)+1;
}
hdfsUtil.createFile(countPath, String.valueOf(count));
context.write(key,new IntWritable(count));
}
2.在MapReduce执行过程中,task可以读取Job的属性。基于这个特性,我们可以在任务启动之初利用Configuration类中的
set(String name,String value)将一些简单的全局数据封装到作业的配置属性中,
然后task再利用Configuration中的get(String name)获取配置到属性中的全局数据
这种方法的优点是简单,资源消耗小,但是对量比较大的共享数据显得比较无力
代码实现
@Override
public void reduce(Text key, Iterable<NullWritable> values, Context context)
throws IOException, InterruptedException {
int count = context.getConfiguration().getInt("overallcount", 1);
count++;
context.getConfiguration().setInt("overallcount", count);
context.write(new Text("count"),new IntWritable(count));
}
总结:
1.Hadoop中可以有多种方式使用第三方jar包,我们这里使用在项目中添加lib目录的方式使用
2.可以使用NullWritable代替不需要的key或value输出
3.通过注释掉core-site.xml文件中关系mr的部分,可以让mr在本地模拟环境运行