HDFS是大数分布式存储
HDFS原理
数据存储发展
单块硬盘
单机时代:早期互联网刚发展的时候,各种硬件资源相对缺乏,成本较高。我们将数据写入到磁盘中,一块不够再来一块,如果把数据一块磁盘一块磁盘的写,有如下问题:
- 单块磁盘写,磁盘读写速度上不去,读写慢;
- 数据写入单块磁盘,一旦磁盘故障导致数据丢失;
在这种情况下,RAID技术就应运而生了。
RAID
RAID ( Redundant Array of Independent Disks )即独立磁盘冗余阵列,简称为「磁盘阵列」,其实就是用多个独立的磁盘组成在一起形成一个大的磁盘系统,从而实现比单块磁盘更好的存储性能和更高的可靠性。
根据 RAID 算法的不同,RAID 有很多种。下面主要介绍 RAID0、RAID1、RAID10。
RAID0
RAID0 是一种非常简单的的方式,它将多块磁盘组合在一起形成一个大容量的存储。
假设阵列中有N块磁盘,当写数据时,会将数据分为N份,然后分别写入N块 磁盘中。因此,RAID0将提供非常优秀的读写性能。
优点:
- 并行写入读取快,空间利用率高。
- 如果你要读取/写入 2G 的数据,在普通硬盘上,要以单盘的速度读取/写入 2G 的数据。
- 如果在 4 盘 RAID0 阵列中,每个盘只需读取/写入 500MB 的数据,四个盘可以并行读取/写入,因此理论的读写速度将是单块硬盘的4倍。
缺点:
- 只要阵列中有一块硬盘坏掉,由于这块硬盘保存着所有数据(每个文件)的某一部分,因此所有数据都将无法读取,整个阵列中的数据将宣告报废。
RAID1
RAID1 是磁盘阵列中单位成本最高的一种方式。因为它的原理是在往磁盘写数据的时候,将同一份数据无差别的写两份到磁盘,分别写到工作磁盘和镜像磁盘,那么它的实际空间使用率只有50%了,两块磁盘当做一块用,这是一种比较昂贵的方案。
优点:
- 数据写入两个磁盘,通过冗余存储实现容错。
缺点:
- 空间利用率低,读写速度慢。
RAID10
RAID10其实就是RAID1与RAID0的一个合体。
先将磁盘阵列组成 RAID1, 再将多个RAID1 组成 RAID0。
读写数据时,可以将数据分N块,并行写入,而且每块数据都有备份。
这样既可以通过冗余存储容错,也可以提高读写的效率。
HDFS3.0
HDFS是Hadoop Distribute File System 的简称,也就是Hadoop的一个分布式文件系统,用来解决存储问题。
HDFS 可以使用低成本的硬件来搭建。
HDFS 可以对海量的数据进行分布式存储。
HDFS 实现软件RAID10。
namenode
名称节点,用来存储元数据。接收客户端的读写请求。
namenode元数据保存到了内存中和磁盘中,保存到内存中是为了快速查询数据信息,保存到磁盘中是为了数据安全。
元数据包括:
- 文件名称
- 文件大小
- 文件权限
- 文件所有者
- 文件切了几块
- 副本数量
- 每一个block数据块存到了哪一个datanode上
- 等等…

3.0中一般有一个active状态的namenode,有两个standby状态的namenode,其中,active状态的NameNode负责所有的客户端操作,standby状态的NameNode处于从属地位,维护着数据状态,随时准备切换。
一个数据块的元数据信息占用namenode内存存储空间为150字节。块越小读取的速度就越快,但是整体占用namenode的空间就越大。
配置方式如下:
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>
<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.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
datanode
数据节点
负责存储client发来的数据块block;执行数据块的读写操作。
- 数据是切块进行分布式存储的,而每个block块都需要存储在datanode上。
- namenode的其中一个作用是存元数据,另外一个作用就是用来管理datanode
- 每隔3sdatanode就会想namenode汇报自身情况,如果超过10min中没有收到datanode的心跳信息,namenode就会认为此datanode丢失了,将其身上的数据拷贝到其他服务器中。
- datanode在启动成功之后会接收namenode同步过来的clusterid,之后的通信过程中,datanode都会带着clusterid去和namenode通信,所以切记不要频繁的格式化namenode,因为每一次格式化namenode都会重新产生新的clusterid,造成namenode和datanode起不来的情况出现。

