HDFS(Hadoop Distributed File System):分布式存储
NameNode
是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,文件/目录的
元信息和每个文件对应的数据块列表。接收用户的操作请求。
文件包括:
1)fsimage:元数据镜像文件。存储某一时段NameNode内存元数据信息。
2)edits:操作日志文件。
3)fstime:保存最近一次checkpoint的时间
以上这些文件是保存在linux的文件系统中。
查看NameNode内容
bin/hdfs oiv -p XML -i fsimage-path -o fsimage.xml
bin/hdfs oev -p XML -i edits-path -o edits.xml
主要配置选项:hdfs-site.xml的
<property>
<name>dfs.namenode.name.dir</name>
<value>/opt/hadoop-repo/name</value>
</property>
通过HDFS命令查看fsimage文件:
hdfs oiv -p XML -i fsimage_0000000000000000115 -o fsimage.xml
查看hdfs://uplooking:9000/hello
<inode>
<id>16386</id>
<type>FILE</type>
<name>hello</name>
<replication>1</replication>
<mtime>1499706594113</mtime>
<atime>1499706593097</atime>
<perferredBlockSize>134217728</perferredBlockSize>//128M
<permission>root:supergroup:rw-r--r--</permission>
<blocks>
<block>
<id>1073741825</id>
<genstamp>1001</genstamp>
<numBytes>29</numBytes>
</block>
</blocks>
</inode>
通过HDFS命令查看edits操作文件
hdfs oev -p XML -i edits_0000000000000000004-0000000000000000115 -o edits.xml
DataNode
提供真实文件数据的存储服务。
文件块(block):最基本的存储单位。对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,
按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。
HDFS默认Block大小是128MB,以一个256MB文件,共有256/128=2个Block。
不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间
Replication。多复本。默认是三个。
hdfs是专门为大文件设计文件系统,而不是为小文件设计的问题。
hdfs不适合存储小文件?
因为hdfs需要在内存中存放datanode中数据的元数据信息,如果存放过多的小文件的话,会极大的浪费内存开销
HDFS Shell操作
hdfs dfs -ls hdfs://uplooking:9000/ --->(hdfs的根目录)
hdfs dfs -ls /
hdfs文件权限说明
- rw- r-- r-- 1 root supergroup 29 2017-07-10 10:09 hdfs://uplooking01:9000/hello
d rwx r-x r-x - root supergroup 0 2017-07-10 10:12 hdfs://uplooking01:9000/output
文 文件 文件 其它 备 文件 用户 文件 修改时间 文件在hdfs上面的路径
件 用户 用户 用户 份 用户 所在 大小
类 权限 组 权限 数 组
型 权限
-表示文件类型为文件
d表示文件类型为目录
用户权限有:r(read 读 4) w(write 写 2) x(execute 执行 1)
rwx:7
如果一个文件的权限是755:rwxr-xr-x
-ls 浏览hdfs的具体目录
hdfs dfs -ls [-R] / --->-R递归浏览/目录
查看文件内容:
-cat 浏览hdfs上的一个文件内容,和linux本地的cat命令一样
hdfs dfs -cat /input/hadoop/hdfs/data.log
-text hdfs dfs -text /input/hadoop/hdfs/data.log
-tail hdfs dfs -tail /input/hadoop/hdfs/data.log
创建目录:
-mkdir:在hdfs上面创建一个目录,如果创建的是多级目录:使用 -mkdir -p
eg. hdfs dfs -mkdir -p /input/hadoop/hdfs
文件移动:
-copyFromLocal [-f] [linux_src_path hdfs_dest_path] 将linux本地的文件拷贝/上传到hdfs
其中-f参数是强制上传,如果hdfs_dest_path已经存在,则覆盖之
eg.hdfs dfs -copyFromLocal /hello /hello-1
-copyToLocal
-moveFromLocal
-moveToLocal
以上四个命令,都是用于在linux本地和hdfs之前传递文件,不是工作中最常用的命令
-put-->就相当于-copyFromLocal---》从linux本地上传文件到hdfs
hdfs dfs -put data.log /input/hadoop/hdfs/
-get-->就相当于-copyToLocal---》从hdfs下载文件到linux本地
hdfs dfs -get /input/hadoop/hdfs/data.log aaa
-cp--->从hdfs上面的路径A,拷贝相关目录到hdfs上面的路径B
hdfs dfs -cp /input/hadoop/hdfs/data.log /input/hadoop/hdfs/data.1.log
-mv--->从hdfs上面的路径A,移动相关目录到hdfs上面的路径B
hdfs dfs -mv /input/hadoop/hdfs/data.log /input/hadoop/hdfs/data.2.log
文件删除:
-rm [-f] [-r|-R] hdfs目录:删除hdfs上面的指定目录
eg. hdfs dfs -rm -R /out 删除hdfs上面的文件夹/out
HDFS读写过程分析
HDFS读文件
1.首先调用FileSystem对象的open方法,其实是一个DistributedFileSystem的实例。
2.DistributedFileSystem通过rpc获得文件的第一个block的locations,同一block按照副本数会返回多个locations,这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面。
3.前两步会返回一个FSDataInputStream对象,该对象会被封装成DFSInputStream对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方法,DFSInputStream最会找出离客户端最近的datanode并连接。
4.数据从datanode源源不断的流向客户端。
5.如果第一块的数据读完了,就会关闭指向第一块的datanode连接,接着读取下一块。这些操作对客户端来说是透明的,客户端的角度看来只是读一个持续不断的流。
6.如果第一批block都读完了,DFSInputStream就会去namenode拿下一批blocks的location,然后继续读,如果所有的块都读完,这时就会关闭掉所有的流。
如果在读数据的时候,DFSInputStream和datanode的通讯发生异常,就会尝试正在读的block的排第二近的datanode,并且会记录哪个datanode发生错误,剩余的blocks读的时候就会直接跳过该datanode。DFSInputStream也会检查block数据校验和,如果发现一个坏的block,就会先报告到namenode节点,然后DFSInputStream在其他的datanode上读该block的镜像。
该设计的方向就是客户端直接连接datanode来检索数据并且namenode来负责为每一个block提供最优的datanode,namenode仅仅处理block location的请求,这些信息都加载在namenode的内存中,hdfs通过datanode集群可以承受大量客户端的并发访问。
HDFS写文件
1.客户端通过调用DistributedFileSystem的create方法创建新文件
2.DistributedFileSystem通过RPC调用namenode去创建一个没有blocks关联的新文件,创建前,namenode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过,namenode就会记录下新文件,否则就会抛出IO异常.
3.前两步结束后会返回FSDataOutputStream的对象,象读文件的时候相似,FSDataOutputStream被封装成DFSOutputStream.DFSOutputStream可以协调namenode和datanode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小packet,然后排成队列data quene。
4.DataStreamer会去处理接受data queue,他先问询namenode这个新的block最适合存储的在哪几个datanode里,比如副本数是3,那么就找到3个最适合的datanode,把他们排成一个pipeline.DataStreamer把packet按队列输出到管道的第一个datanode中,第一个datanode又把packet输出到第二个datanode中,以此类推。
5.DFSOutputStream还有一个对列叫ack queue,也是有packet组成,等待datanode的收到响应,当pipeline中的所有datanode都表示已经收到的时候,这时akc queue才会把对应的packet包移除掉。
如果在写的过程中某个datanode发生错误,会采取以下几步:1) pipeline被关闭掉;2)为了防止丢包ack queue里的packet会同步到data queue里;3)把产生错误的datanode上当前在写但未完成的block删掉;4)block剩下的部分被写到剩下的两个正常的datanode中;5)namenode找到另外的datanode去创建这个块的复制。当然,这些操作对客户端来说是无感知的。
6.客户端完成写数据后调用close方法关闭写入流
7.DataStreamer把剩余得包都刷到pipeline里然后等待ack信息,收到最后一个ack后,通知datanode把文件标示为已完成。
另外要注意得一点,客户端执行write操作后,写完得block才是可见的,正在写的block对客户端是不可见的,只有调用sync方法,客户端才确保该文件被写操作已经全部完成,当客户端调用close方法时会默认调用sync方法。是否需要手动调用取决你根据程序需要在数据健壮性和吞吐率之间的权衡。
HDFS的常见运维命令
hdfs dfs -du -h / --->查看根目录下每一个子目录文件的大小
hdfs dfs -df / --->查看hdfs的磁盘占用情况
du -lh --max-depth=1 linux_path(比如/) ---->在linux下面查看linux_path目录的每一个第一级子目录大小