HDFS高可用架构涉及常用功能整理

HDFS高可用架构涉及常用功能整理

  • 1. hdfs的高可用系统架构和相关组件
  • 2. hdfs的核心参数
    • 2.1 常规配置
    • 2.2 特殊优化配置
      • 2.1.1 NN优化
      • 2.1.2 DN优化
  • 3. hdfs常用命令
    • 3.1 常用基础命令
    • 3.2 常用运维命令
  • 4. 事务性
    • 4.1 数据写流程
    • 4.2 数据读流程
  • 5. 疑问和思考
    • 5.2. hdfs集群初始化部署流程?
    • 5.4. hdfs是如何选择DN进行数据读写的?
    • 5.3. hdfs在读写过程中如果出现异常该如何处理?
    • 5.4 hdfs不擅长处理哪些场景?
  • 6. 参考文档

探讨hdfs的系统架构以及以及整体常用的命令和系统分析,本文主要探讨高可用版本的hdfs集群,并基于日常工作中的沉淀进行思考和整理。更多关于分布式系统的架构思考请参考文档关于常见分布式组件高可用设计原理的理解和思考


1. hdfs的高可用系统架构和相关组件

NameNode 的高可用发展史在 Hadoop2.0 以前,每个 HDFS 集群只有一个 NameNode,一旦这个节点不可用,则整个HDFS集群将处于不可用状态(即HDFS2.0以前,NameNode存在单点故障风险)。 在HDFS集群中同时运行两个NameNode,通过HA的方式进行集群切换,从而达到高可用的目的。

NN节点有如下2种状态:

  • Active(活跃)状态:负责集群中所有客户端的操作(修改命名空间、删除备份数据块等操作);
  • Standby(备份)状态:充当从服务器,和 Active NameNode 有相同的命名空间和元数据。

当 Active NameNode 停止服务时,Standby NameNode 能够快速进行故障切换,以保证 HDFS 集群服务不受影响。

hdfs的系统架构如下

相关核心的组件和角色作用如下

组件 部署模式 组件作用 备注
NN(active) 单机部署 存储集群的元数据,具体集群数据的全局视角 给客户端提供请求服务等,和standby节点进行形成主备
NN(standby) 单机部署 存储集群的元数据,具体集群数据的全局视角 配合active完成checkpoints,合并editlog和fimage,和active节点进行形成主备
zk 多节点部署 zk提供hdfs的NN选主锁和消息通知,zkfc接受相关zk进行主从切换 通过Zab 协议来保证分布式事务的最终一致性
zkfc 和NN部署 和zk交互,通过zk的消息通知,并调用NN的rpc接口实现集群选主和切主 fencing NN,防止出现多active形成脑裂
jn 多节点部署 active和standby节点的editlog数据桥梁,通过rpc完成数据传输 通过paxos协议选主,建议单数节点部署(3/5/7等)
DN 单机部署 数据的存储节点,会定期上报心跳和当前节点的block信息给NN 保存当前节点的块信息,并监控块状态

2. hdfs的核心参数

2.1 常规配置

hdfs-site.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--
 Licensed ...
-->