journalnode
用于数据同步
namenode元数据同步
Namenode 除了内存存储元数据外,磁盘也存储,主要维护两个文件,一个是fsimage,一个是 editlog
- editlog(简称edits)是操作日志文件,记录了NameNode所要执行的操作
- fsimage是元数据镜像文件。存储某NameNode元数据信息,并不是实时同步内存中的数据。
一般而言,fsimage中的元数据是落后于内存中的元数据的

当有写请求时,NameNode会首先写该操作先写到磁盘上的edits文件中,当edits文件写成功后才会修改NameNode内存的元数据,内存修改成功后向客户端返回成功信号。
请求操作记录除了会写入到activenamenode中的edits文件中,还会给journalnode中写入edits文件,然后journalnode会将本地的edits文件中的请求操作,在standbynamenode中进行同步。这样就可以进行元数据的同步了。
随着edits记录的操作越来越多,内存中的元数据越来越多,这样的话内存中的元数据存在风险,一旦宕机,内存数据丢失,所以为了安全起见,需要将内存中的元数据,周期性的写入到fsimage文件中。如果数据出错可以通过 fsimage + edits 恢复。
因为ActiveNamenode相对来说比较忙,所以选择相对轻松的StandbyNamenode来做元数据同步这个事情
namenode 元数据合并
- 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。

周期可以自行配置
<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>
ZKFC
三台namenode已经全部启动成功但全是standby。
#手动切换nn1的节点是主节点
hdfs haadmin -transitionToActive nn1
#查看节点状态
hdfs haadmin -getServiceState nn1
如果每次都是程序员自己切换的话,那也太不灵活了,所以需要引入一个组件,就是zkfc
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; 当ActiveNameNode对应的HealthMonitor监控到NameNode异常时,会告知ZKFC,ZKFC通过ActiveStandbyElector删除所创建的临时节点
- 此时处于Standby的NameNode会监控到这个消息它首先会通过判断节点是否存在来确认情况,如果是正常关闭的,则发起主备选举,成功创建临时节点,并且将NameNode的状态切换为Active

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>
HDFS 常用命令
标准写法
本地文件file:
hdfs路径:hdfs://ns1
ls
hadoop fs -ls hdfs://ns1/
简写
hadoop fs -ls /
-h
文件大小显示为最大单位,更加人性化
hadoop fs -ls -h /
-R
递归显示
hadoop fs -ls -R /
put
标准写法
put 左面:是本地,右面是hdfs集群
hadoop fs -put ~/demo.txt hdfs://ns1/
简写
右面默认找hdfs
hadoop fs -put ~/demo.txt /
上传时重名
hadoop fs -put ~/demo.txt /demo1.txt
上传多个文件
上传多个文件的时候无法改名,最后只能是一个目录
hadoop fs -put a.txt b.txt /
上传目录
hadoop fs -put ceshi /
-f
覆盖上传
hadoop fs -put -f demo.txt /
put 原理(hdfs 写流程)

cat
读取文件,如果文件太大,不要用cat读取文件
hadoop fs -cat /data/demo.log
cat原理(hdfs 读流程)

