Hadoop学习笔记二---HDFS


HDFS的概念 1、数据块      HDFS跟磁盘一样也有块的概念,磁盘上块的大小一般为512字节,而文件系统的块则一般是磁盘块的整数倍,比如我当前centos块的大小事4096 也就是4K,而HDFS块的大小由参数dfs.block.size 设定默认是64M,但是与单一磁盘文件系统相似,HDFS上的文件也被分为块大小的多个分块(chunk)。      为什么HDFS中的块如此之大?      hadoop definitive guide 上面说过了,鉴于本文的初衷,还是陈列到下边:      HDFS的块比磁盘块大,其目的是为了最小化寻址开销。如果块设置的足够大,从磁盘传输数据的时间可以明显大于定位这个块开始位置所需的时间。这样,传输一个由多个块组成的文件的时间取决于磁盘的传输速率。反之,如果块设置的过小,造成文件产生数量很多的块,那传输一个由多个块组成的文件则无疑将会造成许多寻址的资源开销,不再单一取决于磁盘的传输速度,还要取决于磁盘的寻址速度。另外一个方面,如果块的设置比较小,每个块产生一定量的元数据,这样产生的元数据量比较大,造成master过多的内存消耗,NameNode 占用多少内存可以根据block大小,文件大小,和文件多少计算出来。      但是那是不是可以将block设置的足够大呢?太大也不好,MapReduce中的任务通常一次只处理一个block的数据,如果块过大,导致任务数太小,那作业就会分配不均,作业的运行速度就会比较慢。      所以块的大小根据自己的数据量和节点数以及每个节点的map slot综合考虑。      那对HDFS文件分块有哪些好处呢?      1)一个文件的大小可以大于集群网络中任意一个机器中的磁盘的容量,因为将文件分块,不需要所有的块都分布在一个磁盘上,而是将其打散,尽量均匀的分布在每个机器的磁盘上。      2)使用块抽象而非整个文件作为存储单元,简化了存储子系统的设计。这个我个人理解的不深刻,仅从文字层面做了些了解,想深入了解的可以查阅一些资料。      3)块非常适合用于数据备份进而提供数据容错能力的可用性。将每个块复制到少数几个独立的机器上(dfs.replication 默认是3),可以确保在发生块、磁盘或机器故障后数据不丢失。如果一个块不可用,系统会从其他地方读取另外的副本,而这个过程对用户来说是透明的,用户也不需要了解这其中的策略。系统也会及时的将副本不足的块进行slave之间进行复制,从而达到dfs.replication 设定的值。保证副本数恢复到正常的水平。这里要说明一点,一个block不会再同一个机器上存在两个及以上副本,比如现在集群有三台机器,一个master,两台slave 即使dfs.replicaiton设置为3,那也最多也不会超过2个副本,那dfs fsck / -file -blocks 则始终会有警告,提示副本不足,但是此时副本数却大于dfs.replication.min 默认是1 那此时文件系统会保证整个系统正常运行。一个文件到此存在几个副本跟当时进入HDFS 2、HDFS文件系统      不做过多的介绍HDFS的操作,直接可以打开hadoop fs --help 就把所能用的方法都显示出来了,可以逐个尝试一下。      在这主要说明两个问题,第一个是文件访问权限,HDFS文件系统和POSIX权限设置非常相似,基本上就是操作上 需要在前面加一个hadoop fs 声明修改的是HDFS文件系统之外,其它大致相同,默认情况下可以通过正在运行进程的用户名和组名来唯一确定客户端的标志。但由于客户端是远程的,任何用户都可以见到地在远程系统上以他的名义创建一个从账户来进行访问。因此,作为共享文件系统资源和防止数据意外损失的一种机制,权限只能供合作团体中的用户使用,而不能再一个不友好的环境中保护资源,而Hadoop支持一Kerberos用户认证,有兴趣的可以了解一下Kerberos,HDFS支持用户,即通过设置权限来达到这一目的。      第二个,我们需要为HDFS打开回收站,默认回收站是关闭的,参数是fs.trash.interval 默认是0 即是关闭,可以设置一个int数值,单位是minutes 分钟,表示在回收站存放的时间,如果超时,将会删除回收站中的数据,比如要保留一天那就是60*24=1440。hadoop里面有秒 有毫秒,还有分钟,时间上没有形成统一的单位,这需要大家通过记忆了。 这个很重要,防止误删除数据之后,发现数据很有用,在从.Trash中将其mv 到hdfs中,.Trash目录是存放删除的数据的临时目录,但起和通常的HDFS目录是一样的只不过增加了TTL。 3、分布式缓存           DistibutedCache API            前面对DistributedCache 工作机制做了简单的介绍,不再赘述,简单介绍下分布式缓存API           在 hadoop definitive guide 里面有的一段话,拿出来,适度修改一下:           由于可以通过GenericOptionParser 来间接使用分布式缓存,所以大多数情况下不需要显示的使用DistributedCache 的api,但实际上,使用GenericOptionParser访问分布式缓存会更加方便。例如,可以将本地文件复制到HDFS中去,接着JobClient会通过addCacheFile()或者addCacheArchive()方法来告诉DistributedCache在HDFS中的位置。当文件存放在本地时,JobClient 同样获得DistributedCache来创建符号链接,其形式为文件的URI加fragment标识,例如:hdfs://namenode/foo/bar#myfile 指定的文件通过符号链接以myfile文件名存放在任务的工作目录下。           在任务节点上,最方便的方法是直接访问本地化文件。然而,有时候用户需要获得缓存中所有有效文件的列表。JobConf中有两个方法可以做到这一点:           getLocalCacheFiles()和getLocalCacheArchives() 函数均返回一个指向本地文件路径的对象数组。            分布式缓存的使用方法:           1)使用配置文件的方法:                conf.set("mapred.cache.files", "/data/data");                conf.set("mapred.cache. archives", "/data/data.zip");           2)使用API的方法                DistributedCache. addCacheFile(URI, Configuration)                DistributedCache.addArchiveToClassPath(Path, Configuration, FileSystem) 4、文件读取      看下图:            HDFS、namenode、datanode之间的数据流是什么样的,从上面的数据读取流程图中可以看出。文件的读取相对于文件的写入比较简单      首先client 通过调用FileSystem对象的open() 方法来打开希望读取的文件,对于HDFS来说,这个对象是分布式文件系统的一个实例,这里指的是上图中第一个步骤      分布式文件系统通过RPC和Namenode 建立通话,获取要读取文件所有数据块的所在的位置,此处位置是指所在的datanode的地址,注意的是,datanode根据他们与client的距离排序,怎么排序,什么是距离,简单介绍:因为文件系统所在集群是拓扑结构的,每个节点和另外一个节点之间按照统一节点上的进程,同一机架上的进程,同一数据中心、不同数据中心的维度来计算距离,本地当然是最近的,相同机架的其次,其后是不同机架的,和距离最远的是分属不同数据中心的server之间的距离,这期间用到了一个概念,hadoop的机架感知,不过让大家倍感神奇的机架感知并非高科技,而是在部署节点的时候手动将其设定机架号,机房号,集群根据手动设置的值来判断是否分属一个机架,是否在一个信息中心(一个机房等)。附上一张网络距离图:            再向后,如果client获得所要读取的文件所有的block所在的datanode节点,并也知道哪个datanode 的距离,那就按照最近距离有限的策略去读取数据,这期间读取的数据封装在FSDataInputStream(DistributedFileSystem 返回) 中返给client,当读取到datanode块的末位时,DFSInputStream会close与该Datanodede 连接,每个块都一样的流程      最后 数据读取完整 close.
5、文件写入      看下图:            需要了解写入文件到HDFS 文件是由谁创建的?数据是直接写入datanode 呢?还是需要中转namenode,在就是数据之间复制是如何开展的。      首先HDFS client 通过Distributed FileSystem 对象调用create() 函数来创建文件,而DitributedFileSystem 是通过对namenode创建一个RPC调用,在文件系统的命名空间中创建一个要写入的文件文件。此时文件是一个空白文件。在创建文件的过程中namenode 需要做各种检查,以确保此文件在文件系统并且在相应目录中不存在,并且client 有在此目录中创建文件的权限,如果检查通过,那么namenode 就会为新创建的文件记录一条数据;否则,文件创建失败并向client抛出一个IOException 异常。      创建文件成功之后,DistributedFileSystem 向客户端返回一个FSDataOutputStream 对象,开始第三步 write 数据。此时FSDataOutputStream 封装一个DFSOutputStream对象,改对象负责处理datanode和namenode之间的通信。      在client写入数据是,DFSOutputStream将它分成一个个的数据包(packet),并写入内部队列,成为内部队列(data queue).DataStreamer处理data queue,它的主要任务是根据datanode列表来要求namenode分配适合的新块来存储数据备份。这一组datanode构成一个管线(Pipeline Of datanodes) 长度即是我们设置的block副本数(dfs.replication),DataStreamer将数据包流式传输到管线中的第一个datanode,该datanode中存储数据包并将其发送到管线中的第2个datanode.同样的再发送到第三个datanode上。      DFSOutputStream 也维护这一个内部数据包队列来等待datanode的收到确认回执,成为确认队列(ack queue 存储 ack packet)当收到所有datanode的确认信息后,该数据包(data packet)才会从确认队列中删除。      上面的情况都是在顺利的情况,不排除中间datanode出现故障导致管线断裂(中间节点损坏)或者缺失(首位节点损坏)的情况发生,其实什么节点发生故障解决途径都是一样的,具体操作是:      1、关闭管线(Pipeline of datanodes),把确认队列(ack queue)中所有的数据包都添加回数据队列(data queue)的最前端,以确保故障下游的datanode不会漏掉任何一个数据包(data packet),并将存在在正常datanode上的当前数据块 指定一个新的标识,并将改标识传送给 namenode 做记录,以便在故障datanode节点恢复后,根据此标识找到相应的数据块,进而删除该恢复后节点上故障前存储的部分数据块(原则上删除的数据块应该小于等于正常datanode节点标记的数据块)。      从管线中删除故障数据节点并且把余下的数据块写入管线中两个正常的datanode.namenode意识到副本量不足时,会在另外一个节点上创建一个新的副本,后续的数据块继续正常接收处理。      在一个块被写入期间可能有多个datanode同时发生故障,仅仅在datanode发生故障,或者datanode节点数不足,导致管线中节点数不够dfs.replication,只要写入的数据副本数达到dfs.replication.min默认是1,写操作才会成功,否则只要没有达到dfs.replication时 就永远不会返回成功。并且这个块会异步复制,知道达到默认的副本数。      第6步调用 close,此操作将剩余的所有数据包写入datanode 管线中,并在联系namenode且发送文件写入完成信号之前,等待确认(第7步)。namenode已经只带文件由哪些数据块组成(通过DataStreamer询问数据块的分配),所以它只要等待数据块进行最小量的复制时就会返回成功。 6、系统检查      Hadoop提供的对HDFS文件系统检测的工具,可以有hadoop fsck / -files -blocks -locations -racks 选项      在执行 hadoop fsck /   命令后 ,得到一个下列结果:           Total size:     926969878513 B
Total dirs:     7800 Total files:     476228 (Files currently being written: 143) Total blocks (validated):     481426 (avg. block size 1925467 B) (Total open file blocks (not validated): 143) Minimally replicated blocks:     481426 (100.0 %) Over-replicated blocks:     0 (0.0 %) Under-replicated blocks:     1254 (0.26047617 %) Mis-replicated blocks:          0 (0.0 %) Default replication factor:     3 Average block replication:     3.0 Corrupt blocks:          0 Missing replicas:          8778 (0.6077777 %) Number of data-nodes:          3 Number of racks:          1 FSCK ended at Tue Oct 22 15:03:10 CST 2013 in 6837 milliseconds
     上述所有信息基本上根据词面意思都可以理解,因为HDFS是自我修复的,所有对于Over-replicated blocks、Under-replicated blocks、Mis-replicated blocks 如果存在一定的数据也不要关系,系统会自我修复这些问题,倒是 Missing replicas  和Corrupt blocks 意味着数据永远丢失,后悔,痛惜 都解决不了问题,没办法,只能删除,只能删除这些损坏的坏,或者数据不全的块 hadoop fsck -delete 或者是 hadoop fsck -move 清除块,但是这些快从哪去找呢,在执行hadoop fsck / 的过程中 会将问题块列出来,而没有问题的block会以一个原点 "." 来代替。      虽然能够通过fsck 给出HDFS中每个文件的报告,但是却不能获取各DataNode 的信息,hadoop 提供了这样的方法      hadoop dfsamin -report  打印的记过如下:          Configured Capacity: 1293495955456 (1.18 TB)
