大模型和大数据的关系
40ZB
b(bit)比特 最小的信息单元0或者1
B(Byte)字节 1B=8bit 汉字
KB 千字节 1KB=1024B 小段文字
MB 兆字节 1MB=1024KB 一首歌3-5M
GB 吉字节 1GB=1024MB 一部电影
TB 太字节 1TB=1024GB 数据库(25万张高清图片)
PB 拍字节 1PB=1024TB 公司数据中心,云服务提供商
EB 艾字节 1EB=1024PB 全球级别 全球天气观测数据
ZB 泽字节 1ZB=1024EB 全球数量总数40ZB
YB 尧字节 1YB=1024ZB
E·R(画图)
1.1 大数据的定义

TB PB EB
结构化数据: 固定格式 关系型数据库,excel,
半结构化数据:具有一定的层次结构,介于结构化数据与非结构化数据之间 json文件,xml文件,电子邮件
非结构化数据:无固定格式 文本文件,图片,音乐
大数据技术要面对的基本问题,也是最核心的问题:就是海量数据如何可靠存储和高效计算。
letcood网站学算法。
1.2 Google的三驾马车
GFS:The Google File System HDFS
MapReduce:Simplified Data Processing on Large Clusters 大型集群上的简单数据处理
Bigtable:A Distributed Storage System for Structured Data 一个分布式的结构化数据存储系统Hbase
1.2.1 GFS的思想

(1)Google思想一:GFS分布式文件系统

GFS架构:
(1)GFS Master节点管理所有的文件系统元数据,包括命名空间,访问控制权,文件和块的映射信息以及当前块的位置信息。
(2)GFS存储的文件都被分割成固定大小的块,每个块都会被复制到多个块服务器上(可靠性)。块的冗余度默认为3。
(3)GFS Master还管理着系统范围内的活动,比如块服务器之间的数据迁移等。
(4)GFS Master与每个块服务器通信(发送心跳包),发送指令,获取状态。
副本的位置选择策略要满足两个目标:最大化数据的可靠性和可用性。
1.2.2 MapReduce的思想

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

1.3 Hadoop的概述
13.1.Hadoop是什么?
(1)Hadoop是由一个Apache基金会所开发的分布式计算基础框架。
(2)主要解决,海量数据的存储和海量数据的分析计算问题。
(3)广义上来讲,Hadoop通常是指一个更广泛的概念--Hadoop生态圈。
1.3.2.Hadoop根据是Google三篇论文实现
HDFS ——> GFS
MapReduce ——> MapReduce
HBase ——> BigTable
HDFS:Hadoop Distribute File System,是Hadoop项目的核心子项目,是分布式技术中数据存储管理的基础。


1.3.3

1.0与2.0的差别就是多了一个YARN

1.3.4 Hadoop的优势(重要)
高可靠性:Hadoop底层维护多个数据副本,所以即使Hadoop某个计算元素或存储出现故障,也不会导致数据的丢死。
高扩展性:在集群分配任务数据,可方便的扩展数以千计上午节点。
高效性:在MapReduce的思想下,Hadoop是并行工作的,以加快任务处理速度。
高容错性:能够自动将失败的任务重新分配。
1.3.5 Hadoop生态圈
| 组件 | 功能 |
| HDFS | 分布式文件系统 |
| YARN | 资源管理和调度器 |
| MapReduce | 分布式并行编程模型 |
| HBase | Hadoop上的非关系型的分布式数据库 |
| Hive | Hadoop上的数据仓库 |
| Pig | 一个基于Hadoop的大规模数据分析平台,提供类似SQL的查询语言Pig Latin |
| Flume | 一个高可用的,高可靠的,分布式的海量日志采集,聚合和传输的系统 |
| Sqoop | 用于在Hadoop与传统数据库之间进行数据传递 |
| Zookeeper | 提供分布式协调一致性服务 |
| Ambari | Hadoop快速部署工具,支持Apache Hadoop集群的供应,管理和监控 |
| Mahout | 提供一些可扩展的机器学习领域经典算法的实现 |
| Spark | 类似于Hadoop MapReduce的通用并行框架 |
| Oozie | Hadoop上的工作流管理系统 |
| Storm | 流计算框架 |
| Kafka |
一种高吞吐量的分布式发布订阅消息系统,可以处理消费者规模的网站中的所有动作流数据 |
1.4 Hadoop的组成
1.4.1 HDFS架构概述