<configuration>
    <!-- 定义hdfs的namespace,可以配置多个,使用","分隔 -->
    <property>
        <name>dfs.nameservices</name>
        <value>cluster</value>
    </property>
    <!-- 定义hdfs的NN节点 -->
    <property>
        <name>dfs.ha.namenodes.cluster</name>
        <value>namenode1,namenode2</value>
    </property>
    <!-- 定义hdfs的副本数量 -->
    <property>
        <name>dfs.replication</name>
        <value>3</value>
    </property>
    <!-- 定义是否开启web监控页面 -->
    <property>
        <name>dfs.webhdfs.enabled</name>
        <value>true</value>
    </property>
    <property>
        <name>dfs.permissions</name>
        <value>false</value>
    </property>
    <property>
        <name>dfs.permissions.enabled</name>
        <value>false</value>
    </property>
    <!-- 定义hdfs的NN的editlog保存路径 -->
    <property>
        <name>dfs.namenode.name.dir</name>
        <value>file:/data2/hadoop/dfs/name</value>
    </property>
    <!-- 定义hdfs的NN1,NN2节点信息 -->
    <property>
        <name>dfs.namenode.rpc-address.cluster.namenode1</name>
        <value>xx.xx.xx.xx:9000</value>
    </property>
    <property>
        <name>dfs.namenode.rpc-address.cluster.namenode2</name>
        <value>xx.xx.xx.xx:9000</value>
    </property>
    <property>
        <name>dfs.namenode.servicerpc-address.cluster.namenode1</name>
        <value>namenode1:53310</value>
    </property>
    <property>
        <name>dfs.namenode.servicerpc-address.cluster.namenode2</name>
        <value>namenode2:53310</value>
    </property>
    <property>
        <name>dfs.namenode.http-address.cluster.namenode1</name>
        <value>xx.xx.xx.xx:50070</value>
    </property>
    <property>
        <name>dfs.namenode.http-address.cluster.namenode2</name>
        <value>xx.xx.xx.xx:50070</value>
    </property>
    <property>
        <name>dfs.namenode.https-address.cluster.namenode1</name>
        <value>xx.xx.xx.xx:9871</value>
    </property>
    <property>
        <name>dfs.namenode.https-address.cluster.namenode2</name>
        <value>xx.xx.xx.xx:9871</value>
    </property>
    <!-- 定义hdfs的jn节点信息 -->
    <property>
        <name>dfs.namenode.shared.edits.dir</name>
        <value>qjournal://xx.xx.xx.xx:8485;xx.xx.xx.xx:8485;xx.xx.xx.xx:8485/cluster</value>
    </property>
    <property>
        <name>dfs.journalnode.edits.dir</name>
        <value>/data2/hadoop/journal</value>
    </property>
    <property>
        <name>dfs.client.failover.proxy.provider.cluster</name>
        <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    </property>
    <!-- 定义hdfs的NN的fencing信息,NN通过切主时会获取原主的信息,如果调用rpc原主降为standby失败,就会通过fencing ssh到对应的服务器杀死原主的NN进程 -->
    <property>
        <name>dfs.ha.fencing.methods</name>
        <value>sshfence(root:36000)&#xA;shell(/bin/true)
    </property>
    <property>
        <name>dfs.ha.fencing.ssh.private-key-files</name>
        <value>/root/.ssh/id_rsa</value>
    </property>
    <property>
        <name>dfs.ha.fencing.ssh.coNNect-timeout</name>
        <value>30000</value>
    </property>
    <property>
        <name>dfs.ha.automatic-failover.enabled</name>
        <value>true</value>
    </property>
    <property>
        <name>ha.failover-controller.cli-check.rpc-timeout.ms</name>
        <value>60000</value>
    </property>
    <property>
        <name>ipc.client.coNNect.timeout</name>
        <value>60000</value>
    </property>
    <!-- 定义hdfs的DN数据保存目录,可以配置多个路径,用","分割 -->
    <property>
        <name>dfs.datanode.data.dir</name>
        <value>/hdfsdata1/hadoop/dfs/data</value>
    </property>
    <property>
        <name>dfs.namenode.secondary.http-address</name>
        <value>xx.xx.xx.xx:9868</value>
    </property>
    <property>
        <name>dfs.namenode.secondary.https-address</name>
        <value>xx.xx.xx.xx:9869</value>
    </property>
    <property>
        <name>dfs.namenode.datanode.registration.ip-hostname-check</name>
        <value>false</value>
    </property>
    <property>
        <name>dfs.namenode.rpc-bind-host</name>
        <value>0.0.0.0</value>
    </property>
    <!-- 定义hdfs的DN内部的平衡、同步fimage的带宽限制 -->
    <property>
        <name>dfs.image.transfer.bandwidthPerSec</name>
        <value>52428800</value>
    </property>
    <property>
        <name>dfs.datanode.balance.bandwidthPerSec</name>
        <value>52428800</value>
    </property>
    <property>
        <name>dfs.datanode.balance.max.concurrent.moves</name>
        <value>50</value>
    </property>
    <!-- 定义hdfs的需要下线的机器列表 -->
    <property>
        <name>dfs.hosts.exclude</name>
        <value>/usr/local/services/hadoop-3.2.1/etc/hadoop/excludes_datanodes</value>
    </property>
    <property>
        <name>dfs.namenode.http-bind-host</name>
        <value>0.0.0.0</value>
    </property>
    <property>
        <name>dfs.namenode.https-bind-host</name>
        <value>0.0.0.0</value>
    </property>
    <!-- 定义hdfs的zk路径,通过在该路径下创建临时节点选主 -->
    <property>
        <name>ha.zookeeper.parent-znode</name>
        <value>/hadoop-hdfs-ha</value>
    </property>
    <property>
        <name>dfs.datanode.https.address</name>
        <value>0.0.0.0:9865</value>
    </property>
    <property>
        <name>dfs.block.access.token.enable</name>
        <value>true</value>
    </property>
    <!-- 定义hdfs的kerberos鉴权,如果设置鉴权可以不配置 -->
    <property>
        <name>dfs.namenode.keytab.file</name>
        <value>/usr/local/services/hadoop-3.2.1/etc/hadoop/hdfs.keytab</value>
    </property>
    <!-- 定义hdfs的kerberos用户,_HOST代表本机的hostname,因此没台DN的用户hdfs/[email protected]有差别,需要针对每个DN单独配置证书 -->
    <property>
        <name>dfs.namenode.kerberos.principal</name>
        <value>hdfs/[email protected]</value>
    </property>
    <property>
        <name>dfs.namenode.kerberos.https.principal</name>
        <value>HTTP/[email protected]</value>
    </property>
    <property>
        <name>dfs.namenode.kerberos.internal.spnego.principal</name>
        <value>HTTP/[email protected]</value>
    </property>
    <property>
        <name>dfs.datanode.data.dir.perm</name>
        <value>755</value>
    </property>
    <property>
        <name>dfs.datanode.address</name>
        <value>0.0.0.0:9866</value>
    </property>
    <property>
        <name>dfs.datanode.keytab.file</name>
        <value>/usr/local/services/hadoop-3.2.1/etc/hadoop/hdfs.keytab</value>
    </property>
    <property>
        <name>dfs.datanode.kerberos.principal</name>
        <value>hdfs/[email protected]</value>
    </property>
    <property>
        <name>dfs.datanode.kerberos.https.principal</name>
        <value>HTTP/[email protected]</value>
    </property>
    <property>
        <name>dfs.journalnode.keytab.file</name>
        <value>/usr/local/services/hadoop-3.2.1/etc/hadoop/hdfs.keytab</value>
    </property>
    <property>
        <name>dfs.journalnode.kerberos.principal</name>
        <value>hdfs/[email protected]</value>
    </property>
    <property>
        <name>dfs.journalnode.kerberos.internal.spnego.principal</name>
        <value>HTTP/[email protected]</value>
    </property>
    <property>
        <name>dfs.web.authentication.kerberos.principal</name>
        <value>HTTP/[email protected]</value>
    </property>
    <property>
        <name>dfs.web.authentication.kerberos.keytab</name>
        <value>/usr/local/services/hadoop-3.2.1/etc/hadoop/hdfs.keytab</value>
    </property>
    <property>
        <name>dfs.data.transfer.protection</name>
        <value>integrity</value>
    </property>
    <!-- 定义hdfs的DN的最大文件数量 -->
    <property>
        <name>dfs.namenode.fs-limits.max-directory-items</name>
        <value>3200000</value>
    </property>
