目录
目录
HDFS
HDFS_Shell 命令
一般hadoop fs 具体命令 或 hdfs dfs 具体命令
常用命令实操
上传
//剪切 -moveFromLocal从本地剪切粘贴到HDFS
[wyc@hadoop102 hadoop-3.1.3]$ vim shuguo.txt
[wyc@hadoop102 hadoop-3.1.3]$ hadoop fs -moveFromLocal ./shuguo.txt /sanguo
//复制 -copyFromLocal 从本地文件系统中拷贝文件到HDFS路径去
[wyc@hadoop102 hadoop-3.1.3]$ vim weiguo.txt
[wyc@hadoop102 hadoop-3.1.3]$ hadoop fs -copyFromLocal weiguo.txt /sanguo
//复制 -put等同于copyFromLocal更简单
[wyc@hadoop102 hadoop-3.1.3]$ vim wuguo.txt
[wyc@hadoop102 hadoop-3.1.3]$ hadoop fs -put wuguo.txt /sanguo
//追加一个文件到已经存在的文件末尾
[wyc@hadoop102 hadoop-3.1.3]$ vim liubei.txt
[wyc@hadoop102 hadoop-3.1.3]$ hadoop fs -appendToFile liubei.txt /sanguo/shuguo.txt
下载
//下载 -copyToLocal:从HDFS拷贝到本地
[wyc@hadoop102 hadoop-3.1.3]$ hadoop fs -copyToLocal /sanguo/shuguo.txt ./
//下载 -get 等同于copyToLocal,生产环境更习惯用get 可以改名
[wyc@hadoop102 hadoop-3.1.3]$ hadoop fs -get /sanguo/shuguo.txt ./shuguo2.txt
HDFS直接操作
显示目录信息
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -ls /sanguo
-cat:显示文件内容
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -cat /sanguo/shuguo.txt
-chgrp、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -chmod 666 /sanguo/shuguo.txt
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -chown atguigu:atguigu /sanguo/shuguo.txt
//-mkdir:创建路径
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mkdir /jinguo
-cp:从HDFS的一个路径拷贝到HDFS的另一个路径
//[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -cp /sanguo/shuguo.txt /jinguo
//-mv:在HDFS目录中移动文件
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mv /sanguo/wuguo.txt /jinguo
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mv /sanguo/weiguo.txt /jinguo
//-tail:显示一个文件的末尾1kb的数据
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -tail /jinguo/shuguo.txt
//-rm:删除文件或文件夹
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -rm /sanguo/shuguo.txt
//-rm -r:递归删除目录及目录里面内容
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -rm -r /sanguo
//-du统计文件夹的大小信息 查看总大小
[wyc@hadoop102 hadoop-3.1.3]$ hadoop fs -du -s -h /jinguo
27 81 /jinguo //27表示文件大小;81表示27*3个副本;/jinguo表示查看的目录
//列出分大小
[wyc@hadoop102 hadoop-3.1.3]$ hadoop fs -du -h /jinguo
14 42 /jinguo/shuguo.txt
7 21 /jinguo/weiguo.txt
6 18 /jinguo/wuguo.txt
//-setrep:设置HDFS中文件的副本数量 在网页也可以直接修改
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -setrep 10 /jinguo/shuguo.txt
HDFS的API操作
package com.atguigu.hdfs;
import jdk.nashorn.internal.ir.CallNode;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.yarn.webapp.hamlet2.Hamlet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.security.auth.login.AppConfigurationEntry;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
/**
* 客户端代码套路
* 1、获取一个客户端对象
* 2、执行相关的操作命令
* 关闭资源
* 代表 HDFS zookeeper
*/
public class HdfsClient {
private FileSystem fs;
@Before
public void init() throws URISyntaxException, IOException, InterruptedException {
//连接集群nn地址
URI uri = new URI("hdfs://hadoop102:8020");
//创建一个配置文件
Configuration configuration = new Configuration();
//参数1 文件名 副本数
configuration.set("dfs.replication", "2");
//用户
String user = "wyc";
//获取客户端对象
fs = FileSystem.get(uri, configuration, user);
}
@After
public void close() throws IOException {
//关闭资源
fs.close();
}
//创建目录
@Test
public void testmakdir() throws URISyntaxException, IOException, InterruptedException {
//创建一个文件夹
fs.mkdirs(new Path("/xiyou/huaguoshan1"));
}
@Test
//上传
/*
参数优先集级(从小到大)
hdfs-default.xml -> hdfs-site.xml -> 在资源目录resources下的配置文件 -> 代码里面的配置
*/
public void testPut() throws IOException {
//参数解读:参数1 是否删除source源原数据,参数2 是否允许重复,参数3 源数据路径,参数4 目标地路径
fs.copyFromLocalFile(false, true, new Path("D:\\huaguoshan\\sunwukong.txt"), new Path("hdfs://hadoop102/xiyou"));
}
@Test
//文件下载
public void testGet() throws IOException {
//参数1 原文件是否删除 参数2 原文件的路径(hdfs) 参数3 目标地址路径windows 参数4 是否开启csc校验,false为打开
fs.copyToLocalFile(true, new Path("hdfs://hadoop102/xiyou/huaguoshan"), new Path("D:\\"), true);
}
@Test
//删除文件
public void testRm() throws IOException {
//参数1 要删除的文件/目录路径 参数2 是否递归删除
//fs.delete(new Path("/wuguo.txt"),false);
//删除空目录
//fs.delete(new Path("/xiyou"),false);
//删除非空目录
fs.delete(new Path("/jinguo"), true);
}
//文件的更名和移动
@Test
public void tastmv() throws IOException {
//参数1 原文件路径 参数2 目标文件路径
//文件名称的修改
// fs.rename(new Path("/input/word.txt"),new Path("/input/ss.txt"));
//文件的移动及更名
//fs.rename(new Path("/input/ss.txt"),new Path("/cls.txt"));
//目录的更名
fs.rename(new Path("/input"), new Path("/output"));
}
@Test
//获取文件详情信息
public void fileDetail() throws IOException {
//参数1 查看那个路径下的文件信息 参数2 是否递归
//获取所有文件信息
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
//得到的是一个迭代器,需要遍历
while (listFiles.hasNext()) {
LocatedFileStatus fileStatus = listFiles.next();
System.out.println("==============" + fileStatus.getPath() + "=============");
System.out.println(fileStatus.getPermission());
System.out.println(fileStatus.getOwner());
System.out.println(fileStatus.getGroup());
System.out.println(fileStatus.getLen());
System.out.println(fileStatus.getModificationTime());
System.out.println(fileStatus.getReplication());
System.out.println(fileStatus.getBlockSize());
System.out.println(fileStatus.getPath().getName());
//获取块信息
BlockLocation[] blockLocations = fileStatus.getBlockLocations();
System.out.println(Arrays.toString(blockLocations));//打印数组的值不是地址
}
}
//判断是文件夹还是文件
@Test
public void testFiles() throws IOException {
FileStatus[] listStatus = fs.listStatus(new Path("/"));
for (FileStatus status : listStatus) {
if (status.isFile()) { //判断他的状态是文件吗
System.out.println("这是一个文件" + status.getPath().getName());
} else {
System.out.println("这是一个目录" + status.getPath().getName());
}
}
}
}
HDFS的写数据流程
客户端向集群上传数据:
先创立一个分布式文件系统(Distributed Filesystem) ——> Namenode 检查权限及目录结构是否可以上传,检查后向客户端响应可以上传,并根据(结点可用,距离最近,负载均衡)筛选并询问客户端请求第一个 Block上传到哪几个DataNode服务器上——> 数据建立通信管道(请求及应答) ——> 数据以chunk为单位形成Packet进行上传(逐级上传)——> 数据一边上传一在ack队列中备份(接受应答信息,应答成功后才将队列中备份数据删除),应答失败则从ack中继续生成Packet——> 当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。
网络拓扑-节点距离计算
在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。
节点距离:两个节点到达最近的共同祖先的距离总和。
机架感知(副本存储节点选择)
第一个副本在Client所处的节点上。如果客户端在集群外,随机选一个。
第二个副本在另一个机架的随机一个节点
第三个副本在第二个副本所在机架的随机节点
HDFS读数据流程
(1)客户端通过DistributedFileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
(2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。(原则:距离最近,负载均衡)
(3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。(串行读取)
(4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
NN和2NN工作机制
FsImage:在磁盘中备份元数据(备份操作结果)
Edits文件:(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。(记录操作过程)
这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。
SecondaryNamenode:专门用于FsImage和Edits的合并。
NN 和 2NN 的区别是NN中有记录最新的edits-inprogress操作,2NN没有。
Fsimage和Edits解析
NameNode被格式化之后,将在/opt/module/hadoop-3.1.3/data/tmp/dfs/name/curent目录中产生如下文件
fs image 0000000000000000000
fs image 0000000000000000000. md5
seen_ txid .
VERSION
(1) Fsimage文件: HDFS文件系统元数据的一个永久性的检查点,中包含HDFS文件系统的所有目
和文件inode的序列化信息。
(2) Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先
会被记录到Edits文件中。
(3) seen txid文件保存的是一个数字, 就是最后一个edits 的数字
(4)每次NameNode 启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并。(默认1小时合并一次)
(5)VERSION:记录当前Namenode的空间id以及集群id,NN和2NN需要id一致时才会执行数据
oiv查看Fsimage文件:
基本语法:hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
sz 文件名 (传输到win系统中)
[wyc@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000343 -o /opt/software/fsimage.txt
oev查看Edits文件
基本语法:hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径
[wyc@hadoop102 current]$ hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-3.1.3/edits.xml
CheckPoint时间设置
(1)通常情况下,SecondaryNameNode每隔一小时执行一次。
(2)一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。
DataNode工作机制
(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后(NameNode返回主持成功信息),周期性(6小时)的向NameNode上报所有的块信息。
DN向NN汇报当前解读信息的时间间隔,默认6小时。
DN扫描自己节点块信息列表的时间,默认6小时。
(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令,如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用,将不会在和这台DateNode进行数据的读写。
数据完整性
如下是DataNode节点保证数据完整性的方法。
(1)当DataNode读取Block的时候,它会计算CheckSum。
(2)如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。
(3)Client读取其他DataNode上的Block。
(4)常见的校验算法crc(32),md5(128),sha1(160)
(5)DataNode在其文件创建后周期验证CheckSum。
掉线时限参数设置
DataNode进程死亡或者网络故障造成DataNode无法与NameNode通信,NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。
HDFS默认的超时时长为10分钟+30秒。
如果定义超时时间为TimeOut,则超时时长的计算公式为:
TimeOut =2 * dfs .namenode.heartbeat. recheck -interval + 10 * dfs.heartbeat interval。
而默认的dfs .namenode .heartbeat.recheck interval大小为5分钟,dfs heartbeat interva1默认为3秒。(可根据机器配置自行设置)
MapReduce
MapReduce概述
MapReduce定义
MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。
MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。
优点:易于编程,用户只关心业务逻辑。实现框架的接口
良好的扩展性:可以动态的增加服务器,解决计算资源不够的问题。
高容错性:任何一台挂掉,可以将任务转移到其他节点
适合海里数据计算(TB/PB)几千台服务器共同计算。
缺点:不擅长实时计算。(不能像MySQL这样毫秒级查询)
不擅长流式计算。(Sparkstreaming flink擅长)
不擅长DAG(有向无环图)计算 (spark 擅长)
MapReduce核心思想
(1)分布式的运算程序往往需要分成至少2个阶段。
(2)第一个阶段:Map阶段,MapTask并发实例,完全并行运行,互不相干。
(3)第二个阶段:Reduce阶段,ReduceTask并发实例互不相干,但是他们的数据依赖于上一个阶段的所有MapTask并发实例的输出。
(4)MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那就只能多个MapReduce程序,串行运行。
MapReduce进程
一个完整的MapReduce程序在分布式运行时有三类实例进程:
(1)MrAppMaster:负责整个程序的过程调度及状态协调。
(2)MapTask:负责Map阶段的整个数据处理流程。
(3)ReduceTask:负责Reduce阶段的整个数据处理流程。
常用数据序列化类型
Java类型 | Hadoop Writable类型 |
Boolean | BooleanWritable |
Byte | ByteWritable |
Int | IntWritable |
Float | FloatWritable |
Long | LongWritable |
Double | DoubleWritable |
String | Text |
Map | MapWritable |
Array | ArrayWritable |
Null | NullWritable |
MapReduce编程规范
1. Mapper阶段
(1)用户自定义的Mapper要继承自己的父类
(2) Mapper的输入数据是KV对的形式(KV的类型可自定义)
(3) Mapper中的业务逻辑写 在map0方法中.
(4) Mapper的输出数据是KV对的形式(KV的类型可自定义)
(5)map()方法(MapTask进程)对每一个<K,V>调用一次
2. Reducer阶段
(1)用户自定义的Reducer要继承自己的父类
(2) Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
(3) Reducer的业务逻辑写在reduce()方法中
(4) Reduce Task进程对每一组相同k的<k,v> 组调用一次reduce()方法
3. Driver阶段
相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是
封装了MapReduce程序相关运行参数的job对象
WordCount案例实操
package com.wyc.mapreduce.wordcount;
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;
/**
KEYIN, map阶段输入的key的类型,偏移量LongWritable 类型
VALUEIN, map阶段输入的value的类型,Text类型
KEYOUT, map阶段输出的key的类型,Text类型
VALUEOUT, map阶段输出的value的类型,IntWritable类型
*/
public class WordcountMapper extends Mapper <LongWritable, Text,Text, IntWritable>{
private Text outK = new Text();
private IntWritable outV = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//1.获取一行信息
//atguigu atguigu
String line = value.toString();
//2.用空格切割
//atguigu
//atguigu
String[] words = line.split(" ");
//3.循环写出
for (String word : words) {
//key时单词 word需转换成text类型
//封装outK
outK.set(word);
//写出
context.write(outK,outV);
}
}
}
package com.wyc.mapreduce.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
KEYIN, Reduce阶段输入的key的类型,Text类型
VALUEIN,Reduce阶段输入的value的类型,IntWritable类型
KEYOUT,Reduce阶段输出的key的类型,Text类型
VALUEOUT, Reduce阶段输出的value的类型,IntWritable类型
*/
public class WordCountReducer extends Reducer <Text, IntWritable,Text,IntWritable>{
private IntWritable outV = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//Iterable<IntWritable> 是一个集合
int sum =0;
// atguigu (1,1)
//累加
for (IntWritable value : values) {
sum += value.get();
}
outV.set(sum);
//写出
context.write(key,outV);
}
}
package com.wyc.mapreduce.wordcount;
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 conf = new Configuration();
Job job = Job.getInstance(conf);
//2.设置jar路径
job.setJarByClass(WordcountDriver.class);
//3.关联mapper reducer
job.setMapperClass(WordcountMapper.class);
job.setReducerClass(WordCountReducer.class);
//4.设置map输出的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//5.设置最终输出的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//6.设置输入路径和输出路径
FileInputFormat.setInputPaths(job,new Path("D:\\11_input\\inputword"));
FileOutputFormat.setOutputPath(job,new Path("D:\\wordcount-test\\output1"));
//7.提交job
boolean result = job.waitForCompletion(true);
System.exit(result ? 0 : 1);
}
}