Hadoop历史
- 创始人 Doug Cutting,为了实现与Google类似的全文搜索功能,在Lucene框架基础上进行优化升级。
- 2001年,lucene成为apache的一个子项目
- lucene与Google一样,存储不了大数据,检索速度慢
- lucene学习Google:微型版Nutch
- Google 三篇论文 HDFS,MR,Hbase
- 2003-2004,创始人实现了DFS和mapreduce,使得Nutch性能飙升
- 2005年,hadoop作为lucene的子项目Nutch的一部分加入apache
- 2006年,MR和Nutch NDFS分别纳入Hadoop中,Hadoop诞生
- logo大象来自于其儿子的玩具
- apache,Hortonworks,cloudera爱恨情仇: apache开源,但是没有页面化,其他俩公司呢,看到了商机,于是创造了页面化,Hortoworks吸纳了雅虎工程师25到30名,这些工程师贡献了Hadoop80%的源码,与cloudera有一战之力,但2018年后来被cloudera收购。
Hadoop滴四大优势
- 高可靠性:一台机器坏,其他机器顶上不影响工作
- 高扩展性:双十一,动态增加服务器数量
- 高效性:Hadoop并行工作计算
- 高容错:当一台机器上有坏的,会重新将失败的任务重新分配。
hadoop的组成
- 1.x的时候MR(计算+资源调度) HDFS COMMON(辅助工具)
- 2.x的时候MR(计算),yarn(资源调度),HDFS(数据存储),Common(辅助工具)
- 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文件数据非结构化数据
安装遇见的问题
- 分区 启动放在哪,内存不够,取硬盘内存暂替内存
- krump 作用就是崩溃前,资料存储在哪!方便后面回复吧
- ip地址 配三个地方,vm ,windows,虚拟机
- 配置虚拟机ip地址 vim /etc/sysconfig/network-scripts/ifcfg-ens33 BOOTPROTO=“DYPC”动态的ip地址,这里需要换成static,因为你每次开机IP地址不能不一样。
- 配置主机名称 vim /etc/hostname
- 配置映射 vim /etc/hosts
给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配置
- 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>
-
hdfs-site
-
mapreduce-site
-
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总结
- inputformat
- mapper setup()初始化,map()用户的逐条操作 clearup() 关闭资源
- 分区 默认HashPartitioner ,默认按按照key的hash值%numreducetask个数
- 排序 部分排序 全排序(一个reduce) 二次排序(实现一个writableCompare,重写compareTo方法)
- combiner 提前聚合,在map中聚合,解决reduce数据倾斜,继承reducer
- Reducer初始化 setup()初始化,map()用户的逐条操作 clearup() 关闭资源
- 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