</configuration>

core-site.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--
  Licensed ...
-->

<configuration>
    <!-- 定义hdfs的zk配置 -->
    <property>
        <name>ha.zookeeper.auth</name>
        <value>digest:zk_user:zk_passwd</value>
    </property>
    <property>
        <name>ha.zookeeper.acl</name>
        <value>digest:zk_user:Yg6OG5Tas/LEH5bd73noFMYG3xo=:rwcda</value>
    </property>
    <property>
        <name>hadoop.http.filter.initializers</name>
        <value>org.apache.hadoop.security.AuthenticationFilterInitializer</value>
    </property>
    <property>
        <name>hadoop.http.authentication.type</name>
        <value>kerberos</value>
    </property>
    <property>
        <name>hadoop.http.authentication.signature.secret.file</name>
        <value>/usr/local/services/hadoop-3.2.1/etc/hadoop/secret</value>
    </property>
    <property>
        <name>hadoop.http.authentication.simple.anonymous.allowed</name>
        <value>false</value>
    </property>
    <!-- 定义hdfs的kerberos认证信息 -->
    <property>
        <name>hadoop.security.authentication</name>
        <value>kerberos</value>
    </property>
    <property>
        <name>hadoop.security.authorization</name>
        <value>true</value>
    </property>
    <property>
        <name>hadoop.http.authentication.kerberos.principal</name>
        <value>HTTP/[email protected]</value>
    </property>
    <property>
        <name>hadoop.http.authentication.kerberos.keytab</name>
        <value>/usr/local/services/hadoop-3.2.1/etc/hadoop/hdfs.keytab</value>
    </property>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>file:/data2/hadoop/tmp</value>
    </property>
    <!-- 定义hdfs的namespace集群信息,和hdfs-site.xml定义一致 -->
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://cluster</value>
    </property>
    <property>
        <name>io.file.buffer.size</name>
        <value>131072</value>
    </property>
    <property>
        <name>hadoop.proxyuser.hadoop.hosts</name>
        <value>*</value>
    </property>
    <property>
        <name>hadoop.proxyuser.hadoop.groups</name>
        <value>*</value>
    </property>
    <property>
        <name>hadoop.proxyuser.mapred.hosts</name>
        <value>*</value>
    </property>
    <property>
        <name>hadoop.proxyuser.mapred.groups</name>
        <value>*</value>
    </property>
    <!-- 定义hdfs的zk访问地址 -->
    <property>
        <name>ha.zookeeper.quorum</name>
        <value>xx.xx.xx.xx:2181,xx.xx.xx.xx:2181,xx.xx.xx.xx:2181</value>
    </property>
    <property>
        <name>ha.zookeeper.session-timeout.ms</name>
        <value>30000</value>
    </property>
    <!-- 定义hdfs的机架topo配置 -->
    <property>
        <name>topology.script.file.name</name>
        <value>/usr/local/services/hadoop-3.2.1/etc/hadoop/hdfs_rack_info.py</value>
    </property>
    <!-- 定义hdfs的DN 汇报心跳配置 -->
    <property>
        <name>ipc.client.coNNect.max.retries</name>
        <value>10</value>
    </property>
    <property>
        <name>ipc.client.coNNect.retry.interval</name>
        <value>5000</value>
    </property>
    <property>
        <name>ipc.client.coNNect.max.retries.on.timeouts</name>
        <value>3</value>
    </property>
