本文继续介绍HDFS的命令行使用、基准测试、读取与写入过程以及元数据辅助管理。
HDFS的命令行使用
基本命令
基本命令和Linux下的命令使用方式基本相同。
ls
格式:hdfs dfs -ls URI作用:类似于Linux的ls命令,显示文件列表
hdfs dfs -ls /
浏览器输入主机号:50070,查看文件系统
mkdir
格式 :hdfs dfs -mkdir -p /path作用:以中的URI作为参数,创建目录。使用-p参数可以递归创建目录
hdfs dfs -mkdir hellohdfs dfs -mkdir -p /aaa/aaa1/aaa2
lsr
格式:hdfs dfs -ls -R /path作用:在整个目录下递归执行ls
hdfs dfs -ls -R /
put
格式:hdfs dfs -put ... 作用:将单个的源文件src或者多个源文件srcs从本地文件系统拷贝到目标文件系统中(对应的路径),也可以从标准输入中读取输入,写入目标文件系统中。
touch a.txtvim a.txthdfs dfs -put a.txt /hello
在C:\Windows\System32\drivers\etc目录下的host文件添加域名映射
就可以点击Download下载文件了。
moveFromLocal
格式:hdfs dfs -moveFromLocal 作用:和put命令类似,但是源文件localsrc拷贝之后自身被删除,相当于剪切
hdfs dfs -moveFromLocal a.txt /dir1
get
格式:hdfs dfs -get [-ignorecrc ] [-crc] 作用:将文件拷贝到本地文件系统。CRC校验失败的文件通过-ignorecrc选项拷贝。文件和CRC校验和可以通过-CRC选项拷贝
hdfs dfs -get /dir1/a.txt ./
mv
格式:hdfs dfs -mv URI 作用:将hdfs上的文件从原路径移动到目标路径(移动之后文件删除),不能跨文件系统
hdfs dfs -mv /dir1/a.txt /dir2
rm
格式:hdfs dfs -rm [-r] 【-skipTrash】 URI 【URI 。。。】作用:删除参数指定的文件,参数可以有多个,只删除文件和非空目录。如果指定-skipTrash选项,那么在回收站可用的情况下,该选项将跳过回收站而直接删除文件;否则,在回收站可用时,在HDFS Shell 中执行此命令,会将文件暂时放到回收站中。
hdfs dfs -rm /dir2/a.txt
这种方式会默认新建一个user目录,里面有回收站
hdfs dfs -rm -r -skipTrash /aaa/aaa1/aaa2
这种方式直接删除!
cp
格式:hdfs dfs -cp URI [URI ...] 作用:将文件拷贝到目标路径中。如果为目录,可以将多个文件拷贝到该目录下。-f:选项将覆盖目标,如果它已经存在。-p:选项将保留文件属性(时间戳、所有权、许可、ACL、XAttr),属于深度拷贝。
hdfs dfs -cp /hello/a.txt /dir1
cp与put不同,put可以在本地和文件系统间拷贝,而cp是在文件系统内部进行文件拷贝。
将dir1中的b.txt拷贝到dir2中,并重命名为c.txt
hdfs dfs -cp /dir1/b.txt /dir2/c.txt
cat
格式:hdfs dfs -cat URI [uri ...]作用:将参数所指示的文件内容输出到stdout
hdfs dfs -cat /dir1/b.txt
chmod
格式:hdfs dfs -chmod [-R] URI[URI ...]作用:改变文件权限。如果使用-R 选项,则对整个目录有效递归执行。使用这一命令的用户必须是文件的所属用户,或者超级用户。
hdfs dfs -chmod 777 /dir1hdfs dfs -chmod -R 777 /aaa
chown
格式:hdfs dfs -chown [-R] URI[URI ...]作用:改变文件的所属用户和用户组。如果使用-R 选项,则对整个目录有效递归执行。使用这一命令的用户必须是文件的所属用户,或者超级用户。
hdfs dfs -chown -R hadoop:hadoop /dir2/c.txt
appendToFile
格式: hdfs dfs -appendToFile ... 作用: 追加一个或者多个文件到hdfs指定文件中.也可以从命令行读取输入。
hdfs dfs -appendToFile a.xml b.xml /big.xml
高级命令
文件配额设置命令
恶心的某百度网盘不仅会限制用户的下载速度,还会限制用户的存储容量。同样,在多人共用HDFS的环境下,也会对HDFS进行配额设置。文件配置设置非常重要,如果没有配额管理,很容易把所有的空间用完造成别人无法存取。Hdfs的配额设定是针对目录而不是针对账号,可以让每个账号仅操作某一个目录,然后对目录设置配置。hdfs文件的限额配置允许用户以文件个数或者文件大小来限制在某个目录下上传的文件数量或者文件内容总量。
使用命令查看文件夹的配额设置信息
hdfs dfs -count -q -h /user/root/dir1 #查看配额信息
由于没有进行配置,第一个none表示数量限额为空,inf表示余量为无穷,第二个none表示大小限额。
hdfs dfs -mkdir -p /user/root/dir1 #创建hdfs文件夹hdfs dfsadmin -setQuota 2 dir1 # 给该文件夹下面设置最多上传两个文件,发现只能上传一个文件hdfs dfsadmin -clrQuota /user/root/dir1 # 清除文件数量限制
余量为1是因为当前目录本身也占一个数量。
上传第二个文件会报错
清除文件数量限制,再次上传成功!
在设置空间配额时,设置的空间至少是block_size * 3的大小。
hdfs dfsadmin -setSpaceQuota 4k /user/root/dir1 # 限制空间大小4KBhdfs dfs -put /root/a.txt /user/root/dir1dd if=/dev/zero of=1.txt bs=129M count=1 #生成129M的文件hdfs dfsadmin -clrSpaceQuota /user/root/dir1
给文件夹dir2设置空间限额4k再上传文件a.xml会报错!
默认副本数是3,a.xml比较小,分成一个Block,一个Block默认大小128M,128x3=384M,因此最少需要限额384M!
清除限额设置重新设置为384M,再次上传文件成功!
如果某个文件129M,则划分为2个Block,每个Block3个副本,所以共需要128Mx6=768M,因此需要限额768M及以上。
设置767M容量限制并上传129M的1.txt会报错并提示需要最少768M的空间限额。
清除设置并重新设置为768M,再次上传129M的1.txt,成功!
安全模式操作命令
安全模式是Hadoop的一种保护机制,用于保证集群中的数据块的安全性。
当集群启动的时候,会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性。
假设设置的副本数是3,那么在datanode上就应该有3个副本存在,假设只存在2个副本,那么比例就是2/3=0.666。HDFS默认的副本率0.999,副本率0.666明显小于0.999,因此系统会自动的复制副本到其他dataNode,使得副本率不小于0.999。
如果系统中有5个副本,超过设定的3个副本,那么系统也会删除多于的2个副本。在安全模式状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。当整个系统达到安全标准时,HDFS自动离开安全模式。
hdfs dfsadmin -safemode get #查看安全模式状态hdfs dfsadmin -safemode enter #进入安全模式hdfs dfsadmin -safemode leave #离开安全模式
在浏览器首页可以看到安全模式的状态
在命令行下查看
开启安全模式
关闭安全模式
基准测试
集群搭建完毕一般要先进行压力测试集群的读取和写入速度。
进入mapreduce目录
cd /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/
hadoop jar hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -write -nrFiles 10 -fileSize 10MBhadoop jar hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -read -nrFiles 10 -fileSize 10MB
可以在虚拟机中看测试报告,当前目录下会生成TestDFSIO_results.log
写入速度测试同样操作
也可以通过以下命令查看测试结果
hdfs dfs -text /benchmarks/TestDFSIO/io_read/part-00000hdfs dfs -text /benchmarks/TestDFSIO/io_write/part-00000
浏览器中同样可以看到测试报告
通过以下命令清除测试数据
hadoop jar hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -clean
读取与写入过程
写入过程
1.Client发起文件上传请求, 通过RPC(远程调用)与NameNode建立通讯,NameNode检查目标文件是否已存在, 父目录是否存在, 返回是否可以上传的回复信息。
2.Client 请求第一个Block1该传输到哪些 DataNode 服务器上。
3.NameNode根据配置文件中指定的备份数量及机架感知原理进行文件分配,返回可用的DataNode的地址如: {dn1,dn2,dn3}。
4.Client请求3台DataNode中的一台dn1上传数据,本质上是一个RPC调用,建立pipeline,dn1收到请求会继续调用dn2,然后dn2调用dn3,将整个 pipeline 建立完成,后逐级返回client。
5. Client 开始往dn1上传Block1,数据被分割成一个个packet(默认64K)数据包在 pipeline 上依次传输, dn1 收到一个packet 就会传给dn2, dn2传给dn3。
6. 在 pipeline 反方向上, 逐个发送ack(命令正确应答), 最终由 pipeline 中第一个 DataNode 节点 A 将 pipelineack 发送给 Client。
7. 当Block传输完成之后, Client 再次请求NameNode上传第二个 Block2。
读取过程
1.Client向NameNode发起RPC请求,来确定请求文件block所在的位置;
2.NameNode会视情况返回文件的部分或者全部block列表,对于每个block,NameNode都会返回含有该block副本的DataNode地址。
这些返回的 DN 地址,会按照集群拓扑结构得出 DataNode 与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离Client 近的排靠前;心跳机制中超时汇报的DN状态为STALE的排靠后。
3.Client 选取排序靠前的 DataNode来读取block。
4.底层上本质是建立Socket Stream(FSDataInputStream),重复的调用父类DataInputStream的read方法,直到这个块上的数据读取完毕。
5.当读完列表的block后,若文件读取还没有结束,客户端会继续向NameNode 获取下一批的 block列表;
6.读取完一个 block 都会进行checksum 验证,如果读取 DataNode 时出现错误,客户端会通知 NameNode,然后再从下一个拥有该 block 副本的DataNode继续读。
7.read方法是并行的读取block 信息,不是一块一块的读取;NameNode 只是返回Client请求包含块的DataNode地址,并不是返回请求块的数据。
8.最终读取来所有的 block会合并成一个完整的最终文件。
元数据辅助管理
之前已经介绍过,NameNode的所有元数据信息都保存在了fsImage与 eidts 文件当中,这两个文件记录了所有的数据的元数据信息, 元数据信息的保存目录配置在 hdfs-site.xml中:
dfs.namenode.name.dir file:///export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas,file:///export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas2 dfs.namenode.edits.dir file:///export/servers/hadoop-2.7.5/hadoopDatas/nn/edits
使用命令查看fsImage与eidts文件
cd /export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas/currenthdfs oiv -i fsimage_0000000000000000125 -p XML -o myfsimage.xml
cd /export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas/nn/currenthdfs oev -i edits_0000000000000000865-0000000000000000866 -p XML -omyedit.xml
SecondaryNameNode定期合并 fsimage 和 edits, 把edits控制在一个范围内。SecondaryNameNode在合并edits和fsimage时需要消耗的内存和 NameNode 差不多, 所以一般把 NameNode和SecondaryNameNode 放在不同的机器上。
SecondaryNameNode通过http方式从NameNode中获得fsimage和 editlog,将fsimage载入内存, 然后开始合并editlog, 合并之后成为新的fsimage,将新的 fsimage发回给NameNode,NameNode用新的 fsimage 替换旧的 fsimage,把 edits.new 变成 edits。