NameNode:存储文件的元数据,如文件名,文件目录结构,文件属性(生成时间,副本数,文件权限),以及每个文件的块列表和块所爱的DataNode等。
DataNode:在本地文件系统存储文件块数据,以及块数据的校验和。
Secondary NameNode:每隔一段时间对NameNode元数据备份。
1.4.2 YARN架构概述

ResourceManager整个集群资源(内存,cpu等)的老大:
NodeManager单个节点服务器资源老大。
ApplicationMaster:单个任务运行的老大。(1)负责数据的切分(2)为应用程序申请资源并分配内部任务(3)任务的监控与容错
Container:容器,相当于一台独立的服务器,里面封装了任务运行所需要的资源,如内存,cpu,磁盘,网络等。
1.4.3 MapReduce架构
MapReduce将计算过程分为两个阶段:Map和Reduce
Map阶段并行处理输入数据
Reduce阶段对Map结果进行汇总
2.环境安装
用来将一个Docker镜像从 /cg/images/hadoop_node.tar.gz压缩包加载到本地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
docker run --name slave1 --privileged --ulimit nofile=65535:65535 --hostname slave1 --ip 172.18.0.3 --add-host=master:172.18.0.2 --add-host=slave2:172.18.0.4 --add-host=slave3:172.18.0.5 -itd -v /cgsrc:/cgsrc:ro hadoop_node /service_start.sh
docker run --name slave2 --privileged --ulimit nofile=65535:65535 --hostname slave2 --ip 172.18.0.4 --add-host=master:172.18.0.2 --add-host=slave1:172.18.0.3 --add-host=slave3:172.18.0.5 -itd -v /cgsrc:/cgsrc:ro hadoop_node /service_start.sh
docker run --name slave3 --privileged --ulimit nofile=65535:65535 --hostname slave3 --ip 172.18.0.5 --add-host=master:172.18.0.2 --add-host=slave1:172.18.0.3 --add-host=slave2:172.18.0.4 -itd -v /cgsrc:/cgsrc:ro hadoop_node /service_start.sh
docker run创建并启动一个docker容器
--name master:容器的名字叫做master
--privileged:赋予容器特权模式。允许它访问主机上所有设备
--ulimit nofile=65535.65535 设置容器的最大文件描述符数量(软限制/硬限制)。默认值较小,Hadoop、HDFS等大数据组件会频繁打开文件/网络连接,必须调高避免“too many open files”