Present Capacity: 1184226488320 (1.08 TB) DFS Remaining: 1079845535744 (1005.68 GB) DFS Used: 104380952576 (97.21 GB) DFS Used%: 8.81% Under replicated blocks: 428 Blocks with corrupt replicas: 0 Missing blocks: 0
-------------------------------------------------//此线以上时所有datanode汇总的信息,以下是各个datanode 分别的信息。 Datanodes available: 2 (2 total, 0 dead)
Name: 192.168.10.48:50010 Decommission Status : Normal Configured Capacity: 211309056000 (196.8 GB) DFS Used: 52189851648 (48.61 GB) Non DFS Used: 21823569920 (20.32 GB) DFS Remaining: 137295634432(127.87 GB) DFS Used%: 24.7% DFS Remaining%: 64.97% Last contact: Tue Oct 22 15:05:54 CST 2013

Name: 192.168.10.47:50010 Decommission Status : Normal Configured Capacity: 1082186899456 (1007.87 GB) DFS Used: 52191100928 (48.61 GB) Non DFS Used: 87445897216 (81.44 GB) DFS Remaining: 942549901312(877.82 GB) DFS Used%: 4.82% DFS Remaining%: 87.1% Last contact: Tue Oct 22 15:05:53 CST 2013
     还有什么地方用到这个命令了 当hadoop 集群启动的时候 hdfs会有一个时间 处于安全模式 也就是safemode 当对hdfs检查加载完毕之后 会退出safemode,当由于一些特殊原因我们需要手动退出安全模式的时候  会用到 Hadoop dfsamin -safemode leave 当然还有其它可选择 enter get wait 根据不同的需求 使用相应的命令。                 

相关内容