第一章:初识Hadoop大数据技术

 1.大数据与相关技术基础笔记


一、数据存储单位换算

• bit(位):最小数据单位,二进制(0,1),如 0101 为 4b

• B(Byte,字节):1B = 8b,一个汉字占 2 个字节

• KB(千字节):1KB = 1024B,可存储一小段文字

• MB(兆字节):1MB = 1024KB,可存储一首歌曲(3~5M)

• GB(吉字节):1GB = 1024MB,可存储一个视频(如高清短剧)

TB(太字节):1TB = 1024GB,大数据规模起点,可存储数据库

• PB(拍字节):1PB = 1024TB,可存储公司数据中心(约2亿张图片)

• EB(艾字节):1EB = 1024PB,全球级别,如全球天气观测和气候数据

• ZB(泽字节):1ZB = 1024EB,全球数据量的总和

• YB(尧字节):1YB = 1024ZB


二、大数据的4V定义

大数据的核心特征可概括为 4V:

• Volume(大量化):数据规模大,通常以 TB、PB、EB 计量

• Variety(多样化):数据来源和格式多样,包括:

结构化数据:关系型数据库、Excel 等

◦ 半结构化数据:JSON、XML、电子邮件等

◦ 非结构化数据:文本、图片、音视频等

• Velocity(快速化):数据产生和处理速度快,强调实时性

• Value(价值密度低):数据量大,但有价值的信息占比低,需挖掘


三、大数据技术生态

• Hadoop:核心组件包括 HDFS(分布式文件系统)、MapReduce(分布式计算)、YARN(资源调度)

• Spark:快速大数据处理引擎,用于迭代计算和实时分析

• Hive:基于 Hadoop 的数据仓库工具,提供类 SQL 查询

• HBase:分布式、可扩展的 NoSQL 数据库


四、其他重要概念

• E-R模型:由 IBM 的 E.F. Codd 提出的实体-关系数据模型

• 大模型与平台:

◦ DeepSeek、ChatGPT 等大模型

◦ CSDN 等技术社区与学习平台

1.1大数据技术发展

①大数据技术要面对的基本问题,也是最核心的问题:

就是是海量数据如何可靠存储和高效计算

②易观OLAP(比赛,可不记)

1.2Goole的“三驾马车”


一台计算机变成多台计算机

GFS:The Google File System 一种分布式文件系统,用于处理大规模数据密集型应用(HDFS)

MapReduce:Simplified Data Processing on Large Clusters 大型集群上的简单数据处理

Bigtable :A Distributed Storage System for Structured Data 一个分布式的结构化数据存储系统(Hbase)

Chunk Server是存数据

Master是管理

GFS架构:
 
(1)GFS Master节点管理所有的文件系统元数据,包括命名空间、访问控制权、文件和块的映射信息以及当前块的位置信息。
 
(2)GFS存储的文件都被分割成固定大小的块,每个块都会被复制到多个块服务器上(可靠性)。块的冗余度默认为3

(3)GFS Master还管理着系统范围内的活动,比如块服务器之间的数据迁移等

(4)GFS Master 与每个块服务器通信(发送心跳包),发送指令。获取状态

副本的位置选择的策略要满足两个目标:最大化数据的可靠性和可用性。

③MapReduce的思想


————————————————

MapReduce采用“分而治之”的思想,把对大规模数据集的操作,分发给一个主节点管理下的各个子节点共同完成,然后整合各个子节点的中间结果,得到最终的计算结果。MapReduce就是“分散任务,汇总结果”。

Map的输出是Reduce的输入

④BigTable

1.3Hadoop

1.3.1Hadoop的概述


①hadoop是什么?


(1)hadoop是一个由Apache基金会所开发的分布式计算基础框架

(2)主要解决,海量数据的存储和海量数据的分析计算问题。

(3)广义上来讲,Hadoop通常是指一个更广泛的概念--Hadoop生态圈。

②Hadoop根据是Google的三篇论文实现


HDFS → GFS

MapReduce → MapReduce

HBase → BigTable

(1)HDFS:Hadoop Distributed File System,是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础

1.3.3Hadoop的演变

1.3.4Hadoop优势

高可靠性:底层维护多个数据副本,即使Hadoop某个计算元素或存储出现故障,也不会导致数据的丢死。

高扩展性:在集群分别配任务数据,可方便的扩展数以千计的节点

高效性:在MapReduce的思想下,Hadoop是并行工作的,以加快任务处理速度

高容错性:能自动将失败的任务重新分配。

1.3.5Hadoop生态圈

组件功能
HDFS 分布式文件系统
YARN 资源管理和调度器
MapReduce  分布式并行编程模型
HBaseHadoop上的非关系型的分布式数据库
Hive Hadoop上的数据仓库
Pig一个基于Hadoop的大规模数据分析平台,提供类似SQL的查询语言Pig Latin
Flume    一个高可用,高可靠的,分布式的海量日志采集、聚合和传输的系统
Sqoop  用于Hadoop与传统数据库之间进行数据传递
Zookeeper  提供分布式协调一致性服务
Spark 类似于HadoopMapReduce的通用并行框架


1.4Hadoop的组成


1.4.1HDFS架构概述

Hadoop

图1

NameNode:存储文件的元数据,如文件名、文件目录结构、文件属性(生成时间,副本数,文件权限),以及每个文件的快列表和快所爱的DataNode。【老大】管理

DataNode:在本地文件系统存储文件块数据,以及块数据的校验和。【干活的】

Secondary NameNode:每隔一段时间对NameNode元数据备份。(并不是说是namenode的高可用)

1.4.2yarn

ResourceManager:整个集群资源(内存,cpu等)的老大

NodeManager单个节点服务器资源老大:

(多了一个resourcemanager,和多个nodemanager)