启动容器
docker start容器的名字
3.进入容器
docker exec-it--privileged 容器的名字/bin/bash
4.安装Java环境
1.cd /usr/local
第三周:
1.配置分布式模式
HDFS:NameNode(1个)DataNode(多个)SecondaryNameNode(1个)
NameNode和SecondaryNameNode尽量不要安装在同一台服务器
YARN:ResourceManager(1个) NodeManager(多个)
ResourceManager很消耗内存尽量不要和NameNode,SecondaryNameNode放在同一台机器上
| Hadoop1 | Hadoop2 | Hadoop3 | Hadoop4 |
|
NameNode | DataNode | DataNode |
DataNode SecondaryNameNode |
| NodeManager |
NodeManager ResourceManager | NodeManager | NodeManager |
2.ping ip地址:ICMP协议,测试两台计算机之间的连通性(OSI第三层)
ping master
ssh
Secure Shell(安全外壳协议)
一台电脑 --->另外一台电脑(有密码)
客户端--->服务端
场景:陈长湦寄一个箱子给高珊珊,这个箱子比较私密,中途不能让人打开。
1.高珊珊打造了一把锁(公钥)和一把钥匙(私钥)。
2.高珊珊把这把锁(公钥)给了陈长湦,但是钥匙高珊珊自己藏好。(把公钥放到服务器)
3.陈长湦把箱子用高珊珊给他的锁锁上。(用公钥加密)
4.箱子寄出去,中途任何没有钥匙的人都打不开。
5.只有高珊珊可以用她的钥匙打开。
高珊珊:客户端
陈长湦:服务端
生成公钥和私钥
ssh-keygen -t rsa
ssh文件夹下的文件功能解释:
| known_hosts | 记录ss访问过计算机的公钥(public key) |
| id_rsa | 生成的私钥 |
| id_rsa.pub | 生成的公钥 |
| authorized_key | 存放授权过的无密码登录服务器公钥 |
将公钥文件追加到另一个文件authorized_keys中
cat 。/id_rsa.pub >> /authorized_keys
3.scp从一台电脑的-/.ssh/id_rsa.pub的文件,复制到slave1这台电脑上,用户是root
2.2克隆
安全拷贝
1.从Hadoop102服务器上将本服务器的文件推给Hadoop103:
scp -r jdk1.8.0_212/ lotus@hadoop103:/opt/module/
2.在Hadoop103服务器上操作,将Hadoop102的文件拿过来
scp -r lotus@102:/opt/module/jdk1.8.0_212/ ./
同理Hadoop也可以这么操作
scp -r lotus@102:/opt/module/hadoop-3.1.3/ ./
3.在服务器上,将102的文件拷贝到104
scp -r lotus@hadoop102:/opt/module/* lotus@hadoop104:/opt/module/
master登录slave1,slave2,slave3(免密)
slave1 登录到master(没有密码)
实现场景:在slave1里面执行命令ssh master,就可以不输入密码master
1.slave1先生成私钥和公钥
2.slave1的公钥给到master
scp
3.在master上公钥给放到~/.ssh/atuorized_keys
4.去slave1里面测试ssh master
安装Hadoop
1.将hadoop包复制到/usr/local下面
2.解压
tar解压,压缩
-z使用gzip解压
x解压文件
v显示解压过程
f制定文件名
3.修改名字
mv旧的名字 新名字
mv hadoop-3.4.0 hadoop
4.修改配置文件
vim~/.bashrc
在配置文件中

1.bin:存放操作命令,具体包含如(hdfs,mapred,yarn)
2.etc:所有配置文件
配置集群环境
/usr/local/hadoop/etc/hadoop/的配置文件
workers(DataNode节点)
core-site.xml整个集群的核心配置
hdfs-site.xml配置hdfs
mapred-site.xml配置mapreduce
yarn-site.xml配置yarn
hadoop-env.sh
1.编辑workers
vimworkers
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>
<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>
<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
<configuration>
<!-- 指定resource Manager的主机名在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>
配置slave节点
1.将/usr/local/下面的hadoop文件压缩成hadoop.master.tar.gz,并放到root文件下
tar -zcf ~/hadoop.master.tar.gz ./hadoop
2.将master这台机器上的root/hadoop.master.tar.gz这个压缩包上传复制到
3.将~/hadoop.master.tar.gz的这个文件解压
3.环境测试
启动hdfs start-dfs.sh
namenode(1个) secondary namenode(一个) datanode(slave1 slave2 slave3 master)
resoucemanager(1个) nodemanager(master,slave1,2,3)
启动顺序:start-dfs.sh --> start-yarn.sh
关闭顺序:stop-yarn.sh --> stop-dfs.sh
172.18.0.2:9870(9870是默认的web端访问hdfs的端口号) 172.18.0.2(namenode所在机器的ip)
172.18.0.2:8088 172.18.0.2(resouce manager所在电脑的ip地址)8088是默认的web端访问yarn端的端口号
测试hdfs上传文件
1.创建一个本地文件zrw.txt
2.创建一个hdfs的文件夹
3.将本地文件上传到hdfs系统里面的文件夹里
4.查看文件是否上传成功
引入:QQ邮箱 2330551568@qq.com ,逻辑地址(并不是真正意义上存放文件的地址)
物理地址:真实存放文件的地址
hdfs系统
逻辑地址:/zInput/zrw.txt
物理地址:hdfs里面配置了 /usr/local/hadoop/tmp/dfs/data
file:/usr/local/hadoop/tmp/dfs/data
问题:hdfs存放数据,datanode是真正存放数据的节点。hdfs默认存三份
master slave1 slave2 slave3存在那几台机器上了?


测试大文件上传
1.本地有一个大文件
cp被复制文件的地址和文件名粘贴到哪儿的地址
![]()
2.在HDFS系统里面创建一个新的文件

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

4.查看,反思


hdfs系统存放文件是按照块存储。如果是大文件,分成多个块,分别存储。
hdfs: /bigFiles/jkd-8u171-linux-x64.tar.gz
物理地址(实际存放的位置) /usr/local/hadoop/tmp/dfs/data hdfs-site.xml

cat blk_1073741826 >>tmp.tar.gz 将blk_1073741827 >>tmp.tar.gz
tar -zxvf tmp.tar.gz

wordcount测试
上节课上传了小文件,上传到HDFS(/minput/lotus.txt),我们统计这个文件里面每个单词出现的频率。
1.确保你的HDFS系统里面/minput/lotus.txt这个文件是存在的
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=/usr/local/hadoop</value>
</property>
2.测试wordcount是否可以执行成果
cd /usr/local/hadoop/share/hadoop/mapreduce/

hadoop jar hadoop-mapreduce-examples-3.4.0.jar wordcount /zInput/lotus.txt /zOutput
hadoop jar jar包的名字 调用方法的名字(wordcount) 输入路径(/zInput/lotus.txt这个输入文件必须存在) 输出路径(必须不存在,如果以及存在会报错)
3.解读wordcount运行过程和结果展示

mapreduce :map + reduce
是否成功:job completed successfully
多了一个mOutput,说明有输出


查看结果
hadoop fs -cat 文件路径和文件名

4.面试重点
1.常用端口号
hadoop3.X
| HDFS NameNode内部通常端口 | 8020/9000/9820 |
| HDFS NameNode对用户的查询端口 | 9870 |
| Yarn查看恩物运行情况的端口 | 8088 |
| 历史服务器 | 19888 |
hadoop2.X
| HDFS NameNode内部通常端口 | 8020/9000 |
| HDFS NameNode对用户的查询端口 | 50070 |
| Yarn查看恩物运行情况的端口 | 8088 |
| 历史服务器 | 19888 |
2.常用的配置文件
3.x core-site.xml hdfs-site.xml yarn-site.xml mapred-site.xml workers (/hadoop/etc/hadoop)
2.x core-site.xml hdfs-site.xml yarn-site.xml mapred-site.xml slaves
HDFS
一、HDFS概述
1.1 HDFS产生背景
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件系统管理中的一种。
1.2 HDFS定义
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改,适合用来做数据分析,并不适合来做网盘应用。
1.3 HDFS的优缺点
优点:
(1)高容错性
- 数据自动保存多个副本。它通过增加副本的形式,提高容错性。
- 某一个负样本丢失以后,它可以自动恢复。
(2)适合处理大数据
- 数据规模:能够处理数据规模达到GB、TB、甚至PB级别的数据;
- 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
(3)可构建在廉价机器上,通过多副本机制,提高可靠性。
缺点:
(1)不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。
(2)无法高效的对大量小文件进行存储。
- 存储大量小文件的话,他会占用NameNode大量的内存来存储文件目录和块信息。这样是不可取的,因为NameNode的内存总是有限的;(理解 书包含目录和内容)
- 小文件存储的寻址时间会超过读取时间,它违反了HDFS的设计目标。
(3)不支持并写入,文件随即修改。
一个文件只能有一个写,不允许多个线程同时写;
仅支持数据append(追加),不支持文件的随机修改。
1.4 HDFS组成架构

NameNode(nn):就是Master(老板),它是一个主管、管理者。
- 管理HDFS的名称空间;
- 配置副本策略;
- 管理数据块的映射信息;
- 处理客户端的读写请求。
DataNode:就是Slave。NameNode下达命令。DataNode执行实际的操作。
- 存储实际的数据块。
- 执行数据块的读/写操作。
Client:就是客户端
- 文件切分。文件上传HDFS的时候,Cilent将文件切分成一个一个Block,然后进行上传。 (我上传zrw.txt文件,文件大小为200M,正常默认一个Block 134217728B/1024/1024=128M,存两个Block,第一个128M,第二个72M)
- 与NameNode交互,获取文件的位置信息;
- 与DataNode交互,读取或者写入数据;
- Cilent提供一些命令来管理HDFS,比如NameNode增删改查操作;
- Cilent可以通过一些命令来访问HDFS,比如对HDFS增删改查操作。
Secondary NameNode:并非NameNode的设备,当NameNode挂掉的时候,它不能马上替换NameNode并提供服务。 (没有解释,作业:Fsimage和Edits是干什么的,原理是什么)
- 辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode;
- 在紧急情况下,可辅助恢复NameNode。
作业:Fsimage和Edits:
内存(优点:快 缺点:断电容易丢失)edits:编辑文件
硬盘 (Fsimage:为了防止断电数据丢失,会落盘为fsimage
以上内容全部存为fsimage1
edits1:2026年4月14日10:30——10:40 新的东西
edits2:2026年4月14日10:30——10:50 新的东西
Secondary NameNode:fsimage2=fsimage1+edits1+edits2
同步传给NameNode,会存fsimage2
namenode

secondary namenode

只不过namenode会多一个edits inprogress
1. namenode fsimage edits 会跟secondarynamenode同步
2. fsimage edits加起来得到一个新的fsimage,传回给namenode
namenode(物理地址)
/usr/local/hadoop/tmp/dfs
1.5 HDFS文件块大小(面试重点)
HDFS中的文件在物理上分块存储(Block),块的大小可以通过参数配置(dfs.blocksize)来规定,默认大小在Hadoop2.X版本是128M,老版本是64M。
block1 block2 block3 block4 ......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操作(10分)
1.基本的语法
bin/hadooop fs 具体命令
bin/hdfs dfs 具体命令
两个完全相同

2.常用命令
(0) 启动Hadoop集群
sbin/start-dfs.sh 启动hdfs系统
sbin/start-yarn.sh 启动yarn
(1)-help:输出这个命令参数
hadoop fs -help rm :输出rm这个命令相关的解释

错误:重启
(2) -ls:显示目录信息

(3)-mkdir: 在HDFS上创建文件夹
hadoop fs -mkdir -p /wangzherongyao/zhonglu

(4)-moveFromLocal:从本地剪切粘贴到HDFS
1.本地有一个文件
touch buzhihuowu.txt 创建buzhihuowu.txt这个空文件

2.将本地的文件剪切(ctrl+x),粘贴到HDFS系统里面
hadoop fs -moveFromLocal 本地文件HDFS的路径


(5)-appendToFile:追加一个文件到已经存在的文件末尾。(第一组:上单的英雄,第二组:中单,第三组:发育,第四组:辅助,第五组:打野,第六组:中单)
1.本地文件(一般是有内容的)


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

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

(7)-chgrp,chmod,chown:Linux文件系统中的用法一样,修改文件所属权限
(ch:change,grp:group分组,mod:mode权限,own:owner拥有者)

charp [R] 组名 文件或者目录名:更改文件/目录所属的用户组
hadoop fs -chgrp 新改的组名 文件或者文件夹

chown:修改文件/目录所有者
hadoop fs -chown 更改为所有者:组名 文件或者文件夹


chmod [用户类别] [操作符] [权限] 文件/目录 (修改文件/目录的权限)
1.用户类别
u:所有者(user)
g:所属者组(group)
o:其他用户(others)
a:所有用户(all,默认值)
2.操作符
+:添加权限
-:移除权限
=:直接设置权限(覆盖原有的权限)
3.权限
r:读
w:写
x:执行 (-代表没有权限)
| 原有的权限 | 命令 | 现有的权限 |
| user原本rw- | chmod u+x script.sh | user的权限rwx |
| group的权限rw- | chmod g-w data.txt | group的权限r-- |
| others的权限rwx | chmod o=r file.txt | others的权限是r-- |
数字模式:
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- 6
组:r-- 4
其他用户:r-- 4+0+0=4
chmod 644 file.txt

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


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

(10)-cp:从HDFS的一个路径拷贝到HDFS的另一个路径
1.创建一个其他分路的文件夹(游走)

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



(11) -mv:在HDFS目录中移动文件
1.先在HDFS创建一个打野的文件夹。

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 /zOutput Deleted /zOutput
(16) -du 统计文件夹的大小信息(作业:查一下解释)

(17)-setrep:设置HDFS文件的副本数量
hadoop fs -setrep副本数量

(18)-touchz:在hdfs系统里创建一个空的文件
在hdfs系统里面创建一个名为two.txt的空文件
hadoop fs -touchz two.txt
1.7HDFS客户端操作(开发重点)
master(shell),slave1,slave2,slave3
hdfs客户端代码(集群外的一台电脑)可以控制整个集群(master slave1 slave2 slave3)
法1:pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
法2:log4j2.xml
<?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.如果期末考操作系统第一步和第三步是一样的
法1:
package org.zrw;
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的客户端对象filesSystem, (发送了uri网址,配置对象,用户),请求连接集群
//2.登录hdfs成功,可以对HDFS做操作,所以我在HDFS系统里创建了一个aiqinggongyu的文件夹
fileSystem.mkdirs(new Path("/aiqinggongyu"));
//.3退出登录,关闭资源
fileSystem.close();
}
}
法2:
package org.zrw;
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的客户端对象filesSystem, (发送了uri网址,配置对象,用户),请求连接集群
URI uri=new URI(“hdfs://172.18.0.2:9000");
configuration conf=new configuration();
String user="root";
//FileSystem.get不一定有三个参数,也可能是1或者2个
FileSystem fileSystem=FileSystem.get(uri,conf,user1);
//2.登录hdfs成功,可以对HDFS做操作,所以我在HDFS系统里创建了一个aiqinggongyu的文件夹
fileSystem.mkdirs(new Path("/aiqinggongyu"));
//.3退出登录,关闭资源
fileSystem.close();
}
}
上传
@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();
}
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;
import java.net.URISyntaxException;
public class HdfsClientV1 {
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);
}
public void close(){
//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"));
}
}
测试参数优先级
(1) 客户端代码中设置的值 > (2) ClassPath下用户自定义配置文件 > (3) 服务器的自定义配置(hadoop/etc/hadoop/xxx-site.xml) > (4) 服务器的默认配置(xxx-default.xml)

1


2


下载


public void testCopyToLocalFile() throws IOException {
//copyToLocalFile从HDFS系统里面下载文件到本地
//参数1 boolean delsrc:是否删除HDFS上的源文件 ,参数2 Path src:hdfs上要被下载的文件路径
//参数3 path 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会有什么效果
删除
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);
}
没有遍历会报错 除非是空文件


执行true删除文件


HDFS文件名更改/移到

将anqila改为shuangmawei
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:是否递归遍历子目录。如果设置为true时,会返回路径下所有子目录中的文件;false时仅返回当前目录下的直接文件
//左边:右边listFiles()这个方法返回来的所有信息都存储在左边listFiles里面
RemoteIterator<LocatedFileStatus> listFiles=fileSystem.listFiles(new Path("/"),
true);
//遍历
while (listFiles.hasNext()){
//status是 存储的listFiles里面的一条信息 的对象
LocatedFileStatus status=listFiles.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("------");
//获取一个文件存储的所有块信息,块信息存放在blockLocations(大文件会有多个块)
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++++++++++++++++++");
}
}
hdfs判断是文件还是文件夹
public void testListStatus() throws IOException {
//获取在hdfs系统里面/根目录下,所有文件以及文件夹的状态
FileStatus[] listStatus=fileSystem.listStatus(new Path("/"));
//遍历listStatus
for (FileStatus fileStatus:listStatus){
//isFile()方法判断是不是文件
if (fileStatus.isFile()){
System.out.println("wenjian:"+fileStatus.getPath());
}else {
System.out.println("wenjianjia"+fileStatus.getPath().getName());
}
}
}
hdfs写数据流程(面试重点)

(1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否以及存在,父目录是否存在。(Name Node检查权限,检查目录结构)
(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;
Distance(d1/r2/n0,d2/r4/n1)=3+3=6;

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

第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个。(传输速度快)
第二个副本在另一个机架的随机一个节点。(数据可靠性)
第三个副本在第二个副本所在机架的随机节点。(速度)
hdfs读取数据流程

(1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
(2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)
(4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
namenode(nn)和Secondarynamenode(2nn)
NameNode中元数据存储在哪儿?(内存,磁盘)
内存<------开机加载------fsimage存储元数据,edits追加的信息------关机合并到fsimage
NameNode工作机制

第一阶段:NameNode启动
(1)第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode记录操作日志,更新滚动日志。
(4)NameNode在内存中对元数据进行增删改。
第二阶段:Secondary NameNode工作
(1)Secondary NameNode询问NameNode是否需要CheckPoint。直接带回NameNode是否检查结果。
(2)Secondary NameNode请求执行CheckPoint。
(3)NameNode滚动正在写的Edits日志。
(4)将滚动前的编辑日和镜像文件拷贝到Secondary NameNode。
(5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
(6)生成新的镜像文件fsimage.chkpoint。
(7)拷贝fsimage.chkpoint到NameNode。
(8)NameNode将fsimage.chkpoint重新命名fsimage。
DataNode工作机制

(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度、块数据的校验和、以及时间戳。、
(2)DataNode启动后会向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。(跟老板汇报工作)
(3)心跳是每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【属于YARN】:负责整个程序的过程调度及状态协调。
(2) MapTask:负责Map阶段的整个数据处理流程
(3) ReduceTask:负责Reduce阶段的整个数据处理流程

1.4常用数据序列化类型
| Java类型 | Hadoop Writable类型 |
| Boolean | BooleaWritable |
| Byte | ByteWritable |
| Int | IntWritable |
| Float | FloatWritable |
| Long | LongWritable |
| Double | DoubleWritable |
| String | Text |
| Map | MapWritable |
| Array | ArrayWritable |
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() 方法中
(4)ReduceTask进程对每一组相同的<K,V>组调用一次reduce() 方法
3.Driver阶段
相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是封装了MapReduce程序相关运行参数的job对象。
wordCount案例
(1)输入数据
I am somebody
I am smart and kind
I am Important
I am starve of education
I have places to impress
I have world to change
(2)
1 7
am 4
and 1
k1代表偏移量,v1这一行的内容
|
I | a | m | s | o | m | e | b | o | d | y | 换行符 | |||
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
<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>
1.Mapper阶段
(1)用户自定义
mport 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输出valuede类型:IntWritable
public class wordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
@Override
protected void map(LongWritable key1, 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,I am somebody> 会调用一次map()
<14,I am smart and kind> 会调用一次map()
<29,I am important> 会调用一次map()
<40,I am starve of education> 会调用一次map()
<51,I have places to go> 会调用一次map()
<63,I have people to impress> 会调用一次map()
<77,I have world to change> 会调用一次map()
mapper的输出
map()执行完后的结果<1,1>, <am,1>, <somebody,1>
map()执行完后的结果<1,1>, <am,1>,<smart,1>,<and,1>,<kind,1>
map()执行完后的结果<1,1>, <am,1>,<important,1>
map()执行完后的结果<1,1>, ...
map()执行完后的结果<1,1>, ...
map()执行完后的结果<1,1>, ...
map()执行完后的结果<1,1>, ...
shuffile过程
<I,<1,1,1,1,1,1,1,>>
<am,<1,1,1,>>
<somebody,1>
Reduce的输出
<I,7>
<am,3>
<somebody,1>
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的类型:IntWritable
public class wordCountReducer extends Reducer<Text, IntWritable, Text,IntWritable> {
@Override
protected void reduce(Text k3,Iterable<IntWritable> value3,Context context) throws IOException, InterruptedException {
//累加,初始单词个数是0
int total=0;
//遍历reduce输入的value
for (IntWritable v:value3){
total+=v.get(); //total=total+v.get(); 累加单词出现的次数
}
//reduce的输出<单词,单词的个数>
context.write(k3,new IntWritable(total));
}
}
Driver
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.设置Mapper和Reducer类
job.setMapperClass(wordCountMapper.class);
job.setReducerClass(wordCountReducer.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/heyao"));
FileOutputFormat.setOutputPath(job,new Path("/root/IdeaProjects/mapReduceTest/src/main/resources/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/mapReduceTest/target/mapReduceTest-jar-with-dependencies.jar
现在需要上传到resourceManager所在电脑上(master)
scp /root/IdeaProjects/mapReduceTest/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的客户端查看运行的各个状态

8.最后结果


作业:
1.认真看一下driver各行代码和注释
2.创建一个新的工程
输入: 学号,姓名,第一次作业成绩,第二次作业成绩,第三次作业成绩
txt文件:
01,heyao,85,82,96
02,xiaoming,45,60,47
03,lily,85,49,90
04,rose,75,65,7
创建一个txt文件,文件内容如下:
输出:
学号,最好成绩
01 96
02 60
03 90
04 75
Mapper类
01,xiaohua,85,82,96
输出01,<85,82,96>
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:IntWriitable
public class zuihaodechengjiMapper 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(“,”)双引号里面是什么就按照什么切割,切割完是String的数组parts{“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
//01,85
//01,82
//01,96
}
}
Reducer类
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:IntWritable
public class zuihaodechengjiReducer 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));
}
}
Driver
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 zuihaodechengjiDriver {
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(zuihaodechengjiDriver.class);
//3.设置Mapper和Reducer类(你自己的Mapper和Reducer的类名)
job.setMapperClass(zuihaodechengjiMapper.class);
job.setReducerClass(zuihaodechengjiReducer.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/zuihaodechengjiMapReduce/src/main/resources/chengjidan.txt"));
FileOutputFormat.setOutputPath(job,new Path("/root/IdeaProjects/zuihaodechengjiMapReduce/src/main/resources/output"));
//7.提交
boolean result=job.waitForCompletion(true);
System.exit(result?0:1);
}
}
Job job=Job.getInstance(configuration);
job.setJarByclass(zuihaochengjiDriver.class)
MapReduce的核心框架原理


一、InputFormat数据输入
InputFormat功能:数据切分、为Mapper提供输入数据
1.切片
(1)问题引出
Map Task 的并行度决定Map阶段的任务处理并发度,进而影响到整个Job的处理速度。(Map Task不是越多越好)
(2)Map Task并行度觉得机制
数据块:Block是HDFS物理上把数据分成一块一块(默认Block的大小是128M)
数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。
Map Task个数,决定job并行度,Map Task的个数取决于数据切片的个数。
map Task并行度决定机制
(1)一个Job的Map阶段并行度由客户端在提交Job时的切片数决定
(2)每一个Split切片分配一个Map Task并行实例处理
s.exists()查看s是否存在 s.split(“”)把s分割
(3)默认情况下,切片大小=BlockSize=128M
(4)切片时不考虑数据集整体,而是逐个针对每个文件单独切片(不管你有几个文件,一个文件一个文件的处理,不会让两个文件合并在一起再切)
eg例子:
输入data1.txt 300M data2.txt 1M
切片大小设置为128M
切片:切片1:0M-128M 切片2:129-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.max(1,6)=1;
一个文件400MB,设置最小分片(minSize)为256MB,设置最大分片(maxSize)就是默认值,BlockSize=128M,求最终切片为多少?有多少个Map Task任务?
Math.max(256,Math.min(最大值,128))=Math.max(256,128)=256
切片1:0-256M 切片2:256-400M
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)。
Parttition作用:将map阶段产生的所有<key,value>对分配给不同的Reducer处理,可以将Reduce阶段的处理负载进行分摊。
这里回答前面的问题,什么决定Reduce任务数量,答案是:Partition的数量 决定Reducer的数量
一般Reduce的任务数默认值为1,用户可以通过job.setNumReduceTasks(数字)去设置Reduce的个数。
在Driver类里面有这样的代码job.setNumReduceTasks(5);代表有5个Reduce。
3.2合并Combiner
(1)需求
统计过程中对每一个MapTask的输出进行局部汇总,以减少网络传输量即采用Combiner功能。
Combiner是一种特殊Reducer,在Mapper端,先执行一次Reducer
作用:减少Mapper输出到Reduce的数量,缓解网络传输瓶颈,提高reducer的执行效率。
需要注意的问题:一定要谨慎使用Combiner
有些情况不能使用Combiner----->如:求平均值
保证引入Combiner以后,不能改变原来的逻辑。

3.3 Shuffle完整流程理解
map方法之后,Reduce方法之前的数据处理过程称之为Shuffle


分区前面还有一个溢出的步骤。
示例背景
假设有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过程(核心)
1.分区(Partitioning):
1.所有数据分配到Partition0
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)
| 阶段 | 输入 | 输出 | 阶段 |
| 分区(Partitioning) | (key,value) | (partition,key,value) | Map端 |
| 排序(Sorting) | (partition,key,value) | 分区内按键排序的数据 | Map端 |
| combiner(可选) | 排序后的(key,value) | 合并后的(key,CombinedValue) | Map端 |
| 数据拉取(Fetch) | Map输出的磁盘文件 | 属于同一分区的未排序数据 | Reduce端 |
| 归并排序(Merge) | 来自多个Map的同一分区数据 | 全局按键排序的数据 | Reduce端 |
| 分组(Grouping) | 排序后的(key,value)案例 | (key,Iterable<Value>) | Reduce端 |
Yarn
用star-yarn.sh命令启动YARN之后,用jps命令查看YARN的基本组件,包括:ResourceManager和NodeManager。
下图是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的Container启动/停止等请求。
(4)ApplicationMaster (主应用)
ApplicationMaster是一个详细的框架库,它结合从 ResourceManager获得的资源和NodeManager协同工作来运行和监控任务。
用户提交的每一个应用程序均包含一个ApplicationMaster。
主要功能包括:
1)、与ResourceManagen调度器协商以获取抽象资源 (Container) ;
2)、负责应用的监控,跟踪应用执行状态,重启失败任务等;
3)、并且与NodeManager协同工作完成Task的执行和监控。
yarn中应用运行机制

yarn的监控

Yarn调度器
YARN调度器分三种:
(1)FIFO Scheduler ——>先进先出调度器(队列)
最简单的调度器
job1运行完后,job2才能获取到资源
(2)Capacity Scheduler ——>容器调度器(YARN默认采用Capacity Scheduler)
分成多个队列,每个队列占用一定资源可以看作是FIFO Scheduler的多队列版本。
每个队列可以限制资源使用量。但是,队列间的资源分配以使用量作排列依据,使得容量小的队列有竞争优势。
注意:如果不限制某队列最大容量,则运行过程中,它可以占用全部资源。
(3)Fair Scheduler ——>公平调度器
刚开始,job1占用100%资源
job2提交后,job1、job2各占50%
job2运行完后,job1又占100%
三种调度器比较
| 调度器 | 工作方法 |
|
FIFO Scheduler (先进先出调度器) |
(1)单队列 (2)先进先出原则 |
|
Capacity Scheduler (容器调度器) |
(1)多队列 (2)计算能力调度器,选择资源使用量占用最小、优先级高的先执行 (3)多用户的情况下,可以最大化集群的吞吐和利用率 |
|
Fair Scheduler (公平调度器) |
(1)多队列 (2)公平调度,所有的job具有相同的资源 |


被折叠的 条评论
为什么被折叠?