get
下载hdfs文件或目录到本地目录
hadoop fs -get /demo.txt ./
下载hdfs文件到本地目录并重命名
hadoop fs -get /demo.txt ./nihao.txt
cp
拷贝文件/目录
上传本地文件使用file:开头,这就相当于put
hadoop fs -cp file:/home/hadoop/word.txt /
从hdfs进行拷贝
hadoop fs -cp /demo.txt /ceshi
mv
剪切文件
hadoop fs -mv /b.txt /ceshi
rm
删除文件/目录
执行-rm 命令后,默认是把文件移动到 user/hadoop/.Trash/Current 下,会根据配置文件配置的清理周期定期清理。
hadoop fs -rm /demo.txt
匹配模式删除所有文件
hadoop fs -rm /ceshi/*.log
删除目录(空目录)
hadoop fs -rmdir /ceshi
强制删除,并且递归删除文件夹中的内容
hadoop fs -rmr /ceshi
删除之后不放到回收站
hadoop fs -rm -skipTrash /a.txt
touchz
创建空文件
hadoop fs - touchz /aa.txt
mkdir
创建目录,可以同时创建多个目录
hadoop fs -mkdir /tmp1 /tmp2
同时创建父级目录
hadoop fs -mkdir -p /dir1/dir2/dir3
tail
读取文件尾部
查看尾部1K字节
hadoop fs -tail /demo1.txt
appendToFile
追加写入文件
将new.txt的内容追加到node.txt中
hadoop fs -appendToFile new.txt /note.txt
du
获取逻辑空间文件/目录大小
显示HDFS根目录中各文件和文件夹大小
hadoop fs -du /
以最大单位显示HDFS根目录中各文件和文件夹大小
hadoop fs -du -h /
仅显示HDFS根目录大小。即各文件和文件夹大小之和
hadoop fs -du -s -h /
setrep
改变文件副本数
-R
递归改变目录下所有文件的副本数。
-w
等待副本数调整完毕后返回。可理解为加了这个参数就是阻塞式的了。
hadoop fs -setrep -R -w 2 /demo.txt
count
获取HDFS目录的物理空间信息
- 值1 代表目录个数
- 值2 代表文件个数
- 值3 是总大小
hadoop fs -count /
HDFS 高级命令
dfsadmin
-report
查看文件系统的基本信息和统计信息
hadoop dfsadmin -report
-safemode
安全模式命令。
安全模式是NameNode的一种状态,在这种状态下,NameNode不接受对元数据的更改(只读);不复制或删除块。NameNode在启动时自动进入安全模式,当配置块的最小百分数满足最小副本数的条件时,会自动离开安全模式。enter是进入,leave是离开 。
在安全模式情况下不允许任何hdfs的修改操作的,读是可以的
进入安全模式
hadoop dfsadmin -safemode enter
离开安全模式
hadoop dfsadmin -safemode leave
获取安全模式信息
hadoop dfsadmin -safemode get
-rollEdits
手动滚动edits文件
hadoop dfsadmin -rollEdits
fsimage和edits文件详解
两个文件存放的目录/data/namenode/current
VERSION
VERSION是java属性文件,内容大致如下:
- namespaceID是文件系统唯一标识符
- clusterID是系统生成或手动指定的集群ID
- cTime表示Namenode存储的创建时间
- storageType表示这个文件存储的是什么进程的数据结构信息
- blockpoolID表示每一个namenode对应的块池id,这个id包括了其对应的Namenode节点的ip地址。
- layoutVersion表示HDFS永久性数据结构的版本信息,只要数据结构变更,版本号也要递减
edits_*文件
edits文件中存放的是客户端执行的所有更新命名空间的操作。
hdfs oev 解析操作日志文件并且输入到相应的目录中 -i 输入 -o 输出 -p 默认就是xml
hdfs oev -i edits_0000000000000000138-0000000000000000145 -o ~/edits.txt
查看edits文件
vim ~/edits.txt
seen_txid文件
这个文件中保存了一个事务id,这个事务id并不是Namenode内存中最新的事务id。这个文件的作用在于Namenode启动时,利用这个文件判断是否有edits文件丢失,Namenode启动时会检查seen_txid并确保内存中加载的事务id至少超过seen_txid,否则Namenode将终止启动操作。
fsimage_*文件
将fsimage数据导出到文本中
hdfs oiv -i fsimage_0000000000000000024 -o ~/fs.xml -p xml
fs.xml里面有
- version:version描述的一些版本信息
- NameSection:描述的是命名空间的一些信息
- ErasureCodingSection:纠删码
- INodeSection:INodeSection 由一段一段inode组成,是image中内容最大部分,除了上述的几个片段,image中剩下的内容全部都是inode。
手动合并元数据
先进入安全模式
hadoop dfsadmin -safemode enter
手动触发合并元数据
hadoop dfsadmin -saveNamespace
fsimage_*.md5文件
md5校验文件,用于确保fsimage文件的正确性,可以作用于磁盘异常导致文件损坏的情况。
扩容datanode节点
当磁盘容量不够的时候需要对集群进行动态扩容,动态增加一个或者多个服务器。
- 连接新的服务器
- 创建hadoop用户并设置密码
- useradd hadoop
- passwd hadoop
- 安装jdk
- rpm -ivh /public/software/java/jdk-8u144-linux-x64.rpm
- 配置s4的主机名
- vim /etc/hostname
- 将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
- 将环境变量文件也拷贝一份
- scp -r root@s3:/etc/profile /etc/
- source /etc/profile
- 修改/data目录所有者和属组
- chown hadoop:hadoop /data
- 修改 hosts文件
- 修改其他服务器,添加s4节点的映射
- 配置s4和其他服务器免密码登录
- scp -r hadoop@s3:/home/hadoop/.ssh /home/hadoop/
- 测试免密码登录是否正常
- 给workers文件添加s4
- echo s4 >> /usr/local/hadoop/etc/hadoop/workers
- 在新增的s4节点启动datanode
datanode下线
需要修改hdfs-site.xml,将要删除的节点配置在文件中,然后配置文件的路径
<property>
<name>dfs.hosts.exclude</name>
<value>/usr/local/hadoop/etc/hadoop/excludes</value>
</property>
将配置文件分发到各个机器节点中
在nn1节点输入
hadoop dfsadmin -refreshNodes
s4上面的数据迁移到了其他节点上,此时s4下线成功
后续我们删除 workers中的s4节点,那么下次就不会启动它了
scp_all.sh /usr/local/hadoop/etc/hadoop/workers /usr/local/hadoop/etc/hadoop/
hdfs数据负载均衡
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
修改每个节点空间大小在hdfs-site.xml
<property>
<name>dfs.datanode.du.reserved</name>
<value>80484251153203</value>
<description>每个存储卷保留用作其他用途的磁盘大小,不给hdfs用的大小</description>
</property>
机架感知策略
比如说有三个副本,如果都发放在同一个机架,那么这个机架宕机,导致数据丢失。
所以加入机架感知策略。
在hadoop2.7之后,如果开启机架感知策略,那么:
- 第一个副本:如果是集群内部上传,哪个服务器上传的,就将第一个副本放到哪里;
- 第二个副本:放到和第一个副本相同的机架,不同的节点上;
- 第三个副本:放到和第二个副本不同的机架,找一台容量比较充足的进行存放。
我们这里说的机架式逻辑机架而不是物理机架,但是在真正配置的时候,一般逻辑机架,要和物理机架相对应。
默认情况下,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 = {
"sl1":"lmk_rack1",
"sl2":"lmk_rack1",
"sl3":"lmk_rack2",
"192.168.149.53":"lmk_rack1",
"192.168.149.54":"lmk_rack1",
"192.168.149.55":"lmk_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之后查看
HDFS 1.0
Namenode是主 Datanode是从
NameNode是一个进程,在某一个机器(主节点)上,维护内存
内存里有2份重要的数据(元数据-通过Datanode心跳保证):
(1)文件名->block数据块的映射关系(mapping关系)
(2)block数据块->datanode节点地址映射关系
配合着:去访问响应的Datanode
(1)block数据块->真实数据存放的本地地址
NameNode 不存储数据,只存储数据的位置

数据块的副本:默认3个副本
Hadoop集群不适合存储大量的小文件
(1)资源浪费 (每个block64M,如果都存不满,就非常浪费)
(2)Namenode资源有限(文件越多,需要存储的映射就越多)
(3)集群里存在大量的压缩的小文件,启动mapreduce时候,会产生大量的map进程
(4)集群里存在大文件,启动mapreduce时候,并发能力不够,导致MR任务执行慢
1.0里只有一个 NN(Namenode),当时zookeeper没有
SecondaryNameNode:其实并不是Namenode的备份
SNN存在意义:备份、数据恢复

数据完整性校验:检测数据是否损坏
用什么方法:crc32算法产生校验和(hash值)
存在几种校验逻辑?
(1)Client写校验和,Datanode来校验
(2)Datanode存在后台进程(DataBlockScanner):定期