</configuration>

2.2 特殊优化配置

2.1.1 NN优化

对于NN来说,最大的问题还是响应客户端的rpc请求,由于只能单点响应客户端请求,因此单个NN的需要进行系统优化响应服务请求。

1, dfs.namenode.handler.count

参数:namenode的服务器线程数。

NameNode有一个工作线程池用来处理客户端的远程过程调用及集群守护进程的调用。处理程序数量越多意味着要更大的池来处理来自不同DataNode的并发心跳以及客户端并发的元数据操作。对于大集群或者有大量客户端的集群来说,通常需要增大参数dfs.namenode.handler.count的默认值10。设置该值的一般原则是将其设置为集群大小的自然对数乘以20,即20logN,N为集群大小

<property>
    <name>dfs.namenode.handler.count</name>
    <value>200</value>
</property>

2.1.2 DN优化

1, dfs.datanode.balance.bandwidthPerSec
参数: datanode 平衡带宽
描述:指定每个datanode可以利用每秒字节数来平衡目标的最大带宽。

<property>
    <name>dfs.datanode.balance.bandwidthPerSec</name>
    <value>52428800</value>
</property>

2,dfs.datanode.max.transfer.threads
参数:datanode 最大传输线程数
描述:指定用于传输数据进出DN的最大线程数。集群中如果不一致,会造成数据分布不均。

<property>
    <name>dfs.datanode.max.transfer.threads</name>
    <value>100</value>
</property>

3. hdfs常用命令

hdfs dfs
 
下面为显示的内容:

