Hadoop第二次学笔记(尚硅谷)

Hadoop历史

  1. 创始人 Doug Cutting,为了实现与Google类似的全文搜索功能,在Lucene框架基础上进行优化升级。
  2. 2001年,lucene成为apache的一个子项目
  3. lucene与Google一样,存储不了大数据,检索速度慢
  4. lucene学习Google:微型版Nutch
  5. Google 三篇论文 HDFS,MR,Hbase
  6. 2003-2004,创始人实现了DFS和mapreduce,使得Nutch性能飙升
  7. 2005年,hadoop作为lucene的子项目Nutch的一部分加入apache
  8. 2006年,MR和Nutch NDFS分别纳入Hadoop中,Hadoop诞生
  9. logo大象来自于其儿子的玩具
  10. apache,Hortonworks,cloudera爱恨情仇: apache开源,但是没有页面化,其他俩公司呢,看到了商机,于是创造了页面化,Hortoworks吸纳了雅虎工程师25到30名,这些工程师贡献了Hadoop80%的源码,与cloudera有一战之力,但2018年后来被cloudera收购。

Hadoop滴四大优势

  1. 高可靠性:一台机器坏,其他机器顶上不影响工作
  2. 高扩展性:双十一,动态增加服务器数量
  3. 高效性:Hadoop并行工作计算
  4. 高容错:当一台机器上有坏的,会重新将失败的任务重新分配。

hadoop的组成

  1. 1.x的时候MR(计算+资源调度) HDFS COMMON(辅助工具)
  2. 2.x的时候MR(计算),yarn(资源调度),HDFS(数据存储),Common(辅助工具)
  3. 3.x组成和2.x差不多

各项表示

HDFS中NameNode,就是目录,存储元数据,指出DataNode的数据存放位置。
SecondaryNameNode,就是NameNode死翘翘后,顶替其位置。
YARN 资源调度,ResourceManager (多个NodeManager(多个Containner(ApplicationMaster)))

在这里插入图片描述一个Container容器中最多1到8G,如果这个NodeManager分配了4G运行内存,则这个节点上最多有4个Container.

Mapreduce map先分开,reduce再计算聚合
在这里插入图片描述Hdfs,Mapreduce,yarn三者合作流程图

大数据的组件

Sqoop针对于取结构化数据
Flume文件数据非结构化数据

安装遇见的问题

  1. 分区 启动放在哪,内存不够,取硬盘内存暂替内存
  2. krump 作用就是崩溃前,资料存储在哪!方便后面回复吧
  3. ip地址 配三个地方,vm ,windows,虚拟机
  4. 配置虚拟机ip地址 vim /etc/sysconfig/network-scripts/ifcfg-ens33 BOOTPROTO=“DYPC”动态的ip地址,这里需要换成static,因为你每次开机IP地址不能不一样。
  5. 配置主机名称 vim /etc/hostname
  6. 配置映射 vim /etc/hosts
  7. 在这里插入图片描述
    给atguigu用户赋权限,vim /etc/sudoers ,上面位置修改。
    ll命令的详细内容:
    在这里插入图片描述

第一列:-表示文件;d表示文件夹;l表示软连接
第二列:当前用户权限、组用户权限、其他用户权限
第三列:被使用次数
第四列:当前用户、当前用户组
第五列: 文件大小,可以用K或M作为单位(ll -h)
第六列:创建时间
第七列:文件或目录名
sudo chown atguigu:aiguigu 文件1/ 文件2/ 改这俩文件的用户和用户组

hadoop的文件

bin 里边存放hdfs,yarn,mr
sbin里是启动文件
etc 里边是配置文件
share里边有分享的案例
两个常用命令
scp -r 迭代传送 rsync -av****同步传递,格式和scp一样
举例写个xsync的脚本
echo $PATH 把xsync放在路径下,这样不管在哪个目录下都可以用,

XSYNC


