HDFS 原理和安装

教程 薪牛 ⋅ 于 2023-01-03 22:52:54 ⋅ 1687 阅读

1 HDFS原理及搭建

前提:HDFS在Hadoop中是用来对数据进行分布式存储的,提供了数据的容错能力。在没有Hadoop之前,我们的数据存储在哪?以及怎样保证数据的容错特性呢?

1.1 单块硬盘

​ 单机时代:早期互联网刚发展的时候,各种硬件资源相对缺乏,成本较高。我们将数据写入到磁盘中,一块不够再来一块,如果把数据一块磁盘一块磁盘的写,有如下问题:

​ 1)单块磁盘写,磁盘读写速度上不去,读写慢;

​ 2)数据写入单块磁盘,一旦磁盘故障导致数据丢失;

​ 在这种情况下,RAID技术就应运而生了。

1.2 RAID

​ RAID ( Redundant Array of Independent Disks )即独立磁盘冗余阵列,简称为「磁盘阵列」,其实就是用多个独立的磁盘组成在一起形成一个大的磁盘系统,从而实现比单块磁盘更好的存储性能和更高的可靠性。

file

​ 根据 RAID 算法的不同,RAID 有很多种。下面主要介绍 RAID0、RAID1、RAID10。

1.2.1 RAID0

​ RAID0 是一种非常简单的的方式,它将多块磁盘组合在一起形成一个大容量的存储。

​ 假设阵列中有N块磁盘,当写数据时,会将数据分为N份,然后分别写入N块 磁盘中。因此,RAID0将提供非常优秀的读写性能。

file

优点:

​ 并行写入读取快,空间利用率高。

​ 如果你要读取/写入 2G 的数据,在普通硬盘上,要以单盘的速度读取/写入 2G 的数据。

​ 如果在 4 盘 RAID0 阵列中,每个盘只需读取/写入 500MB 的数据,四个盘可以并行读取/写入,因此理论的读写速度将是单块硬盘的4倍。

缺点:

​ 只要阵列中有一块硬盘坏掉,由于这块硬盘保存着所有数据(每个文件)的某一部分,因此所有数据都将无法读取,整个阵列中的数据将宣告报废。

1.2.2 RAID1

​ RAID1 是磁盘阵列中单位成本最高的一种方式。因为它的原理是在往磁盘写数据的时候,将同一份数据无差别的写两份到磁盘,分别写到工作磁盘和镜像磁盘,那么它的实际空间使用率只有50%了,两块磁盘当做一块用,这是一种比较昂贵的方案。

file

优点:

​ 数据写入两个磁盘,通过冗余存储实现容错。

缺点:

​ 空间利用率低,读写速度慢。

1.2.3 RAID10

​ RAID10其实就是RAID1与RAID0的一个合体。

file

​ 先将磁盘阵列组成 RAID1, 再将多个RAID1 组成 RAID0。

​ 读写数据时,可以将数据分N块,并行写入,而且每块数据都有备份。

​ 这样既可以通过冗余存储容错,也可以提高读写的效率。

2 HDFS组件详解

​ HDFS是Hadoop Distribute File System 的简称,也就是Hadoop的一个分布式文件系统,用来解决存储问题。

​ HDFS 可以使用低成本的硬件来搭建。

​ HDFS 可以对海量的数据进行分布式存储。

​ HDFS 实现软件RAID10。

2.1 HDFS 组件介绍-namenode、datanode

file

在 HDFS 体系结构中有两类结点:

​ 一类是 NameNode,又叫“名称结点”

​ 另一类是 DataNode,又叫“数据结点”。

NameNode

1)用来储元数据。接收客户端的读写请求 ,namenode元数据保存到了内存中和磁盘中,保存到内存中是为了快速查询数据信息,保存到磁盘中是为了数据安全。

元数据包括:

  1. 文件名称
  2. 文件大小
  3. 文件权限
  4. 文件所有者
  5. 文件切了几块
  6. 副本数量
  7. 每一块数据存到了哪一个datanode上

2)一般有一个active状态的namenode,有两个standby状态的namenode,其中,active状态的NameNode负责所有的客户端操作,standby状态的NameNode处于从属地位,维护着数据状态,随时准备切换。

3)一个数据块的元数据信息占用namenode内存存储空间为150字节。块越小读取的速度就越快,但是整体占用namenode的空间就越大。

DataNode

​ 干活的。负责存储client发来的数据块block;执行数据块的读写操作。

2.2 namenode环境搭建

  1. 2.2.1一共需要6台服务器,复用之前我们的6台服务器
  • namenode所在服务器:nn1 nn2 nn3

  • datanode所在服务器:s1 s2 s3

file

2.启动6台服务器,并打开所有服务器的shell终端,通过批量命令切换到hadoop用户

#切换用户
su - hadoop
#解压hadoop到 /usr/local目录中
ssh_root.sh tar -zxvf /public/software/bigdata/hadoop-3.1.4.tar.gz -C /usr/local/
#查询解压完毕的安装包
ssh_root.sh ls /usr/local/|grep hadoop-3.1.4

file

#修改安装包的用户权限归属为hadoop用户,因为以后我们都使用hadoop用户安装和使用
ssh_root.sh chown  -R hadoop:hadoop  /usr/local/hadoop-3.1.4/
#创建软连接,使用起来更方便 连接文件不用修改权限
ssh_root.sh ln -s /usr/local/hadoop-3.1.4/ /usr/local/hadoop

file

3)打开hadoop安装目录

file

(1)bin目录:存放对Hadoop相关服务(hdfs,yarn,mapred)进行操作的脚本