Usage: hadoop fs [generic options]
	[-appendToFile <localsrc> ... <dst>]
	[-cat [-ignoreCrc] <src> ...]
	[-checksum <src> ...]
	[-chgrp [-R] GROUP PATH...]
	[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
	[-chown [-R] [OWNER][:[GROUP]] PATH...]
	[-copyFromLocal [-f] [-p] [-l] <localsrc> ... <dst>]
	[-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
	[-count [-q] [-h] <path> ...]
	[-cp [-f] [-p | -p[topax]] <src> ... <dst>]
	[-createSnapshot <snapshotDir> [<snapshotName>]]
	[-deleteSnapshot <snapshotDir> <snapshotName>]
	[-df [-h] [<path> ...]]
	[-du [-s] [-h] <path> ...]
	[-expunge]
	[-find <path> ... <expression> ...]
	[-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
	[-getfacl [-R] <path>]
	[-getfattr [-R] {-n name | -d} [-e en] <path>]
	[-getmerge [-nl] <src> <localdst>]
	[-help [cmd ...]]
	[-ls [-d] [-h] [-R] [<path> ...]]
	[-mkdir [-p] <path> ...]
	[-moveFromLocal <localsrc> ... <dst>]
	[-moveToLocal <src> <localdst>]
	[-mv <src> ... <dst>]
	[-put [-f] [-p] [-l] <localsrc> ... <dst>]
	[-renameSnapshot <snapshotDir> <oldName> <newName>]
	[-rm [-f] [-r|-R] [-skipTrash] <src> ...]
	[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
	[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
	[-setfattr {-n name [-v value] | -x name} <path>]
	[-setrep [-R] [-w] <rep> <path> ...]
	[-stat [format] <path> ...]
	[-tail [-f] <file>]
	[-test -[defsz] <path>]
	[-text [-ignoreCrc] <src> ...]
	[-touchz <path> ...]
	[-truncate [-w] <length> <path> ...]
	[-usage [cmd ...]]

HDFS高可用架构涉及常用功能整理_第1张图片

3.1 常用基础命令

整理日常操作hdfs常用的命令,便于针对hdfs的文件操作

1, –ls:查看指定目录下内容
eg:hadoop fs –ls /user/wangwu

2, –cat:显示文件内容
eg:hadoop fs -cat /user/wangwu/data.txt

3, –put:将本地文件存储至hadoop
eg:hadoop fs –put /home/t/file.txt  /user/t

4, –put:将本地文件夹存储至hadoop
eg:hadoop fs –put /home/t/dir_name /user/t

5, -get:将hadoop上某个文件down至本地已有目录下
eg:hadoop fs –get /user/t/ok.txt /home/t

6, –rm:删除hadoop上指定文件或文件夹
eg:hadoop fs –rm /user/t/ok.txt

7, 删除hadoop上指定文件夹(包含子目录等)
eg:hadoop fs –rm /user/t

8, –mkdir:在hadoop指定目录内创建新目录
eg:hadoop fs –mkdir /user/t

9, -touchz:在hadoop指定目录下新建一个空文件
eg:hadoop  fs  -touchz  /user/new.txt

10, –mv:将hadoop上某个文件重命名
eg:hadoop  fs  –mv  /user/test.txt  /user/ok.txt

11, -setrep:设置HDFS中文件的副本数量
eg:hadoop fs -setrep 10 /tmp/tt/student.txt

12, 将正在运行的hadoop作业kill掉
eg:hadoop job –kill  [job-id]

13, -help:输出这个命令参数
eg:hadoop fs -help rm

14, -moveFromLocal:从本地剪切粘贴到HDFS
eg:hadoop fs  -moveFromLocal  ./stuDNet.txt  /tmp/test/

15, -appendToFile:追加一个文件到已经存在的文件末尾
eg:hadoop fs -appendToFile liubei.txt /sanguo/shuguo/zhangsan.txt

16, -chgrp , -chmod, -chown:Linux文件系统中的用法一样,修改文件所属权限
eg:hadoop fs  -chmod  666  /sanguo/shuguo/zhangsan.txt

17, -copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去
eg:hadoop fs -copyFromLocal README.txt /

18, -copyToLocal:从HDFS拷贝到本地
eg:hadoop fs -copyToLocal /sanguo/shuguo/zhangsan.txt ./

19, -cp :从HDFS的一个路径拷贝到HDFS的另一个路径
eg:hadoop fs -cp /sanguo/shuguo/zhangsan.txt /zhuge.txt

20, -tail:显示一个文件的末尾
eg:hadoop fs -tail /sanguo/shuguo/zhangsan.txt

21, -rmdir:删除空目录
eg:hadoop fs -rmdir /test

22, -du:统计文件夹的大小信息
eg:hadoop fs -du  -h /user/itcast/test
	1.3 K  /user/itcast/test/README.txt
	15     /user/itcast/test/jinlian.txt
	1.4 K  /user/itcast/test/nihao.txt

3.2 常用运维命令

用于日常运维命令,便于进行服务运维,提升系统稳定性。

1, 设置文件副本数量
如果hdfs的磁盘使用率过高,可以临时调整大文件副本,注意如果调整的副本数量过小,可能会面临数据可靠性风险,慎重!

hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt 

2, 检查hdfs的是否有坏块或者副本缺失

hdfs fsck / -list-corruptfileblocks

3, 检查hdfs的文件是否有坏块或者副本缺失

hdfs fsck / -files  -blocks -locations
hdfs fsck /user/root/hello/yarn-demo-1.0-SNAPSHOT-jar-with-dependencies.jar -files  -blocks -locations

也可以通过该命令查看对应的文件的block所在的位置
HDFS高可用架构涉及常用功能整理_第2张图片
3, 执行hdfs执行格式化
执行格式化操作,会清理当前集群的所有数据,重新创建一个新的集群,一般只在新部署hdfs集群时使用,一定要慎重!!!

# 格式化zk,会在zk上创建临时目录,用于选主
hdfs zkfc -formatZK

# 格式化整个hdfs系统
hdfs namenode -format

4, 同步active的元数据
完成active部署后,standby需要跟active同步元数据,才能达成一致,该操作需要再standby节点执行,否则可能会造成元数据丢失.

hdfs namenode -bootstrapStandby

5, hdfs安全模式
当hdfs集群的数据副本丢失过多,或者集群存活的DN数量到达阈值时,就会主动进入安全模式,集群只读,需要人工修复。

# 检查是否进入安全模式
hdfs dfsadmin -safemode get

# 如何离开安全模式
hdfs dfsadmin -safemode leave

6,强行切换NN

# 强行指定某个节点为active
hdfs haadmin -transitionToActive -forcemanual namenode1

# 强行指定某个节点为standby
hdfs haadmin -transitionToStandby -forcemanual namenode2

7, 获取nn的集群节点状态

# 获取所有的nn节点状态
hdfs haadmin -getAllServiceState

#获取单个nn的节点状态
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2

5, 刷新节点信息
通常使用于下线节点

# 配置完exclude后,通过手动刷新配置生效
hdfs dfsadmin -refreshNodes

4. 事务性

4.1 数据写流程

hdfs的数据写流程,整体流程如下。
HDFS高可用架构涉及常用功能整理_第3张图片
客户端写入的总体流程如下

  1. 客户端向NameNode发出写文件请求。
  2. 检查是否已存在文件、检查权限。若通过检查,直接先将操作写入EditLog,并返回输出流对象。(注:WAL,write ahead log,先写Log,再写内存,因为EditLog记录的是最新的HDFS客户端执行所有的写操作。如果后续真实写操作失败了,由于在真实写操作之前,操作就被写入EditLog中了,故EditLog中仍会有记录,我们不用担心后续client读不到相应的数据块,因为在第5步中DataNode收到块后会有一返回确认信息,若没写成功,发送端没收到确认信息,会一直重试,直到成功)
  3. client端按block切分文件(通常一个block是128M)
  4. client将NameNode返回的分配的可写的DataNode列表和Data数据一同发送给最近的第一个DataNode节点,此后client端和NameNode分配的多个DataNode构成pipeline管道,client端向输出流对象中写数据。client每向第一个DN写入一个packet,这个packet便会直接在pipeline里传给第二个、第三个…DataNode(满足一个packet就会发送数据,而不是一个block)
  5. 在pipeline反方向上,逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点将ack发送给client。(注:并不是每写完一个packet后就返回确认信息,个人觉得因为packet中的每个chunk都携带校验信息,没必要每写一个就汇报一下,这样效率太慢。正确的做法是写完一个block块后,对校验信息进行汇总分析,就能得出是否有块写错的情况发生
  6. 写完数据,关闭输输出流。
  7. 发送完成信号给NameNode。

这里面有几个关键概念,需要进行整理

  1. block
    这个大家应该知道,文件上传前需要分块,这个块就是block,一般为128MB(可以改,但是不推荐)。client完成1个block写入后,所有的DN返回后,进行一次数据确认。
  2. packet
    packet是第二大的单位,它是client端向DataNode,或DataNode的PipLine之间传数据的基本单位,默认64KB。当客户端的输出流(outputstream)满足1个packet后,就会开始进行数据发送给DN。
  3. chunk
    chunk是最小的单位,它是client向DataNode,或DataNode的PipLine之间进行数据校验的基本单位,默认512Byte,因为用作校验,故每个chunk需要带有4Byte的校验位。所以实际每个chunk写入packet的大小为516Byte。由此可见真实数据与校验值数据的比值约为128 : 1(即64*1024 / 512)

客户端在给DN发送数据时,

  1. 以chunk单位进行数据校验,完成chunk(516Bytes)数据校验后,写入到packet(64KB)
  2. 当64*1024 / 512=128个chunk写入到packet后,packet满足要求,并输出到outputstream发送给DN
  3. 多个DN之间形成pipeline,并以packet作为基础单元接受数据,DN以3->2->1的顺序反向确认消息返回ack
  4. 当1个block(128MB/64KB=2048个packet)写入,并所有的DN返回ack后,统一返回给client,确认1个block数据写完成

4.2 数据读流程

HDFS高可用架构涉及常用功能整理_第4张图片
读相对于写,简单一些

读详细步骤:

  1. 客户端访问NameNode,查询元数据信息,获得这个文件的数据块位置列表,返回输入流对象。
  2. 客户端就近挑选一台datanode服务器,请求建立输入流 。
  3. DataNode向输入流中中写数据,以packet为单位来校验。

5. 疑问和思考

5.2. hdfs集群初始化部署流程?

hdfs namenode -format
hadoop-daemon.sh start namenode
hdfs namenode -bootstrapStandby
hdfs zkfc -formatZK
hadoop-daemon.sh start zkfc
hadoop-daemon.sh start datanode
启动zk
启动jn
格式化hdfs
启动第一个节点NN
第二个节点NN同步元数据
格式化zkfc
启动zkfc
启动DN
结束

5.4. hdfs是如何选择DN进行数据读写的?

Hadoop 默认的副本数为3,并且在机架的存放上也有一定的策略。优先按照如下策略选择合适的DN节点:
(1)第 1 个副本存放在 HDFS 客户端所在的节点上。
(2)第 2 个副本存放在与第1个副本不同的机架上,并且是随机选择的节点。
(3)第 3 个副本存放在与第2个副本相同的机架上,并且是不同的节点。

5.3. hdfs在读写过程中如果出现异常该如何处理?

1,如果DN收到一半 DN挂了了的处理流程

client发送数据以block作为基础单元。

  1. 假如一个packet在发送后,在收到DN返回的ack确认消息时超时,传输中止,将此时所有DN中正在传输的packet剔除,并进行回滚。
  2. 重新选择DN节点(剔除坏的DN节点,包括里面的所有信息)内部重新建立pipeline建立完成之后,继续传输(客户端不需要重新跟NN交互获取新的DN列表)
  3. 只要有一个DN节点收到了数据,DN上报NN已经收完此块,NN就认为当前block已经传输成功!
  4. NN会自动维护副本数!

2,读取文件时DN挂了
DataNode 挂了只需要失败转移到其他副本所在的 DataNode 继续读取

3.读取到的文件数据损坏

  1. 读取到的文件数据块若校验失败可认定为损坏,依然可以转移到读取其他完好的副本
  2. 并向 NameNode 汇报该文件 block 损坏,后续处理由 NameNode 通知 DataNode 删除损坏文件 block,并根据完好的副本来复制一份新的文件 block 副本。

5.4 hdfs不擅长处理哪些场景?

hdfs擅长处理大数据规模场景下的数据处理场景,常规的接口响应是秒级(几秒到十几秒),数据处理、清晰等场景下,相对于数据的处理和聚合运算,这些时间相对客户忽略不计。有些场景不适用于hdfs集群,总结如下

  • http请求加载图片等: http请求的接口响应是毫秒级别,hdfs是秒级,相差比较大,响应时间相对较长,事实上很多http请求都配置了超时时间(如设置为3s),会导致图片经常加载不成功。
  • 小文件、大量请求: 小文件会占用NN的大量内存,同时由于NN只有1个节点在响应相关的接口,因此NN很容易成为瓶颈。如果NN的内存heap配置过小,容易oom;如果配置过大,会导致长GC,同时节点异常时的恢复时间比较长;

6. 参考文档

  • 联邦-模式搭建指南
  • hfds保证数据一致性
  • HDFS读写流程以及异常处理

你可能感兴趣的:(大数据,Hdfs,hdfs,hadoop,大数据)