目录
数据量很大,他可以存储并且还可以计算并且还可以提供资源。
将一个数据集存储到多个硬盘里,然后并行读取。比如1T的数据,我们平均100份存储到100个1TB硬盘上,同时读取,那么读取完整个数据集的时间用不上两分钟。至于硬盘剩下的99%的容量,我们可以用来存储其他的数据集,这样就不会产生浪费。解决读取效率问题的同时,我们也解决了大数据的存储问题。
但是,我们同时对多个硬盘进行读/写操作时,又有了新的问题需要解决:
1、硬件故障问题。一旦使用多个硬件,相对来说,个别硬件产生故障的几率就高,为了避免数据丢失,最常见的做法就是复制(replication):文件系统保存数据的多个复本,一旦发生故障,就可以使用另外的复本。
2、读取数据的正确性问题。大数据时代的一个分析任务,就需要结合大部分数据来共同完成分析,因此从一个硬盘上读取的数据要与从其他99个硬盘上读取的数据结合起来使用。那么,在读取过程中,如何保证数据的正确性,就是一个很大的挑战,在Hadoop中采用MapReduce来提供这个问题的解决方法。
针对于上述两个问题,Hadoop为我们提供了一个可靠的且可扩展的存储和分析平台。
一个开源的分布式存储和分析计算平台,使用Java语言开发,具有很好的跨平台性,可以运行在商用(廉价)硬件上,用户无需了解分布式底层细节,就可以开发分布式程序,充分使用集群的高速计算和存储。
hadoop2.0以后的四个模块:
- Hadoop Common:Hadoop模块的通用组件
- Hadoop Distributed File System(HDFS):分布式文件系统
- Hadoop YARN:作业调度和资源管理框架
- Hadoop MapReduce:基于YARN的大型数据集并行计算处理框架hadoop3.0新扩展的两个模块:
- Hadoop Ozone:Hadoop的对象存储机制
- Hadoop Submarine:Hadoop的机器学习引擎
HDFS集群采用的是master/slaves这种主从的结构模型来管理数据,这种结构模型主要由四个部分组成,分别是
①Client(客户端)
②Namenode(名称节点):中心服务器,负责管理文件系统的命名空间 (Namespace ),它在内存中维护着命名空间的最新状态,同时并持久性文件(fsimage和edit)进行备份。
③Datanode(数据节点):一个节点运行一个Datanode进程,真正负责管理客户端的读写请求,在Namenode的统一调度下进行数据块的创建、删除和复制等操作。数据块实际上都是保存在Datanode本地的Linux文件系统中的。每个Datanode会定期的向Namenode发送数据,报告自己的状态(我们称之为心跳机制)。没有按时发送心跳信息的Datanode会被Namenode标记为“宕机”,不会再给他分配任何I/O请求。
④SecondaryNameNode:编辑日志和映像文件需要合并,而在同一namenode来执行合并操作会耗费大量内存和计算能力,所以一般合并操作会在另一台机器上(SecondaryNamenode),即辅助节点,使用辅助节点来创建检查点。
真正的一个HDFS集群包括一个Namenode和若干数目的Datanode。
用户在使用Client进行I/O操作时,仍然可以像使用普通文件系统那样,使用文件名去存储和访问文件,只不过,在HDFS内部,一个文件会被切分成若干个数据块,然后被分布存储在若干个Datanode上。
用户在Client上需要访问一个文件时,HDFS的实际工作流程如此:客户端先把文件名发送给Namenode,Namenode根据文件名找到对应的数据块信息及其每个数据块所在的Datanode位置,然后把这些信息发送给客户端。之后,客户端就直接与这些Datanode进行通信,来获取数据(这个过程,Namenode并不参与数据块的传输)。这种设计方式,实现了并发访问,大大提高了数据的访问速度。
1)上传jdk压缩包到指定的路径并解压安装
通过MobaXterm_CHS将jdk压缩安装文件上传至之前建立的/root/softwares 下,通过命令
tar -zxvf /root/softwares/jdk1.8.0_152.tar.gz -C /usr/local
将压缩包接压到usr/local
2)配置环境变量
[root@usr1 local]# vim /etc/profile ...上述内容省略,在末尾添加即可... # Java Environment export JAVA_HOME=/usr/local/jdk1.8.0_321 export PATH=$PATH:$JAVA_HOME/bin3)重新引导,使得环境变量生效
[root@usr1 local]# source /etc/profile
4)验证JDK是否配置完成
[root@usr1 local]# java -version
1)上传hadoop压缩包到指定的路径并解压安装
通过MobaXterm_CHS将hadoop压缩安装文件上传至之前建立的/root/softwares 下通过命令
tar -zxvf /root/softwares/hadoop-3.3.1.tar.gz -C /usr/local
将压缩包接到usr/local
2)配置环境变量
[root@usr1 local]# vim /etc/profile ...上述内容省略,在末尾添加即可... # Hadoop Environment export HADOOP_HOME=/usr/local/hadoop-3.3.1 export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:3)重新引导,使得环境变量生效
[root@usr1 local]# source /etc/profile
4)验证是否配置完成
[root@usr1 local]# hadoop -version
①新建一个目录,存放文本文件
# 将若干个存储单词的文件放入这个目录下
[root@user1 ~]# mkdir /home/qd
[root@user1 ~]# cp /usr/local/hadoop-3.3.1/etc/hadoop/*.xml /home/qd/
②执行wordcount
[root@user1 ~]# hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.1.jar wordcount /home/qd /home/qd/output
hadoop : 提交mapreduce的命令
jar : 使用jar的文件
$HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.1.jar : hadoop自带的测试jar包
wordcount : 运行上述jar文件中的wordcount类
/home/qd : 输入数据路径,注意,单机版都是本地文件系统路径
/home/qd/output : 输出数据路径(输出路径是之前不存在的,执行后自动创建)
③查看结果
[root@user1 ~]# cat /home/qd/output/*
在真实的企业环境中,服务器集群会使用到多台机器,共同配合,来构建一个完整的分布式文件系统。而在这样的分布式文件系统中,HDFS相关的守护进程也会分布在不同的机器上,例如:
平台&软件 | 说明 |
宿主机操作系统 | Windows |
虚拟机操作系统 | CentOS 7 |
虚拟机软件 | Windows: VMWare |
虚拟机 | 主机名: user1, IP地址: 192.167.10.101 |
SSH工具 | Windows: MobaXterm |
软件包上传路径 | /root/softwares |
软件安装路径 | /usr/local |
JDK | X64: jdk-8u152-linux-x64.tar.gz |
Hadoop | X64: hadoop-3.3.1.tar.gz |
用户 | root |
NameNode | DataNode | SecondaryNameNode | |
qianfeng01 | √ | √ | |
qianfeng02 | √ | √ | |
qianfeng03 | √ |
1. 三台机器的防火墙必须是关闭的.
2. 确保三台机器的网络配置畅通(NAT模式,静态IP,主机名的配置)
3. 确保/etc/hosts文件配置了ip和hostname的映射关系
4. 确保配置了三台机器的免密登陆认证(克隆会更加方便)
5. 确保所有机器时间同步
6. jdk和hadoop的环境变量配置
①防火墙关闭
[root@user1 ~]# systemctl stop firewalld
[root@user1 ~]# systemctl disable firewalld
[root@user1 ~]# systemctl stop NetworkManager
[root@user1 ~]# systemctl disable NetworkManager#最好也把selinux关闭掉,这是linux系统的一个安全机制,进入文件中将SELINUX设置为disabled
[root@user1 ~]# vim /etc/selinux/config
.........
SELINUX=disabled
.........[root@user2 ~]# vim /etc/selinux/config
.........
SELINUX=disabled
.........[root@user3 ~]# vim /etc/selinux/config
.........
SELINUX=disabled
.........
②主机映射
#分别在user1、user2和user3服务器上执行如下命令
[root@user1 ~]# vi /etc/hosts
#添加本机的静态IP和本机的主机名之间的映射关系
192.167.10.101 qianfeng01
192.167.10.102 qianfeng02
192.167.10.103 qianfeng03
③ 免密登录
# 1. 使用rsa加密技术,生成公钥和私钥。一路回车即可
[root@user1 ~]# ssh-keygen -t rsa# 2. 使用ssh-copy-id命令
[root@user1 .ssh]# ssh-copy-id root@user1
[root@user1 .ssh]# ssh-copy-id root@user2
[root@user1 .ssh]# ssh-copy-id root@user3# 3. 进行验证,不用输入密码直接切换即为成功
[hadoop@user1 .ssh]# ssh user2
[hadoop@user2 .ssh]# exit
[hadoop@user1 .ssh]# ssh user3[hadoop@user3 .ssh]#exit
# 4. 继续在qianfeng02和qianfeng03生成公钥和私钥,使用ssh-copy-id命令给三台节点拷贝。
④时间同步
参考Linux部分,可以让三台节点都同步网络时间,或者选择其中一台作为时间同步服务器。
⑤安装JDK和hadoop并配置环境变量
参考2.1本地模式搭建中的jdk和hadoop安装配置,在user1机器上完成后可通过scp命令进行分发,后面我们还要对hadoop的配置文件进行配置,故我们这里在后面配置完后再进行分发
前面2.1.3 Hadoop的目录说明中提到了,etc文件中存放着hadoop的配置文件,我们修改的一下文件都是在/usr/local/hadoop-3.3.1/etc/hadoop/路径下,以修改core-site.xml为例,即通过命令
vi /usr/local/hadoop-3.3.1/etc/hadoop/core-site.xml 进行修改。
①core-site.xml
<configuration>
<!-- 设置namenode节点,节点内部通信接口为9820-->
<!-- 注意: hadoop1.x时代默认端口9000 hadoop2.x时代默认端口8020 hadoop3.x时代默认端口 9820 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://user1:9820</value>
</property>
<!-- hdfs的基础路径,被其他属性所依赖的一个基础路径 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/local/hadoop-3.3.1/tmp</value>
</property>
</configuration>
②hdfs-site.xml
<configuration>
<!-- 块的副本数量 -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<!-- secondarynamenode守护进程的http地址:主机名和端口号。参考守护进程布局 -->
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>user2:9868</value>
</property>
<!-- namenode守护进程的http地址:主机名和端口号。参考守护进程布局 -->
<property>
<name>dfs.namenode.http-address</name>
<value>user1:9870</value>
</property>
</configuration>
③hadoop-env.sh
export JAVA_HOME=/usr/local/jdk1.8.0_152
# Hadoop3中,需要添加如下配置,设置启动集群角色的用户是谁
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
④workers
user1
user2
user3
⑤分发
# 我们已经完成了一个节点的环境配置,其他的节点也需要保持完全相同的配置。我们只需要将qianfeng01节点的配置拷贝到其他的节点即可。
# 分发之前,先检查自己的节点数据文件是否存在
# 如果之间格式化过集群,那么会在core-site.xml中配置的hadoop.tmp.dir路径下生成文件,先将其删除
#在user1上删除学习文档
[root@user1 ~]# rm -rf /usr/local/hadoop-3.3.1/share/doc/#分发hadoop
[root@user1 hadoop-3.3.1]# scp -r /usr/local/hadoop-3.3.1 user2:/usr/local/
[root@user1 hadoop-3.3.1]# scp -r /usr/local/hadoop-3.3.1 user3:/usr/local/#分发hadoop的环境变量配置文件
[root@user1 hadoop-3.3.1]# scp -r /etc/profile user2:/etc/
[root@user1 hadoop-3.3.1]# scp -r /etc/profile user3:/etc/#分别在user2和user3上进行刷新环境变量
[root@user2 local]# source /etc/profile
[root@user2 local]# which hadoop
/usr/local/hadoop-3.3.1/bin/hadoop[root@user3 local]# source /etc/profile
[root@user3 local]# which hadoop
/usr/local/hadoop-3.3.1/bin/hadoop
集群搭建好,环境也都配置好后,第一次启动前,我们需要在namenode所启动的服务器上执行元数据数据格式化,以后再启动无需再执行。
hdfs namenode -format
#hdfs的模块化启动
start-dfs.sh # 启动HDFS所有进程(NameNode、SecondaryNameNode、DataNode)
stop-dfs.sh # 停止HDFS所有进程(NameNode、SecondaryNameNode、DataNode)#hdfs的单个服务启动(你想单个启动服务采用)
hadoop-daemon.sh start namenode # 只开启NameNode
hadoop-daemon.sh start secondarynamenode # 只开启SecondaryNameNode
hadoop-daemon.sh start datanode # 只开启DataNodehadoop-daemon.sh stop namenode # 只关闭NameNode
hadoop-daemon.sh stop secondarynamenode # 只关闭SecondaryNameNode
hadoop-daemon.sh stop datanode # 只关闭DataNode
通过jps命令查看集群的进程分布
#user1节点
[root@user1 hadoop]# jps
13442 NameNode
13618 DataNode
13868 Jps# user2节点
[root@user2 ~]# jps
10514 SecondaryNameNode
10548 Jps
10405 DataNode# user3节点
[root@user3 ~]# jps
10931 DataNode
11001 Jps
每次在查看集群的进程分布的时候,都需要在不同的节点之间进行切换,非常的麻烦。所以,我们可以设计一个小脚本。
[root@user1 hadoop-3.3.1]# vim ./sbin/jps-cluster.sh
#覆盖如下内容#!/bin/bash
# 定义所有的节点
HOSTS=( user1 user2 user3 )# 遍历每一个节点
for HOST in ${HOSTS[@]}
do
# 远程登录到指定节点,执行jps命令
ssh -T $HOST << TERMINATER
echo "---------- $HOST ----------"
jps | grep -iv jps
exit
TERMINATER
done#授予执行权限
[root@user1 hadoop-3.3.1]# chmod a+x ./sbin/jps-cluster.sh
执行效果
[root@user1 ~]# jps-cluster.sh
---------- user1 ----------
13442 NameNode
13618 DataNode
---------- user2 ----------
10514 SecondaryNameNode
10405 DataNode
---------- user3 ----------
10931 DataNode
HDFS的角色有三个: NameNode、SecondaryNameNode、DataNode,启动的时候也会有对应的日志文件生成。如果在启动脚本执行之后,发现对应的角色没有启动起来,那就可以去查看日志文件,检查错误的详情,解决问题。
- 日志的位置: $HADOOP_HOME/logs
- 日志的命名: hadoop-username-daemon-host.log
例如:
hadoop-root-namenode-user1.log => user1节点上的namenode的日志 hadoop-root-datanode-user2.log => user2节点上的datanode的日志
- 当前用户使用不当
- /etc/hosts里的映射关系填写错误
- 免密登录认证异常
- jdk环境变量配置错误
- 防火墙没有关闭
问题暴力解决: 重新格式化
当你用了一段时间后想重新格式化,须先把分布式系统上已有的数据文件先删除,否则会出问题,元数据数据格式化后,系统上原有的数据文件会失去组织,发生错乱。
具体步骤:
①若集群是启动状态,先stop-dfs.sh
②三台服务器都要执行删除tmp文件
rm -rf /usr/local/hadoop-3.3.1/tmp/tmp文件是之前我们在core-site.xml配置的hdfs的基础路径。
最好也把logs目录下的内容也清空,因为日志内容已经是前一个废弃集群的日志信息了,留着也无用。
③需要重新进行元数据数据格式化
hdfs namenode -format
这样就格式化成功了。
①数据准备
在user1上执行如下命令
echo "hello world hadoop linux hadoop" >> /home/qd/file1 echo "hadoop linux hadoop linux hello" >>/home/qd/file1 echo "hadoop linux mysql linux hadop" >> /home/qd/file1 echo "hadoop linux hadoop linux hello" >> /home/qd/file1 echo "linux hadoop good programmer" >> /home/qd/file2 echo "good programmer qianfeng good" >> /home/qd/file2
②上传到集群
在user1上将数据上传到HDFS
hdfs dfs -mkdir /input hdfs dfs -put /home/qd/file* /input检查是否已经上传成功
[root@user1 input]# hdfs dfs -ls -R /
drwxr-xr-x - root supergroup 0 2022-06-29 14:11 /input
-rw-r--r-- 1 root supergroup 31 2022-06-29 14:11 /input/file
-rw-r--r-- 1 root supergroup 127 2022-06-29 14:11 /input/file1
-rw-r--r-- 1 root supergroup 59 2022-06-29 14:11 /input/file2
③执行任务
[root@user1 input]# hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.1.jar wordcount /input /output
④查看结果
[root@user1 input]# hdfs dfs -cat /output/*
good 3
hadoop 9
hadop 2
hello 3
linux 10
mysql 2
programmer 2
qianfeng 1
world 1
切记,切记,切记:
- 实际生产环境中,我们不会使用root用户来搭建和管理hdfs,而是使用普通用户。这里为了方便学习,我们才使用的root用户。
- 集群节点一般是需要将防火墙都关闭。一般也部署在局域网内。
- HDFS的NameNode格式化,一般只需要格式化一次,后续切记不能再格式化。
- HDFS的NameNode服务一般都要配置在性能较好的服务器上。
- HDFS如果出现块副本数不一样,可以在1小时候自动复制,如果没有复制可以采取手动修复HDFS集群。
- hadoop.tmp.dir临时目录建议不要默认,因为默认是在/tmp目录下。这个目录下的内是系统控制。建议修改成一个非/tmp的固定目录。
- NameNode在数据量不大情况下,几乎都可以默认,但是如果数据每天增量到TB级别时,一般堆内存要给到50G左右,其它代的内存一般5G左右。
- DataNode的由于主要适用于存取数据,相对使用内存较小,一般堆内存默认5G左右即可。
在浏览器中输入192.168.10.101:9870-->utilities-->browse the file system就能查看分布式的文件系统中的内容。
HDFS其实就是一个分布式的文件系统,我们可以使用一些命令来操作这个分布式文件系统上的文件。
- 访问HDFS的命令:
hadoop fs -- 使用范围更大
hdfs dfs --范围相对较小主要使用hdfs dfs +[...]命令进行对分布式文件系统的操作
- 小技巧
1. 在命令行中输入hdfs,回车后,就会提示hdfs后可以使用哪些命令,其中有一个是dfs。
2. 在命令行中输入hdfs dfs,回车后,就会提示dfs后可以添加的一些常用shell命令。
- 注意事项
分布式文件系统的路径在命令行中,要从/开始写,即绝对路径。
[-mkdir [-p] <path> ...] #在分布式文件系统上创建目录 -p,多层级创建
调用格式: hdfs dfs -mkdir (-p) /目录
例如:
- hdfs dfs -mkdir /data
- hdfs dfs -mkdir -p /data/a/b/c
[-put [-f] [-p] [-l] <localsrc> ... <dst>] #将本地文件系统的文件上传到分布式文件系统
调用格式:hdfs dfs -put /本地文件 /分布式文件系统路径
注意: 直接写/是省略了文件系统的名称hdfs://ip:port。
例如:
- hdfs dfs -put /root/a.txt /data/
- hdfs dfs -put /root/logs/* /data/其他指令:
[-moveFromLocal <localsrc> ... <dst>] #将本地文件系统的文件上传到分布式文件系统
[-copyFromLocal [-f] [-p] [-l] <localsrc> ... <dst>]
[-ls [-d] [-h] [-R] [<path> ...]] #查看分布式文件系统的目录里内容
调用格式:hdfs dfs -ls /[-cat [-ignoreCrc] <src> ...] #查看分布式文件系统的文件内容
调用格式:hdfs dfs -cat /xxx.txttext:
[-tail [-f] <file>] #查看分布式文件系统的文件内容
调用格式:hdfs dfs -tail /xxx.txt
注意:默认最多查看1000行
[-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
注意:本地路径的文件夹可以不存在[-moveToLocal <src> <localdst>]
注意:从hdfs的某个路径将数据剪切到本地,已经被遗弃了[-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
调用格式:同copyToLocal
[-rm [-f] [-r|-R] [-skipTrash] <src> ...]
注意:如果删除文件夹需要加-r[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
注意:必须是空文件夹,如果非空必须使用rm删除
[-df [-h] [<path> ...]] 查看分布式系统的磁盘使用情况
[-du [-s] [-h] <path> ...] #查看分布式系统上当前路径下文件的情况 -h:human 以人类可读的方式显示
[-appendToFile <localsrc> ... <dst>]
调用格式:hdfs dfs -appendToFile 本地文件 hdfs上的文件
注意:不支持在中间随意增删改操作
跟本地的操作一致,-R是让子目录或文件也进行相应的修改
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-setrep [-R] [-w] <rep> <path> ...]
调用格式:hadoop fs -setrep 3 / 将hdfs根目录及子目录下的内容设置成3个副本
注意:当设置的副本数量与初始化时默认的副本数量不一致时,集群会作出反应,比原来多了会自动进行复制.
hdfs dfs [generic options] -stat [format] <path> ...
命令的作用:当向hdfs上写文件时,可以通过dfs.blocksize配置项来设置文件的block的大小。这就导致了hdfs上的不同的文件block的大小是不相同的。有时候想知道hdfs上某个文件的block大小,可以预先估算一下计算的task的个数。stat的意义:可以查看文件的一些属性。
调用格式:hdfs dfs -stat [format] 文件路径
format的形式:
%b:打印文件的大小(目录大小为0)
%n:打印文件名
%o:打印block的size
%r:打印副本数
%y:utc时间 yyyy-MM-dd HH:mm:ss
%Y:打印自1970年1月1日以来的utc的微秒数
%F:目录打印directory,文件打印regular file注意:
1)当使用-stat命令但不指定format时,只打印创建时间,相当于%y
2)-stat 后面只跟目录,%r,%o等打印的都是0,只有文件才有副本和大小
hdfs dfs [generic options] -test -[defsz] <path>
参数说明: -e:文件是否存在 存在返回0 -z:文件是否为空 为空返回0 -d:是否是路径(目录) ,是返回0
调用格式:hdfs dfs -test -d 文件
实例:hdfs dfs -test -d /shelldata/111.txt && echo "OK" || echo "no"
解释:测试当前的内容是否是文件夹 ,如果是返回ok,如果不是返回no
修改core-site.xml文件;注意:我们需要在namenode和datanode同时设置垃圾回收
<property>
<name>fs.trash.interval</name>
<!-- 1440分钟后检查点会被清除,如果为0,垃圾回收站不会启用. -->
<value>1440</value>
</property>
<property>
<name>fs.trash.checkpoint.interval</name>
<value>0</value>
</property>