(2)etc目录:Hadoop的配置文件目录,存放Hadoop的配置文件

(3)lib目录:存放Hadoop的本地库(对数据进行压缩解压缩功能)

(4)sbin目录:存放启动或停止Hadoop相关服务的脚本

(5)share目录:存放Hadoop的依赖jar包、文档、和官方案例

# 配置环境变量
echo 'export HADOOP_HOME=/usr/local/hadoop' >> /etc/profile
echo 'export PATH=$PATH:$HADOOP_HOME/bin' >> /etc/profile
echo 'export PATH=$PATH:$HADOOP_HOME/sbin' >> /etc/profile
#分发所有机器上
scp_all.sh /etc/profile /tmp
ssh_root.sh  mv /tmp/profile /etc
#让环境变量生效
ssh_all.sh source /etc/profile

file

4)修改配置文件启动namenode和datanode

  • 进入hadoop的配置文件目录

file

core-site.xml

<property>
    <name>fs.defaultFS</name>
    <value>hdfs://ns1</value>
    <description>默认文件服务的协议和NS逻辑名称,和hdfs-site.xml里的对应此配置替代了1.0里的fs.default.name</description>
</property>
<property>
    <name>hadoop.tmp.dir</name>
    <value>/data/tmp</value>
    <description>数据存储目录</description>
</property>
<property>
        <name>hadoop.proxyuser.root.groups</name>
        <value>hadoop</value>
        <description>配置root(超级用户)允许通过代理用户所属组</description>
</property>
<property>
    <name>hadoop.proxyuser.root.hosts</name>
    <value>localhost</value>
    <description>配置root(超级用户)允许通过代理访问的主机节点</description>
</property> 

hdfs-site.xml

<property>
    <name>dfs.namenode.name.dir</name>
    <value>/data/namenode</value>
    <description>namenode本地文件存放地址</description>
</property>
<property>
    <name>dfs.nameservices</name>
    <value>ns1</value>
    <description>提供服务的NS逻辑名称,与core-site.xml里的对应</description>
</property>
<!--主要的-->
<property>
    <name>dfs.ha.namenodes.ns1</name>
    <value>nn1,nn2,nn3</value>
    <description>列出该逻辑名称下的NameNode逻辑名称</description>
</property>
<!--主要的-->
<property>
    <name>dfs.namenode.rpc-address.ns1.nn1</name>
    <value>nn1:9000</value>
    <description>指定NameNode的RPC位置</description>
</property>
<!--主要的-->
<property>
    <name>dfs.namenode.http-address.ns1.nn1</name>
    <value>nn1:50070</value>
    <description>指定NameNode的Web Server位置</description>
</property>
<!--主要的-->
<property>
    <name>dfs.namenode.rpc-address.ns1.nn2</name>
    <value>nn2:9000</value>
    <description>指定NameNode的RPC位置</description>
</property>
<!--主要的-->
<property>
    <name>dfs.namenode.http-address.ns1.nn2</name>
    <value>nn2:50070</value>
    <description>指定NameNode的Web Server位置</description>
</property>
<!--主要的-->
<property>
    <name>dfs.namenode.rpc-address.ns1.nn3</name>
    <value>nn3:9000</value>
    <description>指定NameNode的RPC位置</description>
</property>
<!--主要的-->
<property>
    <name>dfs.namenode.http-address.ns1.nn3</name>
    <value>nn3:50070</value>
    <description>指定NameNode的Web Server位置</description>
</property>
<property>
    <name>dfs.namenode.handler.count</name>
    <value>77</value>
    <description>namenode的工作线程数</description>
</property>

hadoop-env.sh

# The maximum amount of heap to use, in MB. Default is 1000.
# java虚拟机使用的最大内存
source /etc/profile
export HADOOP_HEAPSIZE_MAX=512
#首先分发以上配偶的文件到其他机器中
scp_all.sh /usr/local/hadoop/etc/hadoop/core-site.xml /usr/local/hadoop/etc/hadoop/
scp_all.sh /usr/local/hadoop/etc/hadoop/hdfs-site.xml /usr/local/hadoop/etc/hadoop/
scp_all.sh /usr/local/hadoop/etc/hadoop/hadoop-env.sh /usr/local/hadoop/etc/hadoop/

5)将/data目录所有者和属组改为hadoop

ssh_root.sh chown hadoop:hadoop /data

file

6)格式化第一台namenode

#在第一台机器上面进行数据的格式化
hdfs namenode -format

file

7)格式化成功之后会看到/data/namenode/current目录下有一个fsimage文件

file

fsimage文件是namenode元数据的镜像文件,想当于内存中元数据的快照。

#启动第一台namenode
hadoop-daemon.sh start namenode

file

file

8)格式化第二台和第三台namenode

#在nn2和nn3上执行
hdfs namenode -bootstrapStandby

注意:此时不出意外的话要出意外了,格式化第二台namenode的时候竟然没有成功

分析原因:当我格式化第二台namenode的时候需要从第一台同步元数据,多台namenode要保证数据一致,此时需要另外一个组件journalnode

2.3 journalnode环境搭建

file

  1. journalnode的配置-在hdfs-site.xml中添加如下配置

    <property>
    <name>dfs.namenode.shared.edits.dir</name>
    <value>qjournal://nn1:8485;nn2:8485;nn3:8485/ns1</value>
    <description>指定用于HA存放edits的共享存储,通常是namenode的所在机器</description>
    </property>
    <property>
    <name>dfs.journalnode.edits.dir</name>
    <value>/data/journaldata/</value>
    <description>journaldata服务存放文件的地址</description>
    </property>
    <property>
    <name>ipc.client.connect.max.retries</name>
    <value>10</value>
    <description>namenode和journalnode的链接重试次数10次</description>
    </property>
    <property>
    <name>ipc.client.connect.retry.interval</name>
    <value>10000</value>
    <description>重试的间隔时间10s</description>
    </property>