ApplicationMaster:单个任务的老大(1.负责数据切分2.为应用程序申请资源并分配内部认为3.任务的监控与容错

Container:容器,相当于一台独立的服务器,里面封装了任务运行所需要的资源,如内存,cpu,磁盘,网络等。

1.4.3Mapreduce架构

Mapreduce将计算机过程分为两个阶段:Map和Reduce

Map阶段并行处理输入数据

Reduce阶段对Map结果进行汇总

启动Docker容器

docker run --name master --privileged --ulimit nofile=65535:65535 --hostname master --ip 172.18.0.2 --add-host=slave1:172.18.0.3  --add-host=slave2:172.18.0.4 --add-host=slave3:172.18.0.5 -itd -v /cgsrc:/cgsrc:ro -v /headless/course/:/course hadoop_node /service_start.sh

1.docker run创建并启动了一个docker容器

-name master:容器名字叫master

-privileged:赋予容器特权模式,允许访问主机设备(常用于需要内核级操作的场景)

-ulimit nofile=65535:65535 设置文件最大描述符数量(软限制/硬限制)限制为65535,默认值较小,Hadoop,HDFS等大数据组件会频繁打开文件,网络连接,必须调高避免("too many open files"错误)高并发场景下的资源不足问题。

集群(很多电脑,组成的一个集合)

2.docker ps 查看所有启动的容器

docker start容器名字

3.进入容器

docker exec-it-privileged容器的名字/bin/bash

安装Java环境

1.创建Java文件夹

cd /usr/local/java/
tar -zxvf jdk-8u171-linux-x64.tar.gz
rm -f jdk-8u171-linux-x64.tar.gz

1.cd/usr/local

mkdir 创建文件夹

mkdir /usr/local/java
cp /cgsrc/jdk-8u171-linux-x64.tar.gz /usr/local/java/

2.cp 被复制文件位置 最后文件放到的位置

3.解压

tar-zxvf压缩包的名字

4.删除

rm -f要删除的文件

5.编辑环境变量

编辑文件的内容vim(vim文件的名字)

vim~/.bashrc

输入 i 进入编辑模式(末尾粘贴:export JAVA_HOME=/usr/local/java/jdk1.8.0_171 export CLASSPATH=.:${JAVA_HOME}/jre/lib/rt.jar:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar export PATH=$PATH:${JAVA_HOME}/bin

6.让环境变量生效

按Esc,输入“:wq ”保存并退出vim

source ~/.bashrc

验证

slave1

slave2

slave3

注意

1.配置分布式模式

HDFS:NameNode(1个)DataNode(多个)SecondaryNode(1个)

NameNode和SecondaryNode尽量不要安装在同一台服务器

YARN:ResourceManager(1个)NodeManager(多个)

ResourceManager很消耗内存,尽量不要和NameNode,SecondaryNameNode放同一台机器上)

hadoop1hadoop2hadoop3hadoop4
NameNodeDataNodeDataNode

DataNode

SecondaryNameNode

NodeManager

NodeManager

ResourceManager

NodeManagerNodeManager

【第二排hdfs,第二排yarn】

2.ping ip地址:ICMP协议,测试两台计算机之间连通性(OSI第三层)

ping master

ssh

Secure Shell(安全外壳协议)

一套电脑 -->(控制)另外一套电脑(有密码)

客户端--》服务端

场景:王俊凯寄一个箱子给高姗姗,这个箱子比较私密,中途不能让人打开。

1.高姗姗打造了一把锁(公钥)和一把钥匙(私钥)。

2.高姗姗把这把锁(公钥)给王俊凯,但是钥匙(私钥)高姗姗自己藏好。(把公钥放到服务器)

3.王俊凯把箱子用高姗姗给他的锁锁上了。(用公钥加密)

4.箱子寄出去,中途任何没有钥匙的人都打不开。

5.只有高姗姗可以用她的钥匙打开。

高姗姗:客户端

王俊凯:服务端

流程图

1.生成公钥和私钥

ssh-keygen -t rsa

rsa私钥,rsa.pub公钥

ssh-keygen -t rsa

.ssh文件下的文件功能解释

know_hosts记录ssh访问过计算机的公钥(public key)
id_rsa生成的私钥
id_rsa.pub生成的公钥
authorized_keys存放授权过的无密码登陆服务器公钥

2.将公钥文件追加到另一个文件

cat ./id_rsa.pub >> /authorized_keys

3.scp从一台电脑的~/.ssh/id_rsa.pub的文件,复制到slave1这台电脑上,用户是root,放到了slave1里面的/root这个路径下面

scp ~/.ssh/id_rsa.pub root@slave1:/root

1.从Hadoop102服务器上将本文服务器的文件推给Hadoop103

scp -r jdk1.8.0_212/ ~/ lotus@hadoop103:/opt/module

2.从Hadoop103服务器上操作,将Hadoop102文件拿过来

scp -r lotus@hadoop102:/opt/module/jdk1.8.0_212/ ./

同理Hadoop也可以这么操作

scp -r lotus@hadoop102:/opt/module/hadoop-3.1.3/ ./

3.在103服务器上,将102文件拷贝到104

scp -r lotus@hadoop102:/opt/module/* lotus@hadoop104:/opt/module/

master登录slave1.slave2,slave3(免密)

slave1登录到master(没有密码)

实现场景:在slave1执行命令 ssh master,就可以不输密码master

1.slave生成私钥,公钥

2.slave1的公钥给master

scp

3.在master上 公钥给放到~/.ssh/authorized_keys

4.去slave1里面测试,ssh master

5.删掉slave1传到master上的公钥

安装Hadoop

1.将hadoop复制到/usr/local下面

cp /cgsrc/hadoop-3.4.0.tar.gz /usr/local/

解压

tar解压,压缩

-z使用gzip解压

x解压文件

v显示解压过程

f指定文件名

tar -zxvf hadoop-3.4.0.tar.gz
mv hadoop-3.4.0 hadoop

3.mv 旧名字 新名字

4.修改配置文件

vim ~/.bash

在配置文件添加Hadoop的相关路径

export PATH=$PATH:/usr/local/hadoop/bin:/usr/local/hadoop/sbin

让配置文件生效

[root@master local]# vim ~/.bashrc
[root@master local]# source.~/.bashrc

1.bin存放操作命令,具体包含如(hdfs,mapred,yarm)

2.etc所有配置文件

3.include头文件

4.lib本地库(native库)压缩的动态链接库

5libexec拓展库

6sbin集群相关的命令

7share学习的资料文档

配置集群环境

/usr/local/hadoop/etc/hadoop/的配置环境

workers(DateNode节点)

core-site.xml整个集群核心配置

hdlfs-site.xml配置hdfs

mapred-site.xml配置mapred

yarn-site.xml配置yarn

hadoop-env.sh

1.编辑workers

vim workers

master,slave1,slave2,slave3

2.修改core-site.xml

<configuration>
	<! --默认文件系统的URI地址(内部接口) -->
    <property>
		<name>fs.defaultFS</name>
		<value>hdfs://master:9000</value>
	</property>
    <!--临时工作目录(默认一个月就删除) -->
	<property>
		<name>hadoop.tmp.dir</name>
		<value>file:/usr/local/hadoop/tmp</value>
	</property>
</configuration>

3.修改文件hdfs-site.xml

<configuration>
	<!--secondary namenode-->
    <property>
		<name>dfs.namenode.secondary.http-address</name>
		<value>master:50090</value>
	</property>
    <!-- hdfs存数据的分数-->
	<property>
		<name>dfs.replication</name>
		<value>3</value>
	</property>
    <!-- namenode 元数据所在物理地址-->
	<property>
		<name>dfs.namenode.name.dir</name>
		<value>file:/usr/local/hadoop/tmp/dfs/name</value>
	</property>
    <!--datanode数据,存储的物理地址-->
	<property>
		<name>dfs.datanode.data.dir</name>
		<value>file:/usr/local/hadoop/tmp/dfs/data</value>
	</property>
</configuration>

4.修改文件mapred-site.xml

<configuration>
    <!-- mapreduce程序运行在yarn上-->
	<property>
		<name>mapreduce.framework.name</name>
		<value>yarn</value>
	</property>
    <!-- job的服务器地址(内部通讯端口)-->
	<property>
		<name>mapreduce.jobhistory.address</name>
		<value>master:10020</value>
	</property>
    <!--历史服务器web端地址 -->
	<property>
		<name>mapreduce.jobhistory.webapp.address</name>
		<value>master:19888</value>
	</property>
</configuration>

5..修改文件yarn-site.xml

<configuration>	
    <!--指定ResourceManager的主机名(及Master节点) -->
	<property>
		<name>yarn.resourcemanager.hostname</name>
		<value>master</value>
	</property>
    <!--NodeManager提供的辅助服务,运行MapReduce必配-->
	<property>
		<name>yarn.nodemanager.aux-services</name>
		<value>mapreduce_shuffle</value>
	</property>
     <!--nodemanager监控本地磁盘的健康状况(磁盘上限98.5%)-->
	<property>
  	<name>yarn.nodemanager.disk-health-checker.max-disk-utilization-per-disk-percentage</name>
  	<value>98.5</value>
	</property>
</configuration>

6..修改文件hadoop-env.sh

export JAVA_HOME=/usr/local/java/jdk1.8.0_171
export HADOOP_CONF_DIR=/usr/local/hadoop/etc/hadoop

配置slave节点

1.将/usr/local/下面的Hadoop文件压缩成hadoop。master.tar.gz,并放在root文件夹下

tar -zcf ~/hadoop.master.tar.gz ./hadoop

2.将master这台机器上的root/hadoop.master.tar.gz这个压缩包上传复制到slave1这台电脑的/root路径下,并且登录slave1的账户是root

3.将~/hadoop.master.tar.gz的这个文件解压,而且解压到/usr/local文件夹下面

作业:查(-z c x v f 代表什么)

tar -zxvf ~/hadoop.master.tar.gz -C /usr/local/

格式化节点,配置集群的时候执行一次

hdfs namenode -format

启动hdfs

start-dfs.sh

master节点:namenode secondarynamenode DataNode(worker如果有localhost,就有)

slave1,2,3:DataNode

说明(core-site.xml  hdfs-site.xml有问题)

172.18.0.2:9870(ip地址)

启动yarm,必须是在启动了hdfs的前提条件下

start-yarm.sh(usr/local/hadoop/sbin)  stop-yarn.sh

master节点:resuorcemanager,nodemanager

slave1,2,3:nodemanager

172.18.0.2:8088

3.环境测试

启动hdfs start-dfs.sh

namenode(1个) secondary namenode(1个) datanode(slave1,slave2,slave3,master)

启动yarn   start-yarn.sh

resoucemanager(1个)  nodemanager(slave1,slave2,slave3,master)

启动顺序:start-dfs.sh --》start-yarn.sh

关闭顺序:stop-yarn.sh -->stop-dfs.sh

172.18.0.2:9870  172.18.0.2(namenode所在机器的ip) 9870是默认的web端访问hdfs的端口号

172.18.0.2:8088  172.18.0.2(resource manager所在电脑的ip地址)8088是默认的web端访问yarn的端口号

测试hdfs上传文件(每一步代码截图加解释)

1.创建一个本地文件high.txt

vi 文件名名字

2.创建一个hdfs的文件夹

hadoop fs -mkdir 文件夹路径和名字

3.将本地文件上传到hdfs系统里面的文件夹里

hadoop fs -put 本地文件的路径和名字 要上传到hdfs这个系统的具体路径

4.查看文件是否上传成功

引入:QQ邮箱 3503286860@qq.com ,逻辑地址(并不是真正意义上存放的地址)

物理地址:真实存放文件的地址

hdfs系统

逻辑地址:/gInput/high.txt

物理地址:hdfs里面配置了 /usr/local/hadoop/tmp/dfs/data

file:/usr/local/hadoop/tmp/dfs/data

/usr/local/hadoop/tmp/dfs/data/current/BP-522517698-172.18.0.2-1774322483887(你自己的id)/current/finalized/subdir0/subdir0

问题:hdfs存放数据,datanode真正存放数据的节点。hdfs默认存三份

mater,slave1,2,3存在哪几台机器上了?如下图:存放位置在master,slave1,slave2上面

上传大文件

本地有一个大文件

cd /usr/local/java/:进入/usr/local/java这个目录

ls:查看目录下子文件

cp被复制文件的地址和文件名 粘贴到哪儿的地址:复制文件

cd /:回到最顶层根目录 

ls查看

在hdfs系统创建一个新的文件夹。

hadoop fs -mkdir /文件名字(bigFiles)

在hadoop的web UI界面里查看HDFS目录内容

本地大文件上传到新的文件夹

Hadoop fs -put 源文件绝对路径 HDFS目标目录:上传到文件夹

​查看反思

hdfs系统存放文件是按照块存储。如果是大文件,分成多个块,分别存储。

hdfs:/bigFiles/jdk-8u171-linux-x64.tar.gz

物理地址:hdfs里面配置了 /usr/local/hadoop/tmp/dfs/data

wordcount测试

主任务:上传到/gInput/high.txt/统计文件每个单词出现的频率

1.确保你的HDFS系统里面/gInput/high.txt这个文件是存在的

副任务:修改配置文件mapreduce-site.xml

vim mapred-site.xml
cat mapred-site.xml

<configuration>
    <!-- 指定MapReduce运行在YARN上 -->
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>

    <!-- JobHistory Server服务地址 -->
    <property>
        <name>mapreduce.jobhistory.address</name>
        <value>master:10020</value>
    </property>

    <!-- JobHistory Web UI地址 -->
    <property>
        <name>mapreduce.jobhistory.webapp.address</name>
        <value>master:19888</value>
    </property>

    <!-- ApplicationMaster环境变量 -->
    <property>
        <name>yarn.app.mapreduce.am.env</name>
        <value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
    </property>

    <!-- Map任务环境变量 -->
    <property>
        <name>mapreduce.map.env</name>
        <value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
    </property>

    <!-- Reduce任务环境变量 -->
    <property>
        <name>mapreduce.reduce.env</name>
        <value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
    </property>
</configuration>
2.测试wordcount是否可以执行成果

cd /usr/local/hadoop/share/hadoop/mapreduce

hadoop jar jar包的名字 调用方法的名字 (wordcount) 输入路径(gInput/high.txt这个输入文件必须存在) 输出路径必须不存在(存在会报错)

3.解读wordcount(运行过程和结果展示)

mapreduce:map+reduce

是否成功:job completed successfully

1.常用端口

HDFS

一、HDFS

1.1HDFS产生的背景

随着数据量发越来越大,在一个操作系统存放不下所有数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。

1.2HDFS定义

HDFS(Hadoop Distributed(分布式) File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,有很多服务器联合起来实现其功能,集群中的服务器有各自的角色。

HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改,适合用来做数据分析,并不适合来做网盘应用。

1.3HDFS 的优缺点

优点:

(1)高容错性

1.数据自动保存多个副本。它通过增加副本的形式,提高容错性。

2.某一个副本丢失以后,它可以自动恢复。

(2)适合处理大数据

1.数据模型:能够处理数据规模达到GB、TB、甚至PB级别的数据;

2.文件规模:能够处理百万规模以上的文件数量,数量相当之大

(3)适可构建在廉价机器上,通过多副本机制,提高可靠性。

缺点:

(1)不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。

(2)无法高效的对大量小文件进行存储

        1.存储大量小文件的话,他会占用NameNode大量内存来存储文件目录和块信息。这样是不可取的,因为NameNode内存总是有限的;(理解 书包含目录和内容)

       2. 小文件存储的寻址时间会超过读取时间,他违反了HDFS的设计目标。

(3)不支持并发写入,文件随即机修改。

一个文件只能有一个写,不允许多个文件的随即修改

仅支持数据append(追加),不支持文件的随机修改。

1.4HDFS组成架构

NameNode(nn):就是master(老板),它是一个主管、管理员。

  1. 管理HDFS的名称空间
  2. 配置副本策略
  3. 管理数据库的映射信息
  4. 处理客户端的读写请求

DataNode:就是Slave.NameNode下达命令。DataNode执行实际的操作。

  1. 存储实际的数据块、
  2. 执行数据块的读写操作

Client:就是客户端

  1. 文件切分。文件上传HDFS的时候,Client将文件切分成一个一个Block(默认128M),然后进行上传(我上传high.txt文件,大小200M,默认一个block,134217728B/1024/1024=128M,存放两个Block,第一个128M,第二个72M)
  2. 与NameNode交互,获取文件位置信息
  3. 与DataNode交互,读取或写入数据
  4. Client提供一些命令来管理HDFS,比如NameNode格式化
  5. Client可以通过一些命令来访问HDFS,比如对HDFS增删改查操作 

Secondary NameNode:并非NameNode的热备,当Name Node挂掉时候,它不能马上替换NameNode并提供服务。

作业:Fsimage和Edits干什么的,原理是什么?

内存(快,断电容易丢失)edits:编辑文件

硬盘Fsimage:为了防止断电数据丢失,会落盘为fsimage

以上内容全部存在fsimage1

edits1:2026年4月14日10点30-10点40 新东西

edits2:2026年4月14日10点40-10点50 新东西

SecondaryNameNode:fsimage2=fsimage1+edits1+edits2

同步传给namenode,会存fsimage2

namenode(物理地址)

secondary namenode

只不过namenode会多一个edits inprogress

1.namenode fsimage edits 会跟secondarynamenode同步

2.secondarynamenode会把fsimage edits 加起来得到一个新的fsimage,传回给namenode

namenode(物理地址)

/usr/local/hadoop/tmp/dfs

1.5HDFS文件块大小(面试重点)

HDFS中的文件在物理上分块存储(Block),块的大小可以通过参数配置(dfs.blocksize)来规定,默认大小在Hadoop2.X版本128M,老版本64M

block1 block2 block3 ......block65 block66

1.如果寻址时间约为10ms,即找到目标block的时间为10ms

2.寻址时间为传输时间的1%时,则为最佳状态。传输时间=10ms/0.01=1000ms=1s

3.目前磁盘的传输速率普遍为100MB/S    块大小:100MB/s*1s=100M 128M

普通机械硬盘 80m/s-90m/s                    块大小:80-90M 128M,64m

固定硬盘 200m/s-300m/s                         块大小:200M-300M 256M

思考:为什么块的大小不能设置太小,也不能设置太大?

(1)HDFS的块设置太小,会增加寻址时间,程序一直在找块的开始位置(找目标块)

(2)如果块设置的太大,从磁盘传输数据的时间会明显大于定位这个块开始位置的时间(寻址时间)。导致程序的处理这块数据时,会非常慢

总结:HDFS块的大小设置主要取决于磁盘的传输速率

1.6.HDFS的shell常用命令

1.基本语法

bin/hadoop fs具体命令

bin/hdfs dfs具体命令

(0)启动Hadoop集群

bin/start-dfs.sh 启动hdfs

bin/start-yarn.sh 启动yarn

(1)-help:输出这个命令参数

hadoop fs -help rm :输出这个命令的相关解释及参数说明。

(2)-ls:显示目录信息

(3)-mkdir:在HDFS上创建文件夹

hadoop fs -mkdir -p /wangzherongyao/zhonglu

(4)-moveFromLocal:从本地剪切粘贴到HDFS

1.本地有一个文件

touch buzhihuowu.txt创建touch buzhihuowu.txt这个空文件

2.将本地文件剪切,粘贴到HDFS系统里面

hadoop fs -moveFromLocal本地文件 HDFS的路径

(5)-appendToFile:追加一个文件到已经存在的文件末尾(1上单英雄,2中单英雄,3发育英雄,4辅助英雄,5打野英雄,6中单英雄)

1.本地文件(一般有内容)

2.把本地文件内容放到(HDFS系统里面已经存在的)文件末尾

hadoop fs -appendToFile本地文件HDFS的文件:把本地文件内容放到HDFS文件末尾

【作业:选择盘古(完成文件的追加)】

创建并粘贴到HDFS

追加

(6)-cat :显示文件内容

(7)-chgrp,chmod,chown:Linux文件系统中的用法一样,修改文件所属权限

ch:change,grp:group分组,mod:mode权限,own:owner拥有者)

chgrp【R】组名 文件或者目录名:更改文件/目录所属的用户组

hadoop fs -chgrp新改的组名 文件或者文件夹

chown:修改文件/目录所有者

hadoop fs -chown更改所有者:组名 文件或者文件夹

chmod:[用户类别][操作符][权限]文件/目录

1.用户类别

u:所有者(usr)

g:所属者组·(group)

0:其他用户(other)

a:所有用户(all,默认)

3.操作符

+:添加权限

-:移除权限

=:直接设置权限(覆盖原有权限)

3.权限

r:读

w:写

x:执行

原有的权限命令现有的权限
usr原本rw-chmod u+x script.shusr的权限rwx
group的权限rw-chmod g-w data.txtgroup的权限r--
others的权限rwxchmod 0=r file.txtothers的权限r--

数字模式:

(8)chmod[数字组合]文件/目录

1.权限对应数字

r读=4

w写=2

x执行=1

-(无权限)=0

2.数字组合规则

将三类用户(所有者,组,其他用户)的权限,得到三位数字

第一位:所有者权限

第二位:组权限

第三位:其他用户权限

例1:rwxr-xr--

所有者:rwx 4+2+1=7

组:r-x  4+0+1=5

其他用户:r--  4+0+0=4

chmod 754 file.txt

例2,rw-r--r--

所有者:rw-  4+2+0=6

组:r--   4+0+0=4

其他用户:r--  4+0+0=4

chmod 644 file.txt

(9)-copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去

(10)-copyToLocal:从HDFS拷贝到本地

1.创建一个其他分路的文件夹(游走)

2.我们把王昭君从中复制到一个游走

(11)-mv:在HDFS目录中移动文件

1.先创建一个打野的文件夹

2.把不知火舞从中路移到打野的位置

(12)-get:等同于copyToLocal,从HDFS下载文件到本地

hadoop fs -get hdfs 系统里面的文件下载到本地存放路径

(13)-put:等同于copyFromLocal。上传本地文件到HDFS系统里面

hadoop fs -put 本地文件HDFS系统的存放路径

(14)-tail显示一个文件的末尾

(15)-rm:删除文件或者文件夹

hadoop fs -rm -r hdfs文件夹:删除hdfs系统里面的这个文件夹以及文件夹下面的所有文件

(16)-du统计文件夹的大小信息

(作业:-s -h 的解释和输出的数字是什么意思)

(17)-setrep:设置HDFS文件的副本数据

hadoop fs -setrep 数量 文件

(18)在hdfs系统里创建一个空的文件-touchz:

在hdfs系统里面创建一个名为two.txt的空文件

hadoop fs -touchz two.txt

1.7HDFS客户端操作(开发重点)

hdfs客户端代码 可以控制整个集群(master,slave1,slave2,slave3)

hdfs客户端代码(集群外的一台电脑) 可以控制整个集群(master,slave1,slave2,slave3)

<!--dependencies代表这个项目所有的依赖 -->
    <dependency>
    <!--junit单元测试类-->
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!--log4j 打印日志,日志等级-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.12.0</version>
    </dependency>
    <!--hadoop的客户端-->
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.1.3</version>
    </dependency>
</dependencies>
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig">
    <Appenders>
        <!-- 类型名为Console,名称为必须属性 -->
        <Appender type="Console" name="STDOUT">
            <!-- 布局为PatternLayout的方式,
            输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here -->
            <Layout type="PatternLayout"
                    pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" />
        </Appender>
 
    </Appenders>
 
    <Loggers>
        <!-- 可加性为false -->
        <Logger name="test" level="info" additivity="false">
            <AppenderRef ref="STDOUT" />
        </Logger>
 
        <!-- root loggerConfig设置 -->
        <Root level="info">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
 
</Configuration>

3.Hdfs.Client

package org.high; 

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Test;

import java.io.IOException;
import java.net.URI;

public class HdfsClient {

    @Test
    public void testMkdir() throws IOException, InterruptedException{
         //1.创建HDFS的客户端对象filesystem,发送了URI网址,配置对象,用户,请求连接集群
         FileSystem fileSystem = FileSystem.get(URI.create("hdfs://172.18.0.2:9000"),new Configuration(),"root");

         //2.登录HDFS成功,可以对HDFS做操作,所以我在hdfs系统里创建了一个aiqinggongyu的文件夹
        fileSystem.mkdirs(new Path("/aiqinggongyu"));

        //3.退出登录,关闭资源
        fileSystem.close();
    }
}
hdfs上传
  @Test
    public void testCopyFromLocalFile() throws URISyntaxException, IOException, InterruptedException {
        //1.
        连接集群的namenode地址,HDFS的链接地址
        URI uri = new URI("hdfs://172.18.0.2:9000");
        //创建一个配置文件
        Configuration configuration = new Configuration();
        //登陆用户
        String user = "root";
        //获取到HDFS客户端对象
        FileSystem fileSystem = FileSystem.get(uri, configuration, user);

        //2.操作HDFS系统
        //copyFromLocalFile从本地上传文件到HDFS系统
        //参数1:表示是否删除本地的原数据,参数2:是否覆盖HDFS里面已经存在的文件
        //参数3:需要上传的本地文件的路径地址,参数4:HDFS的目标地址(要上传到hdfs的那个位置的地址)
        fileSystem.copyFromLocalFile(false, true, 
new Path("/root/IdeaProjects/HdfsDemo/src/main/resources/zengxiaoxian.txt"), 
new Path("/aiqinggongyu"));

        //3.关闭资源
        fileSystem.close();
    }
}

public class HdfsCilentV1 {
    private FileSystem fileSystem;
    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        //1.
        URI uri = new URI("hdfs://172.18.0.2:9000");
        Configuration configuration = new Configuration();
        String user = "root";
        FileSystem fileSystem = FileSystem.get(uri, configuration, user);
    }
    @After
    public  void close() throws IOException {
        //3.
        fileSystem.close();
    }
    
    @Test
    public void testCopyFromLocalFile() throws URISyntaxException, IOException, InterruptedException {
        //2.
        fileSystem.copyFromLocalFile(false, true,
                new Path("/root/IdeaProjects/HdfsDemo/src/main/resources/zengxiaoxian.txt"),
                new Path("/aiqinggongyu"));


    }
}
测试参数优先级

客户端代码中设置的值>ClassPath下用户自定义配置文件>服务器的自定义配置(hadoop/etc/hadoop/xxx-site.xml) > 服务器的默认配置(xxx-default.xml)

public class HdfsClientV1 {
    // 1.
    private FileSystem fileSystem;

    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        URI uri = new URI("hdfs://172.18.0.2:9000");
        Configuration configuration = new Configuration();
        //configuration.set("dfs.replication","2");
        //System.out.println("dfs.replication"+configuration.get("dfs.replication"));
        String user="root";
        fileSystem=FileSystem.get(uri,configuration,user);
    }

    @After
    public void close() throws IOException {
        //2.
        fileSystem.close();
    }

    @Test
    public void testCopyFromLocalFile() throws URISyntaxException, IOException, InterruptedException {
        //2.
        fileSystem.copyFromLocalFile(false, true,
                new Path("/root/IdeaProjects/HdfsDemo/src/main/resources/zengxiaoxian.txt"),
                new Path("/aiqinggongyu"));
    }

    @Test
    public void testCopyToLocalFile() throws IOException {
        fileSystem.copyToLocalFile(false,
                new Path("/wangzherongyao/youzou/wangzhaojun.txt"),
                new Path("/root/IdeaProjects/HdfsDemo/src/main/resources/"),
                false);
    }
}

下载

public void testCopyToLocalFile() throws IOException {
        //copyToLocalFile 从HDFS系统里面下载文件到本地
        //参数1 boolean delsrc:是否删除HDFS上的源文件,参数2 Path src:hdfs上要被下载的文件路径
        //参数3path dst:要将文件下载到本地的路径
        //参数4 boolean useRawLocalFileSystem:是否开启文件严重(false下载完会有两个文件,crc校验文件;但如果是true,就不会有crc校验文件
        fileSystem.copyToLocalFile(false,
                new Path("/wangzherongyao/youzou/wangzhaojun.txt"),
                new Path("/root/IdeaProjects/HdfsDemo/src/main/resources/"),
                false);
    }

作业:测试上面两个boolean类型变成true会有什么效果

删除Delete
    @Test
    public void testDelete() throws IOException {
            File file=new File("/aiqinggongyu/zengxiaoxian.txt");
            //exists()判断文件是否存在
            if(file.exists()){
                  System.out.print("存在");
            }

           //delete删除HDFS里面的文件或者文件夹
           //参数1:要删除的文件或者文件夹,参数2:是否遍历
        fileSystem.delete(new Path("/aiqinggongyu/zengxiaoxian.txt"),false);
    }

删除爱情公寓的文件夹

HDFS文件名改动

@Test
    public void testRename() throws IOException {
//rename()这个方法是用来修改文件名字和移动文件的
//参数1:HDFS系统原本文件路径和名字,参数2:HDFS系统修改后的路径和名字
        fileSystem.rename(new Path("wangzherongyao/zhonglu/anqila.txt"),
                new Path("wangzherongyao/zhonglu/shuangmawei.txt"));
    }

移动

HDFS文件详情查看

查看文件名称、权限、长度、块信息

 public void testListFiles() throws IOException {  
      //listFiles()这个方法是返回/目录下所有子文件和子目录的详细信息,包括文件的长度、块大小、备份数、时间、所有者、权限
       //参数1:要遍历的目标起始路径  参数2:boolean recursive:是否递归遍历子目录。如果设置为ture时。会返回路径下所有子目录中的文件,false时仅返回当前目录下的直接文件
       //左边:右边listFiles()这个方法返回的所有信息都存储在左边listFiles里面                               
        RemoteIterator<LocatedFileStatus> listFile=fileSystem.listFiles(          
                new Path("/"),                                                    
                true); 
        //遍历                                                  
        while (listFile.hasNext()){  
             //status是 存储的listFiles里面的一天信息的对象                               
            LocatedFileStatus status=listFile.next();   
             //文件名称             
            System.out.println(status.getPath().getName());   
             //文件长度      
            System.out.println(status.getLen());  
             //文件权限                 
            System.out.println(status.getPermission());    
            //文件分组           
            System.out.println(status.getGroup());                                
            System.out.println("------");

            //获取一个文件存储的所有块信息,块信息存放在blockLocation(大文件会有多个块)                                                                                      
            BlockLocation[] blockLocations=status.getBlockLocations();            
            for (BlockLocation blockLocation:blockLocations){          
            //遍历一个文件每个块的hosts(他会包含多个节点,这取决于备份数和datanode有多少个节点           
                String[] hosts=blockLocation.getHosts(); 
            //遍历所有host                         
                for (String host:hosts){                                          
                    System.out.print(host+"|");                                   
                }                                                                 
                System.out.println();                                             
            }                                                                     
            System.out.println("+++++yitiaoxinxidejieshu++++++++++++++++++++++"); 
        }                                                                         
                                                                                  
    }                                                                             
                  

 @Test                                                                               
 public void testListStatus() throws IOException {     
      //获取在hdfs系统里面/根目录下,所有文件以及文件夹的状态                        
     FileStatus[] listStatus = fileSystem.listStatus(new Path("/"));、
     //遍历listStatus            
     for (FileStatus fileStatus : listStatus) {    
         //istFile()方法判断是不是文件                         
         if (fileStatus.isFile()) {                                                  
             System.out.println("wenjian:" + fileStatus.getPath().getName());        
         }else {                                                                     
             System.out.println("wenjianjia:"+fileStatus.getPath().getName());       
         }                                                                           
     }                    

hdfs写数据流程(面试重点)

(1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目录文件是否已经存在,父目录是否存在。(NameNode检查权限,检查目录结构)

(2)NameNode返回是否可以上传。

(3)客户端请求第一个Block上传到哪几个DataNode服务器上。

(4)NameNode返回3个DataNode节点,分别是dn1(DataNode1),dn2,dn3。(副本存储节点选择)

(5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。

(6)dn1,dn2,dn3逐级应答客户端。

(7)客户端开始往dn1上传第一个Block(从磁盘读取数据放到一个本地内存缓存),以Packet为单位·,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传给一个packet会放入一个应答队列等待应答。

(8)当一个Block传输完成后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7)

网络拓扑-节点距离计算

在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢?

节点距离:两个节点到达最近的共用祖先的距离总和。

Distance(d1/r1/n0,d1/r1/n0)=0;

Distance(d1/r1/n1,d1/r1/n2)=1+1=2;

Distance(d1/r2/n1,d1/r3/n2)=2+2=4;

机架感知(副本存储节点选择)

机架感知(replication副本存储节点选择):数据可靠性,传递速度快

第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个。(传输速度快)

第二个副本在另一个机架的随机一个节点。(数据可靠性)

第三个副本在第二个副本所在机架的随机节点。(速度)

hdfs读取数据流程

(1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。

(2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。

(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以packet为单位来做校验)

(4)客户端以packet为单位接收,先在本地缓存,然后写入目标文件。

NameNode中元数据存储在哪(内存,磁盘)

内存<----开机加载-----fsimage存储元数据,edits追加到信息----关机合并(不是实时)到fsimage

NameNode工作机制

第一阶段:NameNode启动

(1)第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件的内存。

(2)客户端对元数据进行增删改的请求

(3)NameNode记录操作日志,更新滚动日志

(4)NameNode在内存中对元数据进行增删改

第二阶段:SecondaryNameNode工作

(1)SecondaryNameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。

(2)SecondaryNaeNode请求执行CheckPoint

(3)NameNode滚动正在写的Edits日志。

(4)将滚动前的编辑日志和镜像文件拷贝到SecondaryNameNode

(5)SecondaryNameNode加载编辑日志和镜像文件到内存,并合并。

(6)生成新的镜像文件fsimage.chkpoint

(7)拷贝到fsimage.chkpoint到NameNode

(8)NameNode将fsimage.chkpoint重新命名fsimage。

DataNode工作机制

(1)一个数据块在DataNode上以文件形式存储的磁盘上,包括两个文件,一个数据本身,一个是元数据包括数据块长度、块数据的校验和、以及时间戳。

(2)DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。(跟老板汇报工作)

(3)心跳每三秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,会删除某个数据块。(保持副本数)如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。

(4)集群运行中可以安全加入和退出一些机器。(dataNode 10-->100)

MapReduce

1.1MapReduce定义

MapReduce是一个分布式运行程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。

MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组合整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。

1.2优缺点

优点

1.MapReduce易于编程

它简单的实现一些接口,就可以完成一个分布式程序,这个分布式程序可以分布到大量廉价的PC机器上运行,也就是说你写一个分布式程序,跟写一个简单的串行程序是一模一样的。就是因为这个特点是得MapReduce编程变得很流行。

2.良好的扩展性

当你的计算资源不能得到满足的时候,你可以通过简单的增加机器来扩展他的计算能力。

3.高容错性

MapReduce设计的初衷就是使程序能够部署在廉价的PC机器上,这就要求他具有很高的容错性。比如其中有台机器挂了,他可以把上面的计算任务转移到另外一个节点上运行,不至于这个任务运行失败,而且这个过程不需要人工参与,而完全是由Hadoop内部完成的。

4.适合PB级以上海量数据的离线处理

可以实现上千台服务器集群并发工作,提供数据处理能力。

缺点

1.不擅长实时计算

MapReduce无法像MySQL一样,在毫秒或者秒级内返回结果。

2.不擅长流式计算

流式计算的输入数据时动态的,而MapReduce的输入数据集是静态的,不能动态变化。这是因为MapReduce自身的设计特点决定了数据源必须是静态的。

3.不擅长DGA(有向图)计算

多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,导致性能非常的低下。

1.3 MapReduce进程
一个完整的MapReduce程序在分布式运行时有三类实力进程:

(1)MrAPPMaster:负责整个程序的过程调度及状态协调。

(2)MapTask:负责Map阶段的整个数据处理流程

(3)ReduceTask:负责Reduce阶段的整个数据处理流程

1.4常用数据序列化类型
java类型Hadoop Writable类型
Boolean

BooleanWritable

ByteByteWritable
IntIntWritable
FloatFloatWritable
LongLongWritable
DoubleDoubleWritable
StringText
MapMapWritable
ArrayArrayWritable
1.5MapReduce编程规范
用户编程的程序分为三类部分:Mapper,Reducer和Driver

1.Mapper阶段

(1)用户自定义的Mapper要继承自己的父类

(2)Mapper的输入数据是KV对的形式(kv的类型可自定义)

(3)Mapper中的业务逻辑写在map()方法里面

(4)Mapper的输出数据是KV对的形式(KV的类型可自定义)

(5)map()方法(MapTask进程)对每一个<K,V>调用一次

2.Reducer阶段

(1)用户自定义的Reducer要继承自己的父类

(2)Reducer的输入数据类型对应Mapper的输出类型,也是KV

(3)Reducer的业务逻辑写在reduce()方法

3.Driver阶段

相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象

wordcount案例

(1)输入数据

I am somebody
I am smart and kind
I am important
I am starved of education
I have places to go
I have people to impress
I have world to change

(2)

1 7

am 4

and 1

Mapper

k1代表偏移量,v1这一行的内容

Iamsomebody换行符
012345678910111213

<0,I am somebody>

<14,I am smart and kind>

<29,I am important>
<40,I am starve of education>
<51,I have places to go>
<63,I have people to impress>
<77,I have world to change>

map()

1.Mapper阶段
(1) 用户自定义的Mapper要继承自己的父类 extends Mapper
(2) Mapper的输入数据是KV对的形式(KV的类型可自定义)
(3) Mapper中的业务逻辑写在map()方法里面
(4) Mapper的输出数据是KV对的形式(KV的类型可自定义)
(5) map()方法(MapTask进程)对每一个<K,V>调用一次 我们有7行文件

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

//mapper输入key的类型:Longwritable
//mapper输入value的类型:Text
//mapper输出key的类型:Text
//mapper输出value的类型:Intwritable

public class wordCountMapper extends Mapper<LongWritable, 
Text, Text, IntWritable> {
    @Override
    protected void map(LongWritable key, Text value, Context context) 
throws IOException, InterruptedException {
         //将输入的value数据转换成string类型
         String line = value.toString();
        //将line整个字符串切割成单词
        // line "I am somebody"
        String[] words = line.split(" ");
        //遍历words
        for (String word : words) {
            //输出单词,还有单词的个数1(一定要注意输出的类型必须保持一致)
            context.write(new Text(word), new IntWritable(1));
        }
    }
    //输出
    //<I,1>
    //<am,1>
    //<somebody,1>
}

Reduce
mapper的输入
<0,l am somebody>
<14,1 am smart and kind>
<29,l am important>
<40,l am starve of education>
<51,l have places to go>
<63,l have people to impress>
<77,1 have world to change>

mapper的输出:

map()  执行完后的结果<1,1>,<am,1>,<somebody,1>
map()执行完后的结果<1,1>,sam,1>,<smart,1>,<and,1>,<kind,1>
map()执行完后的结果<1,1>,<am,1>,<important,1>

shuffle过程

<I,<1,1,1,1,1,1,1>

<am,<1,1,1>>

<somebody,1>

Reduce输出

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

//mapper输入key的类型:Longwritable
//mapper输入value的类型:Text
//mapper输出key的类型:Text
//mapper输出value的类型:Intwritable

public class wordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
         //将输入的value数据转换成string类型
         String line = value.toString();
        //将line整个字符串切割成单词
        // line "I am somebody"
        String[] words = line.split(" ");
        //遍历words
        for (String word : words) {
            //输出单词,还有单词的个数1(一定要注意输出的类型必须保持一致)
            context.write(new Text(word), new IntWritable(1));
        }
    }
    //输出
    //<I,1>
    //<am,1>
    //<somebody,1>
}
wordcountDriver

要背下来(手敲)

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

public class wordCountDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        //1.获取配置信息以及封装任务,获得一个job对象
        Configuration configuration=new Configuration();
        Job job=Job. getInstance(configuration);

        //2.设置jar加载路径(就是自己的本类,生成的class文件
        job.setJarByClass(wordCountDriver.class);

        //3.设置map和reduce类
        job. setMapperClass(wordCountMapper.class);
        job. setReducerClass (wordCountReduce.class);

        //4.设置map输出的key和value
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //5.设置最终输出的key和value
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //6.设置输入和输出路径
        FileInputFormat.setInputPaths(job,new Path("/root/IdeaProjects/mapReduceTest/src/main/resources/high.txt"));
        FileOutputFormat. setOutputPath(job,new Path("/root/IdeaProjects/mapReduceTest/src/main/resources/output"));
        
        //7.提交
        boolean result=job.waitForCompletion(true);
        System.exit(result?0:1);
    }
}

 本地测试

输入文件和输出文件都在本地

执行Driver类,结果如下

使用HDFS系统作为文件的输入输出测试

1.启动HDFS系统

2.修改Driver类代码的路径

3.执行Driver类,可以看到生成了anqilaOutput文件夹,具体结果如下

在集群上测试

1.启动HDFS系统和YARN

2.修改pom.xml文件(注意:mainClass必须跟的是整个项目的启动类,即我们写的Driver类)

<plugins>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>2.3.2</version>
      <configuration>
        <source>1.8</source>
        <target>1.8</target>
      </configuration>
    </plugin>
    <plugin>
      <artifactId>maven-assembly-plugin </artifactId>
      <configuration>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
          <manifest>
            <mainClass>wordCountMain</mainClass>
          </manifest>
        </archive>
      </configuration>
      <executions>
        <execution>
          <id>make-assembly</id>
          <phase>package</phase>
          <goals>
            <goal>single</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    </plugins>

3.修改代码

将输入输出的路径设为可以输入的参数

4.打包(双击package,会生成一个target文件夹,文件夹下面会有两个jar包)

5.上传jar包到集群

目前我们所生成的jar包所在地址为cg这台电脑上面的

/root/IdeaProjects/mapReducceTest/target/mapReduceTest-jar-with-dependencies.jar

现在需要上传到resourceManager所在电脑上(master)

scp /root/IdeaProjects/mapReducceTest/target/mapReduceTest-jar-with-dependencies.jar root@172.18.0.2:/usr/local/hadoop

查看是否上传成功,在master机器上执行

6.执行jar包

在master使用如下命令

hadoop jar mapReduceTest-jar-with-dependencies.jar /anqila.txt /yarnOutput

可以通过YARN的客户端查看运行的各个状态

7.最后结果

作业(1.认真看diver各行代码和注释

2.创建一个新的工程

输入:

学号,姓名,第一次作业成绩,第二次,第三次

01,xiaohua,85,82,96

02,xiaoming,45,60,47

03,lily,85,49,90

04,rose,75,65,70

01,xiaohua,85,82,96

02,xiaoming,45,60,47

03,lily,85,49,90

04,rose,75,65,70

创建一个txt文件,文件内容如下:

输出:

学号,最好的一次成绩

01 96

02 60

03 90

04 75

01 96

02 60

03 90

04 75
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

//map 输入 key:LongWritable
//map 输入 value:Text   01,xiaohua,85,82,96
//map 输入 key:Text   01
//map 输入 value:IntWritable
public class zhcjMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    @Override
    protected void map(LongWritable key,Text value,Context context) throws IOException, InterruptedException {
        //01,xiaohua,85,82,96
        //1.Text类型转换String类型
        String line=value.toString();
        
        //2.切割String类型,split(“,”)"01,xiaohua,85,82,96"
        String[] parts=line.split(",");
        
        //3.xuehao=parts[0]  第一行就是01
        String xuehao=parts[0];

        //4.遍历三次成绩
        for(int i=2;i<parts.length;i++){
            //String类型转换成int类型
            int score=Integer.parseInt(parts[i]);
            //输出,输出的两个参数,第一个是输出的key,第二个数输出的value
            context.write(new Text(xuehao),new IntWritable(score));
        }
        //shuchu
    }
}
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

//reduce 输入 key:Text
//reduce 输入 value:IntWritable
//reduce 输出 key:Text
//reduce 输出 value:IntWriable
public class zhcjReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
    @Override
    //输入 :01,<85,82,96>
    //输出 :01,96
    protected void reduce(Text key,Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
        int max=0;
        //遍历所有的成绩,找到做高的成绩
        for(IntWritable value:values){
            if(value.get()>max){
                //注意这里获取具体的值是get()方法
                max=value.get();

            }
        }
        //输出write方法
        context.write(key,new IntWritable(max));
    }
}
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;

public class zhcjDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        //1.获取配置信息以及封装任务
        Configuration configuration = new Configuration();
        Job job = Job.getInstance(configuration);
        
        //2.设置jar加载路径(程序入口,自己的driver类+.class)
        job.setJarByClass(zhcjDriver.class);

        //3.设置Mapper和Reducer类(你自己的mapper和Reducer类名)
        job.setMapperClass(zhcjMapper.class);
        job.setReducerClass(zhcjReducer.class);


        //4.设置map的输出key和value的类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //5.设置最终输出key和value的类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //6.设置输入和输出路径
        FileInputFormat.setInputPaths(job,new Path("/root/IdeaProjects/zuihaochengjiMapReduce/src/main/resources/chengjidan.txt"));
        FileOutputFormat.setOutputPath(job,new Path("/root/IdeaProjects/zuihaochengjiMapReduce/src/main/resources/output"));
        
        //7.提交
        boolean result = job.waitForCompletion(true);
        System.exit(result?0:1);
    }
}

MapReduce核心框架原理

一、InputFormat数据输入

InputFormat功能:数据切分、为Mapper提供输入数据

1.切片

(1)问题引出

Map Task的并行度决定Map阶段的任务处理并发度,进而影响到整个Job的处理速度。

(Map Tas不是越多越好)

(2)Map Task并行度决定机制

数据块:Block是HDFS物理上把数据分成一块一块。(默认Block大小128M)

数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。

MapTask个数,决定Job并行度。MapTask的个数取决于数据切片的个数。

MapTask并进度决定机制

(1)一个Job的Map阶段并行度由客户端在提交Job时的切片数决定

(2)每一个Split切片分配一个MapTask并行实例处理 s.exists()

(3)默认情况下,切片大小=BlockSize=128M

(4)切片时不考虑数据集整体,而是逐个针每一个文件单独切片(不管你有几个文件,一个文件一个文件处理,不会让两个文件合并在一起了再切)

、例子

输入:data1.txt 300M  data2.txt  1M

切片大小设置为128M

切片:切片1:0M-128M   切片2:129M-256M  切片3:256M-300M 切片4:0M-1M

切片大小计算公式:Math.max(minSize,Math.min(maxSize,blockSize))

Math.max(1,Math.min(最大值,blockSize))=Math.max(1,blockSize)=blockSize

Math.max(1,6)=6;

Math.min(1,6)=1;

问题:一个文件400MB,设置最小分片(minSize)为256MB,最大(maxSize)就是默认值,

BlockSize=128MB,最终切分为多少?有多少个MapTask任务

Math.max(256,Math.min(最大值,128))=Math.max(256,128)=256

切片1:0-256M  切片2:257-400M

两个Map Task任务

2.FileInputFormat实现类

InputFormat是一个抽象类,定义了一个MapReduce作业必须实现的标准规范

FileInputFormat 同样是一个抽象类,它继承自InputFormat

FileInputFormat常见的接口实现类包括:TextInputFormat、KeyValueTextInputFormat、

NLineInputFormat、CombineTextInputFormat和自定义InputFormat

TextInputFormat是默认的FileInputFormat实现类

MapReduce的默认输入格式是?TextInputFormat

二、输出数据OutputFormat

OutputFormat接口实现类

OutputFormat是MapReduce输出的基类,所有实现MapReduce输出实现了OutputFormat接口。

OutputFormat的实现类有TextOutputFormat,SequenceFileOutputFormat,自定义OutputFormat

默认的输出格式是TextOutputFormat,他把每条记录都写为文本行。

三、Shuffle

Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle。

3.1分区Partition

(1)问题引入

要求将统计结果按照条件输出到不同文件中(分区)。比如:将统计结果按照号码归属地不同省份输出到不同文件中(分区)

(2)默认Partition分区

默认分区是根据Key的hashCode对ReduceTasks个数取模(取余)得到的。用户无法控制哪个key存储到哪个分区。

什么是分区?Mapper任务划分数据的过程称作Partition。负责实现数据的类称作Partitioner,默认的分区是Hash分区(Hash Partition)。

Partition作用:将map阶段产生的所有<key;value>对分配给不同的Reducer处理,可以将Reduce阶段的处理负载进行分摊。

这里回答前面的问题,什么决定Reduce任务的数量,答案是:Partition的数量决定Reducer的数量

一般Reduce的任务数默认值是1,用户可以通过job.setNumReduce Tasks(数字)去设置Reduce的个数。 

在Drive类里面有这样的代码job.setNumReduce Tasks (5);代表有5个Reduce(默认1)


3.2合并Combinerc

(1)需求

统计过程中对每一个MapTask的输出进行局部汇总,以减少网络传输量即采用Combiner功能

是一种特殊Reducer,在Mapper端,先执行一次Reducer

作用:减少Mapper输出到Reduce的数据量,缓解网络传输瓶颈,提高reducer的执行效率。

需要注意的问题:一定要谨慎使用Combiner

有些情況不能使用Combiner —>如:求平均值

保证引入Combiner以后,不能改变原来的逻辑

combiner不是所有情况都能用

3.3Shuffle完整流程理解

分区前面还有一个溢出步骤

示例背景

假设有 2个 Map 任务处理以下输入数据:

• Map1 输出:
("apple",1), ("banana",1), ("apple", 1)

• Map2输出:
("banana", 1), ("apple", 1), ("cherry", 1)

最终需统计单词出现次数(WordCount),由2个 Reduce 任务处理(按首字母分区):

• Reduce1: 处理a-c (如 apple, banana, cherry)

•Reduce2:处理 d-z(本例无此类数据)

第一部分:Map任务处理

1. Map任务1输入:(apple, 1), (banana, 1),(apple,1)

2. Map任务2输入:(banana, 1), (apple, 1), (cherry,1)

3. Map输出:保持原始键值对

第二部分:Shuffle过程(核心)(Map端)

1. 分区(Partitioning):

    1. 所有数据分配到Partition 0

     2. 数据标记:(apple,P0),(banana,P0)等

2. Map端排序(Sorting):

    1. Map1排序后:(apple, 1),(apple, 1),(banana, 1)

    2. Map2排序后:(apple, 1),(banana, 1),(cherry,1)

3.Combiner(可选本地聚合):

    1. Map1聚合后:(apple, 2),(banana,1)

    2. Map2保持原样:(apple, 1),(banana, 1),(cherry,1)

第三部分:Reduce端处理 (shuffle)

1. 数据拉取(Fetch):

1. 来自Map1:(apple, 2),(banana,1)

2. 来自Map2:(apple, 1),(banana, 1),(cherry, 1)

2. 归并排序(Merge Sort):

1. 全局排序结果:(apple, 2), (apple,1),(banana, 1), (banana, 1),(cherry,1)

3. 分组(Grouping):

1. apple: [2, 1]

2. banana: [1, 1]

3.cherry: [1]

第四部分:Reduce任务处理

1.Reduce输入:分组后的数据
2.处理过程:对值求和sum(values)
3.最终输出:

1.(apple,3)

2.(banana,2)

3.(cherry,1)

Shuffle过程总结

阶段                 输入输出发生位置
分区(Partitioning)(Key,Value)(Partition,key,Value)Map端
排序(Sorting)(Partition,Key,Value)分区内按键排序的数据Map端
Combine排序后的(Key,Value)合并后的(Key,CombinedValue)Map端
数据拉取(Fetch)Map输出的磁盘文件属于同一分区的未排序数据Reduce端
归并排序(Merge)来自多个Map的同一个分区数据全局按键排序的数据Reduce端
分组(Grouping)排序后的(Key,Value)序列(Key,Iterable<Value>Reduce端

yarn

通过8088端口可以查看YARN的Web监控页面,该页面包含了YARN集群的基本信息,所有应用的基本信息等。

下图是YARN的架构图,它由Container,ResourceManager,NodeManager,ApplicationMaster几个主要部分组成。

YARN的架构是主从架构,主机为ResourceManager,从机为NodeManager,其中ResourceManager负责接收客户端的作业请求以及为作业分配相应的NodeManager资源,在NodeManager启动Container资源容器,在资源容器中运行相关作业。

(1)Container(容器):YARN中资源包括内存、CPU、磁盘输入输出等等。

Container是YARN中资源的抽象,它封装了某个节点上的多维度资源。

(2)ResourceManager(资源管理器)

ResourceManager负责整个系统的资源分配和管理,是一个全局的资源管理器。主要由两个组件构成:调度器和应用程序管理器:

调度器(Scheduler):

      调度器根据资源情况为应用程序分配封装在Container中的资源。

应用程序管埋器(Application Manager):

     应用程序管理器负责管理整个系统中所有应用程序。

(3)NodeManager(节点管理器)

NodeManager是每个节点上的资源和任务管理器。

定时向ResourceManager汇报本节点上的资源使用情况和各个Container的运行状态;

接收并处理来自ApplicationManager的NContainer启动/停止等请求。

(4)ApplicationMaster(主应用)

ApplicationMaster是一个详细的框架库,它结合从 ResourceManager 获得的资源和NodeManager 协同工作来运行和监控任务。

用户提交的每一个应用程序均包含一个ApplicationMaster。

主要功能包括:

1)、与ResourceManager调度器协商以获取抽象资源(Container);

2)、负责应用的监控,跟踪应用执行状态,重启失败任务等;

3)、并且与NodeManager协同工作完成Task的执行和监控。

yarn中应用运行机制

YARN调度器分三种

(1)FIFO Scheduler  先进先出调度器

(2)Capacity Scheduler 容器调度器(YARN默认采用这个)

(分成多个列队,每个队列占用一定资源,可以看作是FIFO Scheduler的多队列版本)

(3)Fair Scheduler 公平调度器

调度器工作方法
FIFO Schedule

(1)单队列

(2)先进先出

Capacity Scheduler

(1)多队列

(2)计算能力调度器,选择资源使用量占用最小、优先级高的先执行

(3)多用户的情况下,可以最大化集群的吞吐和利用率

Fair Scheduler

(1)多队列

(2)公平调度,所有的job具有相同的资源

【背表】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值