Hadoop_Day01
文章目录
Apache基金会的介绍
Apache基金会是一个非营利性的全球开源软件组织,旨在支持和培育各种开源项目的发展。
CDH,HDP,CDP三者之间的关系
CDH、HDP和CDP都是与Hadoop相关的软件套件,它们之间的关系可以简单概括如下:
- CDH(Cloudera Distribution of Hadoop):由Cloudera提供的Hadoop发行版,是一个集成了Hadoop生态系统各种组件的完整解决方案。它包括了Hadoop核心、HDFS、YARN、MapReduce以及其他相关工具和组件。
- HDP(Hortonworks Data Platform):由Hortonworks提供的Hadoop发行版,也是一个全面的Hadoop解决方案。它集成了Hadoop核心、HDFS、YARN、MapReduce等,同时还包括一些附加工具和组件,如Hive、Pig和HBase等。
- CDP(Cloudera Data Platform):CDP是Cloudera推出的企业级数据平台,整合了CDH和HDP的功能,并在其基础上进行了进一步的扩展和优化。CDP提供了更加全面和灵活的数据管理和分析能力,涵盖了大数据、机器学习和人工智能等领域。
总结来说,CDH和HDP是两个独立的Hadoop发行版,都提供了完整的Hadoop生态系统和相关工具。而CDP则是基于CDH和HDP的基础上发展而来的企业级数据平台,具备更加全面和灵活的功能。
Hadoop的发展史
Hadoop的创始人
Doug cutting
Hadoop的Logo以及名字的由来
Doug cutting看到他儿子在牙牙学语时,抱着黄色小象,亲昵的叫 hadoop,他灵光一闪,就把这技术命名为 Hadoop,而且还用了黄色小象作为标志Logo
Hadoop发展过程
-
hadoop诞生与google的三篇论文:Google FileSystem,Bigtable,MapReduce,三篇文章分别对应后期的HDFS,Hbase,MapReduce
-
在Hadoop1.X版本中Doug cutting只实现了HDFS以及MapReduce,这个时候还没有Yarn,那么作业的调度就交给JobTraker
-
在Hadoop2.X版本中新增了Yarn,且从hadoop2.2版本之后引入了除了mapreduce这种离线计算模型之外的实时计算模型如spark,flink,还有通用的计算引擎Tez
Hadoop在版本2.2之后开始支持Spark、Flink和Tez。
具体地说,Hadoop 2.2引入了YARN(Yet Another Resource Negotiator)作为集群资源管理器,取代了之前的MapReduce专用框架。YARN的引入使得Hadoop可以同时运行多个计算框架,包括Spark、Flink和Tez等。
Spark是一个快速的、通用的集群计算系统,它与Hadoop YARN的集成从Hadoop 2.2版本开始支持。
Flink是另一个强大的流式处理和批处理框架,它也可以与Hadoop YARN集成,支持从Hadoop 2.2版本开始。
Tez是一个基于YARN的数据处理框架,旨在提供更高效的数据处理方式。从Hadoop 2.2版本开始,Tez也得到了支持。
因此,从Hadoop 2.2版本开始,用户可以在同一个Hadoop集群上使用Spark、Flink和Tez等计算框架来处理数据。
-
Hadoop3.X版本支持GPU
什么是Hadoop
Hadoop是一个适合海量数据的分布式存储和分布式计算的平台
在Hadoop1.x中JobTracker的作用
JobTracker
是 Hadoop 分布式计算框架(MapReduce)的关键组件,用于协调和管理整个集群中的作业任务。它接收来自客户端的作业提交请求,并将作业划分为多个任务,然后分配给可用的 TaskTracker
节点进行执行。JobTracker
负责任务的调度、监控、容错以及和 TaskTracker
的通信等工作。
MapReduce和JobTracker之间的关系
在 Hadoop 1.x 版本中,JobTracker 是 MapReduce 框架中的一个关键组件,并且与 MapReduce 有直接的关系。下面是它们之间的关系说明:
- MapReduce 是一种分布式计算框架,用于处理大规模数据集的批处理任务。它将一个大的作业划分为多个独立的任务,并在集群中的多台机器上并行执行这些任务。
- JobTracker 是 MapReduce 框架的主要组件之一。它负责协调和管理整个作业任务的执行。JobTracker 接收来自用户或应用程序的作业提交请求,并将作业划分为多个任务,并将这些任务分配给可用的 TaskTracker 进行执行。
- JobTracker 监控任务的执行状态,跟踪任务的进度,并在任务失败时进行容错处理。它还负责调度任务和资源管理,控制作业的整体执行流程。
所以,可以说 JobTracker 是 MapReduce 框架中的中央调度器和管理器,负责管理和控制整个作业的执行过程。在 Hadoop 1.x 版本中,MapReduce 作业的提交、任务调度和监控等功能都是通过与 JobTracker 进行交互来完成的。但需要注意的是,在 Hadoop 2.x 及之后的版本中,JobTracker 已经被 YARN(Yet Another Resource Negotiator)取代,YARN 成为了新一代的集群资源管理器,负责整体的作业调度和资源分配,而 MapReduce 框架则作为 YARN 的一个应用程序运行。
大数据框架
再加上一个资源调度框架包含常用的三个:dolphinSchedule,阿里云,CDH
Hadoop四大组件的简单介绍
-
Hadoop Common 提供了用于支持其他 Hadoop 组件的公共工具和库
-
HDFS 是分布式文件系统,用于存储和管理大规模数据
-
YARN 是资源管理器,负责集群资源的管理和任务的调度
-
MapReduce 是一种分布式计算框架,用于处理大规模数据集的并行计算
什么是文件系统
文件系统是一种用于组织和管理计算机存储设备上文件和目录的方法或数据结构。
什么是寻址开销
寻址开销是指在计算机系统中进行内存地址定位或寻找存储数据时所产生的时间和资源成本
数据块Block
- 是磁盘进行数据 读/写的最小单位,数据被切分后的一个整体被称之为块
- 在Hadoop 1默认大小为64M,在Hadoop 2及其之后默认大小为128M块,这么大是为了最小化寻址开销
为什么拆分数据块需要等大
-
通过偏移量就知道这个块的位置,数据计算的时候简化问题的复杂度(否则进行分布式算法设计的时候会因为数据量不一很难设计)
-
数据读取的时候时间相对一致
-
数据本地性:Hadoop 的数据处理模型是将计算移动到数据而不是将数据移动到计算。如果数据块的大小不一致,那么某些计算节点可能会存储大量数据块,而其他计算节点则很少存储数据块。这会导致数据倾斜和网络负载不均衡。通过使用等大的数据块,可以更好地实现数据本地性,使计算节点能够更有效地处理存储在本地的数据。
-
任务调度和资源管理:Hadoop 的资源调度和管理机制通常以数据块为单位进行计算资源的分配和调度。如果数据块大小不一致,会导致不均匀的资源利用和调度问题。通过保持数据块大小相同,可以更好地管理和分配集群中的资源。
注意事项
- 只要有任意一个块丢失,整个数据文件被损坏
- HDFS中一旦文件被存储,数据不允许被修改
- 修改会影响偏移量,导致蝴蝶效应
- 修改会导致数据倾斜(单节点数据量过多)
- 但是可以被追加(一般不推荐),追加设置需要手动打开
- 一般HDFS存储的都是历史数据.所以将来Map Reduce都用来进行离线数据的处理
- 块的大小一旦文件上传之后就不允许被修改 128M-512M
Block块数据安全问题
- 副本的数量可以变更,副本的数量要小于等于节点的数量(每一个几点最多备份一个数据)
- 每个数据块默认会有三个副本,相同副本是不会存放在同一个节点上
Hadoop中实际上对于block块的切分处理
- 默认情况下,一个block块会生成一个map任务,交给map任务去处理,但是,当最后个block块大小与倒数第二个block块实际大小加一起的时候,如果小于128M*1.1的话,这两个block块一起只会生成一个map任务,否则,产生两个map任务。
使用Java代码分别通过两种方式去处理students.txt的班级人数
HashMap的方法
package com.shujia.xlj.moniqiefen1;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
纯java思想实现统计每个班级的人数
*/
public class Demo1 {
public static void main(String[] args) throws Exception {
//创建一个Map集合
HashMap<String, Integer> map = new HashMap<>();
//读取文件
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("hadoop/data/students.txt"));
//1500100002,吕金鹏,24,男,文科六班
String line = null;
while ((line = br.readLine()) != null) {
//根据逗号进行切分,获取到班级
String clazz = line.split(",")[4];
if (map.containsKey(clazz)) {
map.put(clazz, map.get(clazz) + 1);
} else {
map.put(clazz, 1);
}
}
//遍历集合
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
String clazz = entry.getKey();
Integer number = entry.getValue();
System.out.println(clazz + ":" + number);
}
/*
文科六班:104
文科二班:87
文科三班:94
理科五班:70
文科四班:81
理科一班:78
文科五班:84
理科六班:92
理科二班:79
文科一班:72
理科三班:68
理科四班:91
*/
}
}
使用Java程序模拟mapreduce的方法
切分文件
package com.shujia;
import java.io.*;
import java.util.ArrayList;
public class SplitFileBlock {
public static void main(String[] args) throws Exception {
//将数据读取进来
//字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("data/students.txt"));
int index = 0;
//字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("data/blocks2/block---" + index));
//现在是假设一行数据是1m,没128m数据,就生成一个block块,不到128m也会生成一个block块
//每次读到128*1.1约等于140行的数据,就写入128行,剩下的12行计入下一次block块中去存储
//定义一个集合,用于存储,读取的内容
ArrayList<String> row = new ArrayList<>();
String line = null;
//定义一个变量,记录读取的行数
int offset = 0;
//定义一个变量,记录读取的是哪一个block块
int rowNum = 0;
while ((line = br.readLine()) != null) {
row.add(line);
offset++;
//当我们的偏移量,128*1.1约等于140行的数据,就写入128行,剩下的12行计入下一次block块中去存储
if (offset == 140) {
rowNum = 128 * index;
//循环128次,将集合存储的数据,写入到block块中
for (int i = rowNum; i <= rowNum + 127; i++) {
String s = row.get(i);
bw.write(s);
bw.newLine();
bw.flush();
}
index++;
//将offset设置为12
offset = 12;
bw = new BufferedWriter(new FileWriter("data/blocks2/block---" + index));
}
}
//把剩余的数据写到一个block块中
for(int i = row.size()-offset;i<row.size();i++){
String s = row.get(i);
bw.write(s);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
br.close();
}
}
map任务
package com.shujia;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTask implements Runnable {
private File file;
public int offset;
public MapTask(File file,int offset) {
this.file = file;
this.offset = offset;
}
@Override
public void run() {
//字符缓冲输入流
try {
BufferedReader br = new BufferedReader(new FileReader(file));
//创建一个Map集合,使用HashMap
HashMap<String, Integer> map = new HashMap<>();
String line = null;
while ((line = br.readLine()) != null) {
//用逗号进行切分
String clazz = line.split(",")[4];
//如果在map中没有该班级作为key,那我们就把这个班级作为key存放在集合,value设置为1
if (!map.containsKey(clazz)) {
map.put(clazz, 1);
} else {
//否则value值加1
map.put(clazz, map.get(clazz) + 1);
}
}
//结束读取数据流程
br.close();
//将局部的map任务结果写入到文件中
//创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("data/parts2/part---" + offset));
//遍历HashMap
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> keyValue : entries){
String clazz = keyValue.getKey();
Integer sumNumber = keyValue.getValue();
//写入文件
bw.write(clazz+":"+sumNumber);
//换行
bw.newLine();
bw.flush();
}
//关闭写通道
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
map任务执行
package com.shujia;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
Map(通过线程池的方式,简单来说,模拟hadoop中一个block块生成一个map任务,一个map任务相当于一个线程)
(将切分出来的bolck块中,统计每个班级的人数)
4423毫秒
*/
public class Map {
public static void main(String[] args) {
long start = System.currentTimeMillis();
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(10000);
File file = new File("data/blocks2");
//定义一个文件编号,从0开始
int offset = 0;
File[] files = file.listFiles();
for (File f : files) {
MapTask mapTask = new MapTask(f, offset);
executorService.submit(mapTask);
offset++;
}
//关闭线程池
executorService.shutdown();
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end - start)+"毫秒");
}
}
reduce任务
package com.shujia;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//306毫秒 537毫秒 == 843毫秒
//4423毫秒reduce总耗时:117551毫秒
/*
模拟hadoop的切分map-reduce处理的方式,总耗时14毫秒
将每个map任务的结果,再做一次总的聚合,统计出最终的班级人数
当数据量过大的时候,TB以上的级别的时候
1、一台服务器不够存
2、可能一台够存,但是纯java程序是由JVM虚拟机调起的,内存有限,可能会导致,OOM内存溢出
这时候,就必须使用分布式存储,将大文件进行切分,先局部做运算,这时候局部的数据少很多,然后再总的聚合,数据量少且块!
*/
public class Reduce {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
//将past目录封装成File对象
File file = new File("data/parts2");
//获取下面的所有文件对象数组
File[] files = file.listFiles();
//创建一个map集合,接收总的结果数据
HashMap<String, Integer> map = new HashMap<>();
//遍历每个part文件
for (File f : files) {
//读取文件,进行分割
//创建缓冲字符输入流对象
BufferedReader br = new BufferedReader(new FileReader(f));
String line = null;
while ((line = br.readLine()) != null) {
//以冒号进行分割得到班级和人数
String[] strings = line.split(":");
String clazz = strings[0];
//包装类
Integer sum = Integer.valueOf(strings[1]);
//判断map集合中是否存在对应的key
if (!map.containsKey(clazz)) {
map.put(clazz, sum);
} else {
//如果存在,value值相加
map.put(clazz, map.get(clazz) + sum);
}
}
//关闭读取数据的通道
br.close();
}
//将结果写入到最终一个文件
BufferedWriter bw = new BufferedWriter(new FileWriter("data/result-big/part-r-000000"));
//遍历集合
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> keyValue:entries){
String clazz = keyValue.getKey();
Integer number = keyValue.getValue();
bw.write(clazz+":"+number);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
long end = System.currentTimeMillis();
System.out.println("reduce总耗时:"+(end-start)+"毫秒");
}
}