#将hdfs-site.xml发送到其他节点
scp_all.sh /usr/local/hadoop/etc/hadoop/hdfs-site.xml /usr/local/hadoop/etc/hadoop/

2.因为journalnode是用来进行namenode数据同步的,所以需要先启动三台journalnode再对namenode进行格式化

启动journalnode之前先将nn1上namenode停掉,并将格式化生成的/data/namenode目录删除掉

hadoop-daemon.sh stop namenode
rm -rf /data/namenode
#启动两个机器的journalnode
#nn1 nn2 nn3
su - hadoop
hadoop-daemon.sh start journalnode

file

file

3.journalnode已经准备完毕,那么再次格式化第一台namenode并启动,

#在nn1机器上面进行namenode的格式化
hdfs namenode -format
#启动nn1上的namenode
hadoop-daemon.sh start namenode

然后再次格式化第二台namenode试一下,你会惊奇的发现意外没有了,并且成功同步了nn1节点的元数据。

file

file

4,格式化并启动第三台namenode,并访问页面进行测试

#格式化第二台和第三台namenode
hdfs namenode -bootstrapStandby
#启动第二台和第三台namenode
hadoop-daemon.sh start namenode

file

5.格式化第三台namenode并启动测试

6.到此为止namenode和journalnode全部搭建完毕,开心一小下,离成功越来越近了

file

7.环境搭建问题解决了,大家跟我想另外两个问题

  1. journalnode怎么做到的元数据的同步。

file

  • Namenode 除了内存存储元数据外,磁盘也存储,主要维护两个文件,一个是fsimage,一个是 editlog

    editlog(简称edits):

    ​ 操作日志文件,记录了NameNode所要执行的操作;

     **fsimage:**

    ​ 元数据镜像文件。存储某NameNode元数据信息,并不是实时同步内存中的数据。

    ​ 一般而言,fsimage中的元数据是落后于内存中的元数据的;

    ​ 当有写请求时,NameNode会首先写该操作先写到磁盘上的edits文件中,当edits文件写成功后才会修改NameNode内存的元数据,内存修改成功后向客户端返回成功信号。

    请求操作记录除了会写入到activenamenode中的edits文件中,还会给journalnode中写入edits文件,然后journalnode会将本地的edits文件中的请求操作,在standbynamenode中进行同步。这样就可以进行元数据的同步了

  1. namenode元数据是怎么进行合并的。

    • 随着edits记录的操作越来越多,内存中的元数据越来越多,这样的话内存中的元数据存在风险,一旦宕机,内存数据丢失,所以为了安全起见,需要将内存中的元数据,周期性的写入到fsimage文件中。如果数据出错可以通过 fsimage + edits 恢复。
    • 因为ActiveNamenode相对来说比较忙,所以选择相对轻松的StandbyNamenode来做元数据同步这个事情

file

3.合并周期是什么呢?

  • StandByNamenode检查是否达到checkpoint条件:离上一次checkpoint操作是否已经有一个小时,或者HDFS已经进行了100万次操作。

  • StandByNamenode检查达到checkpoint条件后,将该元数据以fsimage.ckpt_txid格式保存到StandByNamenode的磁盘上,并且随之生成一个MD5文件。然后将该fsimage.ckpt_txid文件重命名为fsimage_txid。

  • 然后StandByNamenode通过HTTP联系ActiveNameNode。

  • ActiveNameNode通过StandByNamenode从StandByNamenode获取最新的fsimage_txid文件并保存为fsimage.ckpt_txid,然后也生成一个MD5,将这个MD5与StandByNamenode的MD5文件进行比较,确认ANN已经正确获取到了StandByNamenode最新的fsimage文件。然后将fsimage.ckpt_txid文件重命名为fsimage_txit。   

    通过上面一系列的操作,SBNN上最新的FSImage文件就成功同步到了ANN上

4,周期不是固定的,可以通过配置文件进行配置

<property>
    <name> dfs.namenode.checkpoint.period</name>
  <value>3600</value>
  <description>
    两次连续的 checkpoint 之间的时间间隔。默认 1 小时
  </description>
</property>
<property>
  <name>dfs.namenode.checkpoint.txns</name>
  <value>1000000</value>
  <description>最大的没有执行 checkpoint 事务的数量,满足将强制执行紧急 checkpoint,即使尚未达到检查点周期。默认设置为 100 万。
  </description>
</property>

2.4 ZKFC环境搭建

file

  1. 三台namenode已经全部启动成功,但是和我们想的还不太一样,最开始我们定的是有一个namenode是active的也就是老大,另外两个namenode是备份的小弟,但是现在查看三个namenode都是小弟,这怎么办?

    答案:可以程序员自己决定

    #手动切换nn1的节点是主节点
    hdfs haadmin -transitionToActive nn1
    #查看节点状态
    hdfs haadmin -getServiceState nn1

