一、hadoop简介
1、概述
Hadoop是Apache提供的一个开源的、可靠的、可扩展的系统架构,可以利用分布式架构来进行海量数据的存储以及计算。需要注意的是Hadoop处理的是离线数据,即在数据已知以及不要求实时性的场景下使用。
2、版本
3、模块
(1)Common:在Hadoop1.0中,包含HDFS、MapReduce和其他项目公共内容,从Hadoop2.0开始,HDFS和MapReduce被分离为独立的子项目,其余内容为Hadoop Common (2)HDFS:用于分布式环境下数据的存储 (3)Yarn:Hadoop2.0版本中出现,用于进行资源管理和任务调度的框架. (4)MapReduce:从Hadoop2.0开始,基于Yarn,用于在海量数据的场景下进行并行计算 (5)Ozone:基于HDFS进行对象的存储 (6)Submarine:基于Hadoop进行机器学习的引擎
4、相关组件
(1)HBase: 类似Google BigTable的分布式NoSQL列数据库。(HBase和Avro已经于2010年5月成为顶级 Apache 项目) (2)Hive:数据仓库工具,由Facebook贡献 (3)Zookeeper:分布式锁设施,提供类似Google Chubby的功能,由Facebook贡献 (4)Avro:新的数据序列化格式与传输工具,将逐步取代Hadoop原有的IPC机制。 (5)Pig: 大数据分析平台,为用户提供多种接口 (6)Ambari:Hadoop管理工具,可以快捷的监控、部署、管理集群 (7)Sqoop:于在Hadoop与传统的数据库间进行数据的传
二、hadoop安装
1、上传文件
2、解压文件夹
ll
3、关闭防火墙
4、配置主机名
5、配置主机名和ip的映射
6、配置免密登录
见前一篇文章
7、安装并配置jdk(hadoop是java写的,其运行也需要java的支持)
8、配置hadoop
(1)配置hadoop-env.sh
a. 编辑hadoop-env.sh:vim hadoop-env.sha.
b. 修改JAVA_HOME的路径,修改成具体的路径。例如:export JAVA_HOME=/home/software/jdk1.8b.
c. 修改HADOOP_CONF_DIR的路径,修改为具体的路径,例如:export HADOOP_CONF_DIR=/home/software/hadoop-2.7.1/etc/hadoopc.
d. 保存退出文件
e. 重新加载生效:source hadoop-env.s
(2)配置 core-site.xml
a. 编辑core-site.xml:vim core-site.xmla.
b. 添加如下内容
<property>
<!-- 指定HDFS中的主节点 - namenode -->
<name>fs.defaultFS</name>
<value>hdfs://hadoop01:9000</value>
</property>
<property>
<!-- 执行Hadoop运行时的数据存放目录 -->
<name>hadoop.tmp.dir</name>
<value>/home/software/hadoop-2.7.1/tmp</value>
</property>
(3)配置 hdfs-site.xm
a. 编辑hdfs-site.xml:vim hdfs-site.xmla.
b. 添加如下配置:
<property>
<!-- 设置HDFS中的复本数量 -->
<!-- 在伪分布式下,值设置为1 -->
<name>dfs.replication</name>
<value>1</value>
</property>
c. 保存退出
(4)配置 mapred-site.xml
a. 将mapred-site.xml.template复制为mapred-site.xml:cp mapred-site.xml.template mapred-site.xmla.
b. 编辑mapred-site.xml:vim mapred-site.xmlb.
c. 添加如下配置:
<property>
<!-- 指定将MapReduce在Yarn上运行 -->
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
d. 保存退出
(5)配置 yarn-site.xml
a. 编辑yarn-site.xml:vim yarn-site.xmla.
b. 添加如下内容:
<!-- 指定Yarn的主节点 - resourcemanager -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop01</value>
</property>
<!-- NodeManager的数据获取方式 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
c. 保存退出
(6)配置slaves
a. 编辑slaves:vim slavesa.
b. 添加从节点信息,例如:hadoop01b.
c. 保存退出
(7)配置hadoop的环境变
a. 编辑profile文件:vim /etc/profilea.
b. 添加Hadoop的环境变量,例如:
export HADOOP_HOME=/home/software/hadoop-2.7.1
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
或
export JAVA_HOME=/home/software/jdk1.8.0_131
export HADOOP_HOME=/home/software/hadoop-2.7.1
export PATH=$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
c. 保存退出
d. 重新生效:source /etc/profiled
(8)格式化namenode:hadoop namenode -format (9)启动hadoop:start-all.sh
9、出错处理方式:
1、停掉集群 stop-all.sh 2、删除hadoop安装包下的tmp目录 3、检查配置文件 4、重新格式化 5、重新启动
10、常见错误及处理方法
(1)问题:The authenticity of host ‘0.0.0.0 (0.0.0.0)’ can’t be established.RSA key fingerprint is 62:46:08:c6:0d:fd:93:25:d0:78:d8:d5:08:ff:cb:da. 解决方法:修改/etc/ssh/ssh_config文件(或$HOME/.ssh/config)中的配置,将#StrictHostKeyChecking ask中的ask改为no并去掉# 改好配置后,重新启动sshd服务即可(service sshd restart)。 (2)问题:localhost: Host key verification failed. 解决方法:去掉slaves文件中的localhost (3)Java版本问题:安装1.8后,使用java-version查看版本时仍为1.7 解决方法:更改Java默认版本:
update-alternatives --install /usr/bin/java java /usr/java/jdk1.8.0_131/bin/java 300
update-alternatives --install /usr/bin/javac javac /usr/java/jdk1.8.0_131/bin/javac 300
update-alternatives --config java
三、HDFS细节
1、Block
(1)数据块是hdfs数据存储的最基本的单位 (2)当hdfs存储超大文件时,hdfs会以一个标准将大文件切分为多块进行分布式存储 (3)block在hadoop1.0的时候是64M,但是在hadoop2以上的版本都是128M (4)切块的优点: a. 能够存储超大文件 b. 有利于数据的复制 (5)在hdfs中,如果一个文件小于数据块的大小。并不会占用整个数据块的空间,实际是多少就占用多少
[root@hadoop01 home]# hadoop fs -put bok /book
21/08/19 10:06:31 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
[root@hadoop01 home]# cd software/
[root@hadoop01 software]# hadoop fs -put hadoop-2.7.1_64bit.tar.gz /hadoop
21/08/19 10:09:20 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
2、NameNode
(1)NameNode是用来存储元数据的,并且用来管理datanode (2)namenode维护的hdfs的元数据信息
a. 文件的存储路径
b. 文件的大小
c. block块的大小
d. 文件和blockid的映射关系
e. 文件的权限
f. 上传的用户
g. Block的数量关系
h. 复本的数量
i. block和datanode对应的关系
(3)每一条元数据的大小是150B左右 (4)namenode不适合存储大量的小文件 (5)元数据信息存储在内存及磁盘中。存到内存中是为了快速查询,存在磁盘是为了元数据的可靠 (6)元数据持久化到namenode节点的硬盘上,目录由core-site.xml->dfs.tmp.dir属性决定 (7)元数据保存到了/home/software/hadoop-2.7.1/tmp/dfs/name/current
[root@hadoop01 current]# cd /home/software/hadoop-2.7.1/tmp/dfs/name/current
(8)和元数据相关的文件:
a. Fsimage:元数据的镜像文件,存储namenode元数据信息,并不是实时同步内存中元数据信息的,而是落后于内存中的元数据信息
b. edits:记录操作日志。记录namenode所要执行的操作
达到条件之后,fsimage才会去同步内存中的元数据:i 时间达到1小时、 ii edits文件达到64M、 iii 手动通过命令同步 vi 重启集群的时候会同步
(9)当写请求的时候,namenode会首先将操作记录到edits文件汇总,写成功后,会去修改内存,更新元数据,内存修改完成后,会像客户端返回一个ack信号。代表更新成功,此时,fsimage文件中的数据没有发生更改。所以说,fsimage中的数据不是实时的数据。需要达到条件再进行更新 (10)namenode是通过心跳机制来管理datanode的 (11)datanode会每隔3s向namenode汇报自身情况 a. 自己节点的状态(正常、退役、服役) b. 自己存储的数据块 c. 自身剩余的空间容量 (12)如果超过10min没有向namenode发送心跳,那么namenode会认为此datanode lost了,然后namenode就会将此节点的数据转移到其他的服务器(找相对空闲的节点进行转移)
3、SecondaryNameNode
(1)SecondaryNameNode不是namenode的热备份,而是协助namenode完成元数据的合并 (2)SecondaryNameNode是hadoop1.0的机制,在hadoop2.0的伪分布式可以看见,但是如果是hadoop2.0的完全分布式就不会看见 (3)当达到条件之后,SNN会将NN中的fsimage和edits文件通过网络的方式拷贝到SNN (4)同时namenode中会创建一个edits_inprogress来保存新的请求。 (5)在SNN,会将拷贝过来的fsimage中的元数据加载进内存,将edits文件中记录的最新的操作请求,在内存中进行更新,将更新后的元数据写入到新的文件fsimage.ckpt中 (6)写好的新的文件fsimage.ckpt再拷贝会namenode (7)循环以上处理方式
4、DataNode
(1)在hdfs中,数据是存放在datanode上面的,是以block块形式存放的 (2) 存放block块的位置:/home/software/hadoop-2.7.1/tmp/dfs/data/current/BP-976893665-192.168.232.129-1629336175258/current/finalized/subdir0/subdir0/ (3)在hdfs启动的时候, 每一个datanode会将当前存储的数据块的信息告诉namende节点 (4)之后, datanode节点会不断的向namenode发送心跳报告,默认是3s- 发送 (5)发送的心跳信息包括 节点的状态以及数据块的信息 (6)如果namenode 10min没有收到datanode的心跳,就会认为已经丢失,那么namenode会将这个datanode上的block复制到其他的datanode上 (7)如果是伪分布式,复本的数量只能设置为1,因为如果数量大于1,会导致hdfs一直处于安全模式不能退出 (8)安全模式:如果datanode在进行汇报的时候,namenode统计出来某一个文件本来有三个数据块,但是根据datanode汇报的信息,只有两个块存在,有块丢失了, 这个时候namenode就会进行复本的复制以达到三个块,在复制的过程中,会进入安全模式,在安全模式中,hadoo集群只能对外提供读服务,不能提供写服务。
4、复本的放置策略
(1)在hdfs中,支持多复本策略,如果不指定,默认是3.这个数量可以通过属性来进行指定。dfs.replication (2)第一个复本: a. 集群内部上传,谁上传就放在谁身上 b. 集群外部上传,谁空闲就放在谁身上 (3)第二个复本: a,在hadoop2.7之前:第二个复本放在和第一个复本不同的机架的节点上 b.在hadoop2.7之后:第二个复本放在和第一个复本相同的机架的不同节点上 (4)第三个复本: a.在hadoop2.7之前:第三个复本放在和第二个复本相同的机架的不同节点上 b.在hadoop2.7之后:第三个复本放在和第二个复本不同的机架的节点上
5、基本命令
命令 | 说明 |
---|
hadoop fs -put bok /book | 上传文件到hdfs | hadoop fs -mkdir /student | 在hdfs上创建目录 | hadoop fs -get /aaa /opt | 将hdfs上aaa文件下载到本地opt目录下 | hadoop fs -cat /book | 查看hdfs上文件的内容 | hadoop fs -rmdir /student | 删除hdfs上的空目录 | hadoop fs -rnr /student | 删除hdfs上不为空的目录 | hadoop fs -rm /aaa | 删除hdfs上的普通文件 | hadoop fs -ls / | 列出/路径下的文件 | hadoop fs -lsr / | 递归列出/路径下的所有的文件 | hadoop fs -mv /bok/hehe | 更改hdfs上文件的名字 | hadoop fs -cp /hehe/demo | 拷贝hdfs上的文件 | hadoop fs -touchz /nihao | 在hdfs上创建一个空白的文件 |
6、读取流程
(1)客户端需要向namenode发送RPC请求 (2)namenode会根据情况(文件过大,切块过多,一次返回数据量太大)返回全部或部分的block的列表,并且返回对应block以及该block对应的复本存储在datanode上的位置 (3)client会选举离客户端最近的datanode去读取block。如果客户端本身就是datanode,那么会直接从本地读取 (4)读取完一个block会进行checksum的校验,即验证读取到的block大小和声明的block大小是否一致。如果读取datanode数据出现错误,客户端会通知namenode,然后再从下一个离得近的datanode上读取相应的复本 (5)读取完当前的block数据后,关闭当前datanode的链接,并为读取下一个block寻找最佳的datanode (6)当读取完列表中的block后,会通知namenode返回下一批block的列表,接着读取 (7)当文件最后一个block读取完成后,客户端会链接namenode告诉其关闭文件。
7、写入流程
(1)客户端向namenode发送rpc请求 (2)namenode会检查要创建的文件是否已经存在,并检查客户端是否有权限(原生的hadoop对于权限这块没有涉及) (3)namenode就会返回客户端要写入数据的datanode的地址 (4)客户端就开始向第一个离得较近的datanode开始写入数据,写的时候是以packets(对数据进行封包)进行写入。并且底层会以队列的形式管理packets。底层是以管道pipeline的形式将数据包发送给所有的datanode (5)最后一个datanode写入数据成功后,会返回一个ack给第二个datanode,同样,第二个datamode写入成功后,会返回第一个datanode一个ack信号,同样第一个写完后,会返回给客户端一个ack信号。三个datanode都写完之后,从队列中删除已发送的packets (6)如果传输过程中,有个datanode出现了故障,那么当前的pipeline会关闭,出现故障的datanode会从当前pipeline中移除,剩余的block会继续在剩余的datenode中继续以pipeline的形式传输,同时namenode会分配一个新的datanode,保持复本的数量
8、删除流程
(1)客户端向namenode发起RPC请求 (2)现在namenode上将此文件的元数据删除,但是此时数据并没有真正的删除 (3)datanode会定时向namenode汇报自身的情况,在汇报的时候,namenode会告诉datanode说此文件的元数据已经被删除了 (4)通知datanode删除自身的block块数据
四、在eclipse中集成hadoop插件
1、将上面的jar包放入下面两个包(eclipse的安装目录下)中
2、将hadoo-2.7.1_64bit.tar解压到D盘
3、将hadoopbin_for_hadoop2.7.1中的内容放到解压到的hadoop-2.7.1/bin下面
4、新建如下两个系统变量
编辑环境变量path
5、打开eclipse,点击windows->perferences->Hadoop Map/Reduce->选择安装目录
6、点击windows->show view -> other->MapReduce Tools ->Map/Reduce Locations
点击如下图标 配置如下内容
7、点击windows->show view->Project Explorer出现如下内容
五、回收站机制
1、开启回收站机制
(1)首先停掉集群
[root@hadoop01 opt]# stop-all.sh
(2)编辑core-site.xml文件
[root@hadoop01 opt]# cd /home/software/hadoop-2.7.1/etc/hadoop/
[root@hadoop01 hadoop]# vim core-site.xml
(3)添加如下内容
<!-- 开启回收站-->
<property>
<name>fs.trash.interval</name>
<value>10</value>
</property>
2、开启回收站机制后
(1)再次执行删除命令,运行结果如下
[root@hadoop01 hadoop]# hadoop fs -rm /nihao
21/08/19 15:10:43 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
21/08/19 15:10:44 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 10 minutes, Emptier interval = 0 minutes.
Moved: 'hdfs://hadoop01:9000/nihao' to trash at: hdfs://hadoop01:9000/user/root/.Trash/Current
(2)恢复文件,执行:
hadoop fs -mv /user/root/.Trash/Current/nihao
(3)如果不移动,10min后自动删除
六、eclipse写API
1、新建java Project并添加jar
new->Folder 将下面的两个图片中的四个区域中的jar复制到上步建立的hdfs_jar中,会有重复,直接覆盖 选中hdfs_jar中的所有jar包,右击选择build Path
2、开始编写hdfsTest
(1)读取文件
@Test
public void readFile() throws IOException, URISyntaxException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://192.168.232.129:9000"), conf);
FSDataInputStream in = fs.open(new Path("/demo/hehe"));
FileOutputStream out = new FileOutputStream("D://aaa.txt");
IOUtils.copyBytes(in, out, conf);
}
(2)上传文件
@Test
public void putFile() throws IOException, URISyntaxException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://192.168.232.129:9000"), conf);
FSDataOutputStream out = fs.create(new Path("/park1"));
ByteArrayInputStream in=new ByteArrayInputStream("hello hdfs".getBytes());
IOUtils.copyBytes(in, out, conf);
}
(3)删除文件
@Test
public void deleteFile() throws IOException, URISyntaxException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://192.168.232.129:9000"),conf);
fs.delete(new Path("/park"));
}
(4)创建文件夹
@Test
public void testMkdir() throws IOException, URISyntaxException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://192.168.232.129:9000"),conf);
fs.mkdirs(new Path("/video"));
}
(5)查看指定目录下的文件
@Test
public void testLs() throws IOException, URISyntaxException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://192.168.232.129:9000"),conf);
FileStatus[] listStatus = fs.listStatus(new Path("/hadoop"));
for (FileStatus fileStatus:listStatus) {
System.out.println(fileStatus);
}
}
(6)获取文件块信息
@Test
public void getBlock() throws IOException, URISyntaxException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://192.168.232.129:9000"),conf);
BlockLocation[] data = fs.getFileBlockLocations(new Path("/hadoopaaa"), 0, Integer.MAX_VALUE);
for (BlockLocation blockLocation : data) {
System.out.println(blockLocation);
}
}
(7)import包
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.Test;```
|