#!/bin/bash
#1. 判断参数个数
if[ $#  -lt  1]
then 
echo NotEnough Arguement
exit;
fi
#2. 遍历集群中所有机器
for host in node001,node002,node003
do
	echo =========$host===========
	#3. 遍历所有目录,挨个发送
	for  file in $@ 
	do
	  	#4.判断文件是否存在
	  if [ -e $file ] 
			then 
	  	#5.	 获取父目录
	  		pdir =$(cd -P $(dirname $file); pwd)
	  	#6. 获取当前文件的名称
	  		fname=$(basename $file)
	  		ssh $host "mkdir -p $pdir"
	  		rsync -av $pdir/$fname $host:$pdir
	  	else 
	  		echo $file does not exists!
	  	fi
	  	done
	  	done
	  	
	

硬链接 软链接

硬链接就是关系硬,删除不影响另一个
软链接和快捷方式差不多,但又有点不一样。

Hadoop配置

  1. core-site
<property>
    <name>fs.defaultFS</name><!--定义Hadoop HDFS中 namenode 的URI和端口-->
    <value>hdfs://node001:9000</value>
</property>
<property>
    <name>hadoop.tmp.dir</name><!--Hadoop数据的存储目录-->
    <value>file:/opt/SoftWare/Hadoop/hadoop-2.7.7/tmp</value>
</property> 
  1. hdfs-site

  2. mapreduce-site

  3. yarn-site
    在这里插入图片描述

hadoop中配置遇到的问题

我在yarn-site中配置ResourceManage到hadoop003中,但启动的时候RM启动不了,说链接不上,在这里插入图片描述我只能先把它改为node001

SSH免密登录

在这里插入图片描述

hdfs namenode format 初始化

初始化后多了,初始化那个机器上多了一个data,name,data存数据,name是目录和logs //这两个位置就是配置core.site中的,临时那个配置hadoop.tmp.dir

hadoop 2.x文件管理界面50070 ,3.x 9870
8088页面是mapreduce运行情况。

配置历史服务器

在这里插入图片描述
bin/marped --daemon start historyserver
出现jobHistoryServer进程

配置日志聚集

在这里插入图片描述方便查看MR运行的日志,和配置历史历史服务器一样,都是8088端口访问。

端口号

HDFS NameNode 内部通常端口:8020/9000/9820 注意:9000是2.X的内部端口,8020内部在2.X中并不能用。
HDFS NameNode 对用户查询到端口号: 9870(3.X)50070(2.X)
Yarn查看任务运行情况:8088
历史服务器:19888

配置文件slaves(2.x) ,workers(3.x)

该配置文件slaves文件里面记录的是集群里所有DataNode的主机名,到底它是怎么作用的呢?slaves文件只作用在NameNode上面。

时间同步

systemctl start ntpd
vim /etc/ntp.conf 修改在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述

log4j

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

HDFS的API操作

在这里插入图片描述注意,URI里的不是50070,说明是内部的端口号,不是8020说明是2.X而不是3.X.
这里只举一个例子,其他的都差不多,configuration里可以配置副本数等,也可以创建hdfs-site.xml里配置
recursive 递归

HDFS写数据流程

在这里插入图片描述注意packet,每次传输512b数据+4b校验位攒够64kpacket,然后一packet为单位发送。

block存放的机器位置

考虑距离还有负载均衡。这个距离还是看具体的情况,不好说啊,目前我也很迷茫不知道咋看

HDFS读数据流程

在这里插入图片描述注意,优先选择距离近的,但如果距离近的服务器比较繁忙,选择其他的,这时候如果从DataNode1中和DataNode2中分别读取不同的块,注意,他不是并行读的,而是串行读的。

NameNode 和2NN工作机制

在这里插入图片描述注意:fsimage和edits是在name中,而不是在data中

查看镜像文件fsimage 和edits

hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径 查看fsimage
hdfs oev -p 文件类型 -i 镜像文件 -o 转换后文件输出路径 /查看edits

DataNode工作机制

在这里插入图片描述
数据传输中采用crc校验block,除了数据还有校验码,比如在API操作中,copyToLocal()这里边就有个参数,是否有校验,如果添true的话,那么会多一个 呀 “ .crc”的文件

MapReduce

在这里插入图片描述hadoop中的数据类型,除了text=String ,其他的都是加上了writable 其实就是Hadoop的序列化
分为3个部分,Mapper,Reducer,Driver
Driver要干的事

在这里插入图片描述
在这里插入图片描述Mapper过程,输入参数key ,value,输出参数 key,value ,第一个输入参数之所以是longWritable是因为距离用Long,就是要一行一行滴读取嘛。这一定要记住啊,还有就是Text和String之间也要转化啊 text.set(String),Context是mapper,reduce信息交互的桥梁,也要记住啊
在这里插入图片描述Reduce的过程,这里我有一点疑问不太明白,为什么Mapper传过来的(text,1),(text,1)在这reducer直接变成了(text,(1,1)),是因为Iterable这个类似于迭代器的东西么?他的底层是怎样实现的呢?先记住这点吧
在这里插入图片描述 System.exit(status) ,status为0时表示运行正确,为1时表示运行错误。

打包引入的两个插件

<build>
    <plugins>
        <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.1</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>
            </configuration>
        </plugin>
    </plugins>
</build>

第一个插件打包,所打成的jar包小,不含其他依赖,如hadoop-client ,带上第二个的话含,如果其他集群上有其环境的话,就打成第一个包,没有的话,这两个依赖都加吧。
补充学习:args[0] args[1] 可以理解为外界传入的参数,如在mapreduce中那个wordcount中,FileOutputPath(driver,new Path(args[0])) ,可以这样写,这样的话,打包上传到linux中就可以 hadoop jar wc.jar 路径 路径

序列化

自定义序列化


```java
package com.zhenghaozhe.writable;

import org.apache.hadoop.io.Writable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class FlowBean implements Writable {
    private long upFlow;
    private long downFlow;
    private long sumFlow;

    public long getUpFlow() {
        return upFlow;
    }

    public void setUpFlow(long upFlow) {
        this.upFlow = upFlow;
    }

    public long getDownFlow() {
        return downFlow;
    }

    public void setDownFlow(long downFlow) {
        this.downFlow = downFlow;
    }

    public long getSumFlow() {
        return sumFlow;
    }

    public void setSumFlow() {
        this.sumFlow = this.downFlow + this.upFlow;
    }

    @Override
    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeLong(upFlow);
        dataOutput.writeLong(downFlow);
        dataOutput.writeLong(sumFlow);
    }

    @Override
    public String toString() {
        return "FlowBean{" +
                "upFlow=" + upFlow +
                ", downFlow=" + downFlow +
                ", sumFlow=" + sumFlow +
                '}';
    }

    @Override
    public void readFields(DataInput dataInput) throws IOException {
        this.upFlow=dataInput.readLong();
        this.downFlow=dataInput.readLong();
        this.sumFlow=dataInput.readLong();

    }

    public FlowBean() {
    }
}

自定义序列化,说白了就是继承一个writable 然后把自己封装的数据写入他的两个方法中write和readField中,然后让这些数据变为LongWriteable,然后还要有一个无参的构造函数

public class mapper extends Mapper<LongWritable,Text,LongWritable,FlowBean> {
    LongWritable outT=new LongWritable();
    FlowBean outF=new FlowBean();
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        String line=value.toString();
        String[] split=line.split("\t");
        String phone=split[1];
        String up=split[split.length - 3];
        String down =split[split.length - 2];
        outF.setDownFlow(Long.parseLong(down));
        outF.setUpFlow(Long.valueOf(up));
        outT.set(Long.parseLong(phone));
        outF.setSumFlow();
        context.write(outT,outF);
    }
}

Mapper中,注意格式的转换,Long.parseLong 。

package com.zhenghaozhe.writable;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class reduce extends Reducer<LongWritable,FlowBean,LongWritable,FlowBean> {
    private FlowBean f=new FlowBean();
    @Override
    protected void reduce(LongWritable key, Iterable<FlowBean> values, Context context) throws IOException, InterruptedException {
        long totalUp=0;
        long totaldown=0;
        for (FlowBean value : values) {
            totalUp += value.getUpFlow();
            totaldown += value.getDownFlow();
        }
        f.setUpFlow(totalUp);
        f.setDownFlow(totaldown);
        f.setSumFlow();
        context.write(key,f);
    }
}

reduce这个数据是牵扯算法。

package com.zhenghaozhe.writable;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
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 driver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //获取job
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        //设置class包
        job.setJarByClass(driver.class);
        //mapper和reduce
        job.setMapperClass(mapper.class);
        job.setReducerClass(reduce.class);
        //mapper输出
        job.setMapOutputKeyClass(LongWritable.class);
        job.setMapOutputValueClass(FlowBean.class);
        //最终的输出
        job.setOutputKeyClass(LongWritable.class);
        job.setOutputValueClass(FlowBean.class);
        //输入输出路径
        FileOutputFormat.setOutputPath(job,new Path("E://out.txt"));
        FileInputFormat.setInputPaths(job, new Path("E://wc.txt"));
        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);
    }


}

1	13213665198	120.2	16	92	300
5	13213665128	120.2	111	91	300
4	13213665138	120.2	1113	90	300
3	13213665118	120.2	1114	91	300
2	13213665148	120.2	1115	93	300

以上这是那个求4 5 行的和,以第二列电话号为key的代码

数据切片与MapTask并行度决定机制

在这里插入图片描述

切片的规则

在这里插入图片描述minSize 默认为1M maxSize为ValueSize,可变并没有给具体值,blocksize在本地模式32M,集群模式128M,只是逻辑切片。
这里就是想把切片调大,调minsize,想把切片调小,调maxsize,那么为啥大佬要这么反着写源码呢? 切片的多少与文件大小和切分规则有关(图片中那个代码公式)

获取切片信息API

    FileSplit fileSplit= (FileSplit) context.getInputSplit();
        fileSplit.getPath().getName();

TextinputFormat CombineTextInputFormat

textInputFormat是按任务对文件进行规划切分,CombineInputFormat是把许多小文件放到一个切片
平时默认的是TextinputFormat
如果想要改变成CombineInputFormat,在
driver中加入job.setInputFormatClass(CombineTextInputFormat.class)
CombineTextInput.setMaxInputSplitSize(job ,20971520)把切片设置为20M

Shuffle过程

在这里插入图片描述

自定义Partitionor 分区数量

为了把手机号137 138 139开头分给不同的文件下,采用自定义分区,注意设置reduce的个数
   //设置partition 在driver中
        job.setPartitionerClass(partition.class);
        job.setNumReduceTasks(3);
 

package com.zhenghaozhe.partiton;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;

public class partition extends Partitioner<LongWritable, FlowBean> {
    @Override
    public int getPartition(LongWritable longWritable, FlowBean flowBean, int i) {
        int p;
        String l=longWritable.toString();
        String x=l.substring(0,3);
        if("137".equals(x)){
            p=1;
        }
        else if ("165".equals(x)){
            p=0;
        }
        else  {
            p=2;
        }

        return p;
    }
}

为啥MR在hadoop中要排序?

首先在shuffle时,环形缓冲区进行一个快速排序,然后出来后一个归并排序
在reduce阶段进行一个归并排序,
mapTask和ReduceTask会根据key进行排序,字典顺序,在环形缓冲区中,他不是进去一个数据排序一次,而是大概到80%,到达一定阈值,然后排序。
对于Reduce ,从mapTask 上拷贝数据,如果数据大小超过一定阈值,则溢写在磁盘上,否则存储在内存中,如果磁盘上数目达到一定数值,则归并排序到一个更大的文件,如果内存中文件大小超过一定阈值,则进行一次合并后,将数据溢写到磁盘上,当所有数据拷贝完毕后,ReduceTask,对内存和磁盘上的所有数据进行一次归并排序
hadoop中的key一定要能排序,不能的话就报错

自定义比较

1继承 writableCompare
2 重写compareTo

Combiner

可有可无,(a,1)(a,1)合并为(a,2)目的是为了减少数据的传输。
在这里插入图片描述
Combiner是Reducer的子类,继承Reducer,然后重写reduce方法就可以喽

自定义OutputFormat

首先写一个类继承FileOutputFormat
重写里边的Recordwriter的方法, 再写一个类继承recordWriter,在recordWriter的writer中写入需要的信息。

MapTesk的工作机制

客户端首先根据参数配置,把文件逻辑上划分片,然后提交给yarn的RM ,yarn 开启MRappMaster,MRappmaster开启maptask,他会用inputformat(默认是textinputformat)(combinerinputformat)中的RecorderReader中的reader获取数据(K,V),返回给map,然后map之后给环形缓冲区,一半存索引,一半存数据,到达百分之80后溢出,溢写到磁盘上,溢写之前要进行快排,最后磁盘上的文件再进行归并排序。

ReduceTesk的工作机制

首先拉取上一步的数据,然后进行归并排序,然后reduce处理,然后输出到文件。

ETL数据清洗

在mapper中清洗

MR总结

  1. inputformat
  2. mapper setup()初始化,map()用户的逐条操作 clearup() 关闭资源
  3. 分区 默认HashPartitioner ,默认按按照key的hash值%numreducetask个数
  4. 排序 部分排序 全排序(一个reduce) 二次排序(实现一个writableCompare,重写compareTo方法)
  5. combiner 提前聚合,在map中聚合,解决reduce数据倾斜,继承reducer
  6. Reducer初始化 setup()初始化,map()用户的逐条操作 clearup() 关闭资源
  7. OutputFormat 默认textOutputFormat 按行输出 自定义

hadoop数据压缩

在这里插入图片描述在这里插入图片描述 在api操作中通过conf 和job配置

Yarn

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

yarn的基本命令

yarn application -list 查看的是8088页面下MR的运行情况
yarn application -kill 杀死该程序
yarn logs -applicationId id号 //查看程序日志
yarn logs -applicationId id -containerId rongqihao //查看某个容器的日志
yarn containner -list 查看container
yarn node -list -all
yarn rmadmin -refreshQueues 更新队列配置
yarn queue -status default

yarn生产环境核心配置

1ResourceManager相关
yarn.resourcemanager.sheduler.class
公平调度器还是容量调度器(默认)
yarn.resourcemanager.scheduler.client.thread-count
设置线程数,默认为50
2NodeManager相关
yarn.nodemanager.resource.detect-hardware-capblities 是否让yarn自己检测硬件进行配置,默认false
yarn.nodemanager.resource.count-logical-processors-as-core 是否将虚拟核数作为cpu核数
yarn.nodemanager.resource-pcores-vcores-multiplier 虚拟核数和物理核数乘数,例如:4核8线程该参数就是2
yarn.nodemanger,resource.memory-mb NM使用内存默认8G,如果她只有4G的话会崩溃。
yarn.nodemanager.resouce.system-reserved-memory-mb 为系统保留多少内存 以上两个参数配置一个即可
yarn-nodemanager.resource.cpu-vcores NodeManager使用CPU核数,默认8个
yarn.nodemanager.pmem-check-enabled 开启物理内存检查限制container
yarn.nodemanager.vmem-check-enabled
是否开启虚拟内存检查限制
yarn.nodemanager.vmem-pmem-ratio虚拟物理内存默认2:1
3 Container相关
yarn.shedule.minimum-allcation-mb 容器最小内存
yarn.scheduler.maximum-allcation-mb 容器最大内存
yarn.sheduler.minimum-allcation-vcores 最小cpu数
yarn.scheduler.maximum-allcation-vcores 容器最大cpu核数

设置队列

hadoop-2.7.4/etc/hadoop/capacity-scheduler.xml
在这里边设置队列,并可以设置其占的内存比

查看端口号所占的内存

jmap -heap 端口号

namenode和datanode内存所占比

在hadoop-env.sh中配置
namenode最小值1G,每增加1百万个block,增加1G内存 datanode 最小值为4G,一个datanode上的副本数低于4百万则小于4G,每增加1百万,加1G

namenode心跳并发机制

每个datanode都得给namenode传输说他的情况,然后namenode就得分线程管他们,分多少个线程最合适呢? 一般3台机器的话,21个线程,在hdfs-site中配置。

开启回收站

fs.trash.interval 在core-site中配置

fs.trash.interval
1

value中的值,说明每过一分钟,清空一下

集群压测

在这里插入图片描述

配置两个namenode

在这里插入图片描述
没啥用,两个namenode一模一样

配置多目录datanode

在这里插入图片描述
这里边的内容和namenode不一样,存放的数据不同。在三点差中,可均衡两个磁盘的数据 hdfs diskbalancer -plan hadoop103

HDFS集群扩容和缩容

在这里插入图片描述## 开启数据均衡命令
sbin/start-balancer.sh threshould 10 每个服务器之间不能超过10

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值