file

  1. 如果每次都是程序员自己切换的话,那也太不灵活了,所以需要引入一个组件,就是zkfc

  2. zkfc本质上就是一个进程,全称是ZKFailoverController,需要在三台namenode上启动。它的主要任务就是一边联系同服务器的namenode,一边连接zookeeper。我们三个namenode启动之后,怎么通过zkfc选出一个active的namenode呢?那就看哪台节点的zkfc先在zookeeper中创建节点。谁创建成功,哪台服务器就是active的namenode,具体过程如下:

    主备切换过程

    • ① 启动NameNode,ZKFC,此时三个NameNode的状态都是竞选状态

    • ② 三个ZKFC分别通过ActiveStandbyElector发起NameNode的选举
      通过zookeeper的写一致性以及临时节点来实现

    • ③ 发起主备选举的时候,ActiveStandbyElector会尝试在zookeeper的/hadoop-ha/ns1创建一个临时节点,zookeeper的写一致性会保证只有一个节点创建成功

    • ④ 创建成功的ActiveStandbyElector通过回调方式通知ZKFC,将对应的NameNode切换为Active状态;创建失败的也通过同样方式将NameNode切换为Standby状态

    • ⑤ 无论是否创建成功,这些ActiveStandbyElector都会监听/hadoop-ha/ns1;
      当Active NameNode对应的HealthMonitor监控到NameNode异常时,会告知ZKFC,ZKFC通过ActiveStandbyElector删除所创建的临时节点

    • ⑥ 此时处于Standby的NameNode会监控到这个消息它首先会通过判断节点是否存在来确认情况
      如果是正常关闭的,则发起主备选举,成功创建临时节点,并且将NameNode的状态切换为Active

4.zkfc安装

core-site.xml中添加一下内容

<property>
    <name>ha.zookeeper.quorum</name>
    <value>nn1:2181,nn2:2181,nn3:2181</value>
    <description>HA使用的zookeeper地址</description>
</property>

hdfs-site.xml增加如下配置

<property>
    <name>dfs.ha.fencing.methods</name>
    <value>sshfence</value>
    <description>指定HA做隔离的方法,缺省是ssh,可设为shell,稍后详述</description>
</property>

<property>
    <name>dfs.ha.fencing.ssh.private-key-files</name>
    <value>/home/hadoop/.ssh/id_rsa</value>
    <description>杀死命令脚本的免密配置秘钥</description>
</property>
<property>
        <name>dfs.client.failover.proxy.provider.ns1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

<property>
     <name>dfs.client.failover.proxy.provider.auto-ha</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property> 

<property>
    <name>dfs.ha.automatic-failover.enabled</name>
    <value>true</value>
</property>
#分发脚本配置到各个节点
scp_all.sh /usr/local/hadoop/etc/hadoop/core-site.xml /usr/local/hadoop/etc/hadoop/
scp_all.sh /usr/local/hadoop/etc/hadoop/hdfs-site.xml /usr/local/hadoop/etc/hadoop/

file

启动zkfc之前需要在zookeeper中初始化zkfc的节点

#在nn1节点执行
hdfs zkfc -formatZK

file

分别在nn1,nn2,nn3 机器启动zkfc

#nn1 nn2 nn3启动zkfc
hadoop-daemon.sh start zkfc

file

重启三台namenode查看是否会选举active namenode

#三个机器分别重启namenode
hadoop-daemon.sh stop namenode
hadoop-daemon.sh start namenode

file

当nn1的namenode宕掉,看看是否可以进行故障切换

file

恭喜nn2变成active的namenode

file

当nn2的namenode宕掉,看看是否可以再次进行故障切换

file

file

hadoop3.x之后,可以两个namenode宕机

2.5 Datanode环境搭建

file

  1. 数据是切块进行分布式存储的,而每个block块都需要存储在datanode上。
  2. 我们之前了解到namenode的其中一个作用是元数据,另外一个作用就是用来理datanode
  3. 每隔3sdatanode就会想namenode汇报自身情况,如果超过10min中没有收到datanode的心跳信息,namenode就会认为此datanode丢失了,将其身上的数据拷贝到其他服务器中。
  4. datanode在启动成功之后会接收namenode同步过来的clusterid,之后的通信过程中,datanode都会带着clusterid去和namenode通信,所以切记不要频繁的格式化namenode,因为每一次格式化namenode都会重新产生新的clusterid,造成namenode和datanode起不来的情况出现

  5. 安装 datanode

    修改hdfs-site.xml

<property>
    <name>dfs.datanode.data.dir</name>
    <value>/data/datanode</value>
    <description>datanode本地文件存放地址</description>
</property>
<property>
    <name>dfs.replication</name>
    <value>3</value>
    <description>文件复本数</description>
</property>
<property>
    <name>dfs.namenode.datanode.registration.ip-hostname-check</name>
    <value>false</value>
</property>
<property>
    <name>dfs.client.use.datanode.hostname</name>
    <value>true</value>
</property>
<property>
    <name>dfs.datanode.use.datanode.hostname</name>
    <value>true</value>
</property>

修改workers

file

#分发配置文件到各个节点中
 scp_all.sh /usr/local/hadoop/etc/hadoop/hdfs-site.xml /usr/local/hadoop/etc/hadoop/
 scp_all.sh /usr/local/hadoop/etc/hadoop/workers /usr/local/hadoop/etc/hadoop/
 #启动各个节点的datanode
hadoop-deamons.sh start datanode

file

file

到此为止,hdfs所有组件全部启动成功。如果大家和我一样的话,恭喜大家!!!

以后启动可以不用一个一个启,我们可以一起全部启动

# 关闭hdfs的所有进程
stop-dfs.sh

file

#启动hdfs的所有进程

start-dfs.sh 

file

测试向hdfs存储数据

# 在hdfs的根路径创建student目录
hadoop  fs -mkdir /student

file

# 向student目录上传文件 1.txt 是linux本地文件 
hadoop fs -put 1.txt /student

file

file

datanode数据存储路径:

/data/datanode/current/BP-1353249831-11.94.204.125-1670328197569/current/finalized/subdir0/subdir0

#存储文件
blk_1073741831
#这个blk的信息[大小  创建时间  校验和]
blk_1073741831_1007.meta

file

file

总结:

file

NameNode:用来理datanode,并用来储元数据

journalnode:负责两个状态的namenode进行数据同步,保持数据一致。

ZKFC:作用是HA自动切换。会将NameNode的active状态信息保存到zookeeper。

DataNode:负责存储client发来的数据块block;执行数据块的读写操作。

2.6.hdfs的高级配置

core-site.xml中进行配置

#开启本地库对压缩的支持
<property>
    <name>io.native.lib.available</name>
    <value>true</value>
    <description>开启本地库支持</description>
</property>
#支持的压缩格式
<property>
    <name>io.compression.codecs</name>    <value>org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.BZip2Codec,org.apache.hadoop.io.compress.SnappyCodec</value>
    <description>相应编码的操作类</description>
</property>
#SequenceFiles在读写中可以使用的缓存大小
<property>
    <name>io.file.buffer.size</name>
    <value>131072</value>
    <description>SequenceFiles在读写中可以使用的缓存大小</description>
</property>
# 设置mr输入到hdfs中的数据的压缩是按照块压缩
<property>
    <name>mapreduce.output.fileoutputformat.compress.type</name>
    <value>BLOCK</value>
</property>
# 出入到hdfs中的文件是按照块为一个整体进行压缩
<property>
    <name>io.seqfile.compressioin.type</name>
    <value>BLOCK</value>
</property>
# 客户端连接超时时间
<property>
    <name>ipc.client.connection.maxidletime</name>
    <value>60000</value>
</property>

hdfs-site.xml中的配置

# hdfs开启支持文件追加操作
#关闭文件系统权限
#开启垃圾箱,删除的文件不会消失会移除到垃圾箱中
<property>
    <name>dfs.support.append</name>
    <value>true</value>
    <description>是否支持追加</description>
</property>
<property>
    <name>dfs.permissions.enabled</name>
    <value>false</value>
    <description>是否开启目录权限</description>
</property>
<property>
    <name>fs.trash.interval</name>
    <value>2880</value>
    <description>回收周期</description>
</property>
# datanode在读写本地文件的时候设置最大机器文件打开数
<property>
        <name>dfs.datanode.max.transfer.threads</name>
        <value>8192</value>
        <description>相当于linux下的打开文件最大数量,文档中无此参数,当出现DataXceiver报错的时候,需要调大。默认256</description>
</property>
# 在hdfs多个节点中数据均衡的时候能够用到的最大系统带宽,防止占用太多带宽
<property>
        <name>dfs.datanode.balance.bandwidthPerSec</name>
        <value>104857600</value>
</property>
# 设置每个机器的磁盘要预留两个G的数据,不能全部都给hdfs使用
# 设置存储的datanode机器的选择策略,优先以机器剩余磁盘存储两个G以上
<property>
    <name>dfs.datanode.du.reserved</name>
    <value>2147483648</value>
    <description>每个存储卷保留用作其他用途的磁盘大小</description>
</property>
<property>
    <name>dfs.datanode.fsdataset.volume.choosing.policy</name>
    <value>org.apache.hadoop.hdfs.server.datanode.fsdataset.AvailableSpaceVolumeChoosingPolicy</value>
    <description>存储卷选择策略</description>
</property>

<property>
    <name>dfs.datanode.available-space-volume-choosing-policy.balanced-space-threshold</name>
    <value>2147483648</value>
    <description>允许的卷剩余空间差值,2G</description>
</property>
# 设置客户端读取数据
# 如果读取数据的客户端和datanode在同一个机器上那么可以直接从本地读取数据,不需要走远程IO
<property>
    <name>dfs.client.read.shortcircuit</name>
    <value>true</value>
</property>
<property>
    <name>dfs.domain.socket.path</name>
    <value>/data/dn_socket_PORT</value>
</property>
#复制以上内容到core-site.xml和hdfs-site.xml中
#将这个文件分发到不同的机器中
scp_all.sh /usr/local/hadoop/etc/hadoop/hdfs-site.xml /usr/local/hadoop/etc/hadoop/
scp_all.sh /usr/local/hadoop/etc/hadoop/core-site.xml /usr/local/hadoop/etc/hadoop/
#重启集群
stop-dfs.sh
start-dfs.sh

3 HDFS命令

3.1 配置操作机

file

hadoop集群在正常公司集群部署的时候我们是不能直接使用的,这也是为了集群安全来考虑,所以需要一个操作机去代理我们将请求发送到hadoop集群。

这就需要让操作机能够识别我们的操作命令。需要给操作机配置相应的环境

#进入op机器,并且创建hadoop用户
useradd hadoop
#设置hadoop密码
passwd hadoop
#使用root用户解压hadoop到/usr/local下面
tar -zxvf /public/software/bigdata/hadoop-3.1.4.tar.gz -C /usr/local

file

#删除原来的软连接
#使用root用户创建软连接
rm -rf /usr/local/hadoop
ln -s /usr/local/hadoop-3.1.4/ /usr/local/hadoop

file

#删除hadoop的配置文件
rm -rf /usr/local/hadoop/etc/hadoop/*
# 将nn1配置好的配置文件放入到op机中
scp -r root@11.237.80.38:/usr/local/hadoop/etc/hadoop/ /usr/local/hadoop/etc/hadoop/* 

file

file

# 修改hadoop文件夹的权限给hadoop用户使用

chown hadoop:hadoop -R /usr/local/hadoop-3.1.4/

file

# 切换用户,配置环境变量
su - hadoop
vim ~/.bash_profile 
#增加如下配置
export JAVA_HOME=/usr/local/jdk1.8.0_144
export PATH=$PATH:$JAVA_HOME/bin
export HADOOP_HOME=/usr/local/hadoop
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin

# source配置文件生效
source ~/.bash_profile

file

测试操作机好不好用

file

file

3.2 hdfs常用命令

1) 查看hdfs根目录

# 标准写法
hadoop fs -ls hdfs://ns1/
# 简写(推荐)
hadoop fs -ls /
# -h:文件大小显示为最大单位,更加人性化
hadoop fs -ls -h /
# -R:递归显示
hadoop fs -ls -R /  

file

2) 上传文件/目录 put

hdfs的写流程:

file

#创建本地文件
echo hello wuyifan >> ~/demo.txt
#标准写法:put 左面:是本地,右面是hdfs集群
hadoop fs -put ~/demo.txt hdfs://ns1/
#简写:右面默认找hdfs (推荐)
hadoop fs -put ~/demo.txt /
#当上传时要对文件进行重名
hadoop fs -put  ~/demo.txt /demo1.txt
#在本地创建多个文件
echo 'hello' >> a.txt
echo 'world' >> b.txt
#一次上传多个文件到HDFS路径
hadoop fs -put a.txt b.txt  /  
#上传目录
mkdir ceshi
cd ceshi
touch aa.txt
touch bb.txt
hadoop fs -put ceshi /    
# -f覆盖上传
hadoop fs -put -f demo.txt /

file

file

3) 读取文件 cat

HDFS的读流程

file

#如果文件太大,不要用cat读取文件
hadoop fs -cat /data/demo.log

4) 下载文件/目录 get

#下载hdfs文件到本地目录
hadoop fs -get /demo.txt ./
#下载hdfs文件到本地目录并重命名
hadoop fs -get /demo.txt ./nihao.txt

file

5) 拷贝文件/目录 cp

# 创建新的文件
touch word.txt
# 上传本地文件使用file:开头
hadoop fs -cp file:/home/hadoop/word.txt /
# 查看上传
hadoop fs -ls /
# 从hdfs进行拷贝
hadoop fs -cp /demo.txt /ceshi
# 查询
hadoop fs -ls /ceshi

file

6) 剪切文件 mv

#剪切
hadoop fs -mv /b.txt /ceshi
#查询
hadoop fs -ls /
hadoop fs -ls /ceshi

file

7)删除文件/目录 rm

执行-rm 命令后,默认是把文件移动到 user/hadoop/.Trash/Current 下,会根据配置文件配置的清理周期定期清理。

#删除文件
hadoop fs -rm /demo.txt
#匹配模式删除所有文件
hadoop fs -ls /ceshi 
hadoop fs -rm /ceshi/*.log
#报错 rm只能删除文件
hadoop fs -rm /ceshi
#强制删除,并且递归删除文件夹中的内容
hadoop fs -rmr /ceshi
#删除之后不放到回收站  
hadoop fs -rm -skipTrash /a.txt

file

file

file

file

8)创建空文件 touchz

hadoop fs - touchz /aa.txt

file

9) 创建目录 mkdir

#可以同时创建多个目录
hadoop fs -mkdir /tmp1 /tmp2   
#同时创建父级目录
hadoop fs -mkdir -p /dir1/dir2/dir3

file

10) 读取文件尾部 tail**

#查看尾部1K字节   
hadoop fs -tail /demo1.txt

file

11) 追加写入文件 appendToFile

#本地创建文件 note.txt
touch note.txt
#写入hello
echo 'hello' >> note.txt
#本地创建文件 new.txt
touch new.txt
#写入world
echo 'world' >> new.txt
#将note.txt上传到hdfs中
hadoop fs -put note.txt /
#将new.txt的内容追加到node.txt中
hadoop fs -appendToFile new.txt /note.txt

file

12 获取逻辑空间文件/目录大小 du

#显示HDFS根目录中各文件和文件夹大小
hadoop fs -du / 
#以最大单位显示HDFS根目录中各文件和文件夹大小
hadoop fs -du -h / 
#仅显示HDFS根目录大小。即各文件和文件夹大小之和
hadoop fs -du -s -h /

file

file

13 改变文件副本数 setrep

#-R 递归改变目录下所有文件的副本数。
#-w 等待副本数调整完毕后返回。可理解为加了这个参数就是阻塞式的了。
hadoop fs -setrep -R -w 2 /demo.txt

file

修改之后

file

file

14 ) 获取HDFS目录的物理空间信息 count

hadoop fs -count / #显示HDFS根目录在物理空间的信息

file

3.3 hdfs高级命令

hdfs dfsadmin**

例如:hadoop dfsadmin -report

dfsadmin命令详解

1) -report:

        查看文件系统的基本信息和统计信息。

2)-safemode :

        安全模式命令。安全模式是NameNode的一种状态,在这种状态下,NameNode不接受对元数据的更改(只读);不复制或删除块。NameNode在启动时自动进入安全模式,当配置块的最小百分数满足最小副本数的条件时,会自动离开安全模式。enter是进入,leave是离开 。

#进入安全模式
hadoop dfsadmin  -safemode enter
#离开安全模式
hadoop dfsadmin -safemode leave
#获取安全模式信息
hadoop dfsadmin -safemode get

file

在安全模式情况下不允许任何hdfs的修改操作的

file

file

安全模式下可以查询元数据信息,但是不能对文件做任何的修改

4 Fsimage和Edits文件详解

1) 首先我们看一下两个文件存放的目录/data/namenode/current

file

2) VERSION是java属性文件,内容大致如下:

file

  1. namespaceID是文件系统唯一标识符
  2. clusterID是系统生成或手动指定的集群ID
  3. cTime表示Namenode存储的创建时间
  4. storageType表示这个文件存储的是什么进程的数据结构信息
  5. blockpoolID表示每一个namenode对应的块池id,这个id包括了其对应的Namenode节点的ip地址。
  6. layoutVersion表示HDFS永久性数据结构的版本信息,只要数据结构变更,版本号也要递减

*3)edits_文件**

edits文件中存放的是客户端执行的所有更新命名空间的操作。

# hdfs oev 解析操作日志文件并且输入到相应的目录中 -i 输入 -o 输出 -p 默认就是xml
hdfs oev -i edits_0000000000000000138-0000000000000000145 -o ~/edits.txt
#查看edits文件
vim ~/edits.txt

file

file

file

4) seen_txid文件

这个文件中保存了一个事务id,这个事务id并不是Namenode内存中最新的事务id。这个文件的作用在于Namenode启动时,利用这个文件判断是否有edits文件丢失,Namenode启动时会检查seen_txid并确保内存中加载的事务id至少超过seen_txid,否则Namenode将终止启动操作。

*5) fsimage_文件**

#先进入安全模式
hadoop dfsadmin  -safemode enter
#首先我们手动触发合并元数据
hadoop dfsadmin -saveNamespace
#然后将fsimage数据导出到文本中
hdfs oiv -i fsimage_0000000000000000024 -o ~/fs.xml -p xml

fs.xml里面有

  • version:version描述的一些版本信息
  • NameSection:描述的是命名空间的一些信息
  • ErasureCodingSection:纠删码
  • INodeSection:INodeSection 由一段一段inode组成,是image中内容最大部分,除了上述的几个片段,image中剩下的内容全部都是inode。

*6) fsimage_.md5文件**

md5校验文件,用于确保fsimage文件的正确性,可以作用于磁盘异常导致文件损坏的情况。

5 扩容datanode节点

file

当磁盘容量不够的时候需要对集群进行动态扩容,还不能停止先有集群正常工作,怎么办呢?

动态增加一个或者多个服务器

file

1) 连接新的服务器

file

2) 创建hadoop用户并设置密码

useradd hadoop
#密码输入12345678
passwd hadoop

3)安装jdk

rpm -ivh /public/software/java/jdk-8u144-linux-x64.rpm

file

4) 配置s4的主机名

vim /etc/hostname

file

5) 将s3上的hadoop安装目录传输到s4上,并配置软连接

 scp -r hadoop@s3:/usr/local/hadoop-3.1.4  /usr/local/
 #修改所有者和属组
 chown hadoop:hadoop -R /usr/local/hadoop-3.1.4
 #创建软连接
 ln -s /usr/local/hadoop-3.1.4/ /usr/local/hadoop

file

6) 将环境变量文件也拷贝一份

scp -r root@s3:/etc/profile  /etc/

file

source /etc/profile

file

7) 修改/data目录所有者和属组

chown hadoop:hadoop /data

file

8) 修改 hosts文件

file

9) 修改其他服务器,添加s4节点的映射

file

10) 配置s4和其他服务器免密码登录

scp -r hadoop@s3:/home/hadoop/.ssh /home/hadoop/

测试免密码登录是否好使

file

11)给workers文件添加s4

#所有节点执行
echo s4 >> /usr/local/hadoop/etc/hadoop/workers 

12) 在新增的s4节点启动datanode

file

file

6 datanode下线

file

为了保证能够识别新创建的节点s4我们关闭环境,重新启动实验

file

先生成镜像然后重新启动

准备一个大文件上传到hdfs上

file

file

file

接下来删除s4节点 需要修改hdfs-site.xml,将要删除的节点配置在文件中,然后配置文件的路径

<property>
    <name>dfs.hosts.exclude</name>
    <value>/usr/local/hadoop/etc/hadoop/excludes</value>
</property>

file

file

将配置文件分发到各个机器节点中

scp_all.sh /usr/local/hadoop/etc/hadoop/excludes /usr/local/hadoop/etc/hadoop/excludes
scp_all.sh /usr/local/hadoop/etc/hadoop/hdfs-site.xml /usr/local/hadoop/etc/hadoop/
#在nn1节点输入
hadoop dfsadmin -refreshNodes

file

s4上面的数据迁移到了其他节点上,此时s4下线成功

后续我们删除 workers中的s4节点,那么下次就不会启动它了

file

scp_all.sh /usr/local/hadoop/etc/hadoop/workers /usr/local/hadoop/etc/hadoop/

file

7 hdfs数据负载均衡

file

Hadoop的HDFS集群非常容易出现机器与机器之间磁盘利用率不平衡的情况,例如:当集群内新增、删除节点,或者某个节点机器内硬盘存储达到饱和值。当数据不平衡时,Map任务可能会分配到没有存储数据的机器,这将导致网络带宽的消耗,也无法很好的进行本地计算。
        当HDFS负载不均衡时,需要对HDFS进行数据的负载均衡调整,即对各节点机器上数据的存储分布进行调整。从而,让数据均匀的分布在各个DataNode上,均衡IO性能,防止热点的发生。进行数据的负载均衡调整,必须要满足如下原则:

  • 数据平衡不能导致数据块减少,数据块备份丢失
  • 管理员可以中止数据平衡进程
  • 每次移动的数据量以及占用的网络资源,必须是可控的
  • 数据均衡过程,不能影响namenode的正常工作

        在Hadoop中,包含一个 start-balancer.sh 脚本,通过运行这个工具,启动HDFS数据均衡服务。该工具可以做到热插拔,即无须重启计算机和 Hadoop 服务。

启动命令为:‘start-balancer.sh –threshold`

影响Balancer的参数:

  • -threshold
  • 默认设置:10,参数取值范围:1-100
  • 参数含义:datanode间磁盘使用率相差阈值。理论上,该参数设置的越小,整个集群就越平衡。
#启动数据均衡,默认阈值为 10%
start-balancer.sh

#启动数据均衡,阈值 5%
start-balancer.sh -threshold 5

#停止数据均衡
stop-balancer.sh
<property>
    <name>dfs.balance.bandwidthPerSec</name>
    <value>104857600</value>
    <description>根据每秒字节数指定每个数据节点可用于平衡的最大带宽,设置为100M</description>
</property>

为了演示效果,上传一些大文件

在集群中上传hadoop的安装包

hdfs dfs -put /public/software/bigdata/hadoop-3.1.4.tar.gz /

复制多分文件

cp /public/software/bigdata/apache-dolphinscheduler-3.1.0-bin.tar.gz  ./do1
#然后赋值翻倍数据
cp do1 do2
cp do1 do3
cp do1 do4
cp do1 do5
cp do1 do6
cp do1 do7
cp do1 do8

#在hdfs创建/test测试目录

hadoop fs -mkdir /test

#将数据存放到/test目录下

hadoop fs -put do1 do2 do3 do4 do5 do6 do7 do8 /test

将s4节点增加进来

将之前excludes文件中s4删除掉,修改workers文件添加s4节点

#删除里面的s4
vim /usr/local/hadoop/etc/hadoop/excludes

file

echo "s4" >> /usr/local/hadoop/etc/hadoop/workers 

file

文件分发

 scp_all.sh /usr/local/hadoop/etc/hadoop/excludes /usr/local/hadoop/etc/hadoop/
 scp_all.sh /usr/local/hadoop/etc/hadoop/workers /usr/local/hadoop/etc/hadoop/

刷新集群

hadoop dfsadmin -refreshNodes

file

此时我们进行数据的负载均衡

首先先降低hdfs使用磁盘的容量,默认73T的容量,测试负载均衡比较困难

#每个节点预留内存是73T,剩余100G
<property>
    <name>dfs.datanode.du.reserved</name>
    <value>80484251153203</value>
    <description>每个存储卷保留用作其他用途的磁盘大小</description>
</property>

file

影响Balancer的参数:

  • -threshold
    • 默认设置:10,参数取值范围:1-100
    • 参数含义:datanode间磁盘使用率相差阈值。理论上,该参数设置的越小,整个集群就越平衡
start-balancer.sh -threshold 1

此时会发现s4数据量越来越多,数据也变得越来越均衡

file

8 机架感知策略

file

我们这里说的机架式逻辑机架而不是物理机架,但是在真正配置的时候,一般逻辑机架,要和物理机架相对应

默认情况下,Hadoop机架感知是没有启用的,需要在NameNode机器的hdfs-site.xml里配置一个选项,例如:

<property>  
    <name>topology.script.file.name</name>
    <value>/usr/local/hadoop/etc/hadoop/tp.py</value>
</property>

其中:

        这个配置选项的 value 指定为一个可执行程序,通常为一个脚本,可以是shell脚本或者python脚本。

        接受的参数通常为 datanode 机器的 ip 地址,而输出的值通常为该ip地址对应的 datanode 所在的rackID,例如”/rack1”。   

        Namenode 启动时,会判断该配置选项是否为空,如果非空,则表示已经启用机架感知的配置,此时 namenode 会根据配置寻找该脚本,并在接收到每一个 datanode 的 heartbeat 时,将该 datanode 的ip地址作为参数传给该脚本运行,并将得到的输出作为该datanode 所属的机架,保存到内存的一个map中。

        至于脚本的编写,就需要将真实的网络拓朴和机架信息了解清楚后,通过该脚本能够将机器的ip地址正确的映射到相应的机架上去。

        当没有配置机架信息时,所有的datanode,hadoop都默认在同一个名为 “/default-rack”机架下。

# 编辑to.py文件,因为官网没有指出到底是根据ip还是hostname进行判断机架
# 所以我们都配置 如下在tp.py中
#!/usr/bin/python

#-*-coding:UTF-8 -*-

import sys

rack = {
        "s1":"hainiu_rack1",
        "s2":"hainiu_rack1",
        "s3":"hainiu_rack2",
        "s4":"hainiu_rack2",
        "11.237.80.49":"hainiu_rack1",
        "11.237.80.44":"hainiu_rack1",
        "11.112.227.52":"hainiu_rack2",
        "11.67.196.12":"hainiu_rack2"
        }

if __name__=="__main__":

    print "/" + rack.get(sys.argv[1],"rack0")

以上的内容根据/etc/hosts中的内容配置

这个时候在集群需要得到机器的远近的时候就可以通过传入ip或者hostname进行判断

#增加执行权限
ssh_all.sh chmod +x /usr/local/hadoop/etc/hadoop/tp.py
#输入命令打印机架感知
 hadoop dfsadmin -printTopology

重启hdfs之后查看

file

版权声明:原创作品,允许转载,转载时务必以超链接的形式表明出处和作者信息。否则将追究法律责任。来自海汼部落-薪牛,http://hainiubl.com/topics/75963
成为第一个点赞的人吧 :bowtie:
回复数量: 0
    暂无评论~~
    • 请注意单词拼写,以及中英文排版,参考此页
    • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
    • 支持表情,可用Emoji的自动补全, 在输入的时候只需要 ":" 就可以自动提示了 :metal: :point_right: 表情列表 :star: :sparkles:
    • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif,教程
    • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
    Ctrl+Enter